aboutsummaryrefslogtreecommitdiffhomepage
path: root/amd64/sysv.c
blob: 55739e839d79a49bb014ec9c0d6a6de5dd7ae7a4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "all.h"

static int
classify(uchar cls[2], const struct typedata *td, uint off)
{
   uint siz = alignup(td->siz, 8);
   if (siz > 16) /* MEMORY */
      return 0;
   for (int i = 0; i < td->nmemb; ++i) {
      struct fielddata *fld = &td->fld[i].f;
      uint align = typealign(fld->t);
      if (alignup(fld->off, align) != fld->off) /* unaligned field */
         return cls[0] = cls[1] = 0;
      if (isagg(fld->t)) {
         if (!classify(cls, &typedata[fld->t.dat], fld->off))
            return cls[0] = cls[1] = 0;
      } else if (isflt(fld->t)) { /* SSE */
         if (!cls[(fld->off + off)/8])
            cls[(fld->off + off)/8] = KF8;
      } else { /* INTEGER */
         cls[(fld->off +  off)/8] = KI8;
      }
   }
   return !!cls[0] + !!cls[1];
}

static int
argabi(short r[2], uchar cls[2], int *ni, int *nf, union irtype typ)
{
   static const uchar intregs[] = { RDI, RSI, RDX, RCX, R8, R9 };
   enum { NINT = arraylength(intregs), NFLT = 8 };
   int ret, ni_save, nf_save;

   if (!typ.isagg) {
      if (kisflt(typ.cls) && *nf < NFLT) {
         cls[0] = KF8; /* SSE */
         r[0] = XMM0 + (*nf)++;
         return 1;
      }
      if (*ni < NINT) {
         cls[0] = KI8; /* INTEGER */
         r[0] = intregs[(*ni)++];
         return 1;
      }
      return 0; /* MEMORY */
   }
   cls[0] = cls[1] = 0;
   ret = classify(cls, &typedata[typ.dat], 0);
   if (!ret) return 0;
   ni_save = *ni, nf_save = *nf;
   assert(ret <= 2);
   for (int i = 0; i < ret; ++i) {
      assert(cls[i]);
      if (cls[i] == KF8 && *nf < NFLT)
         r[i] = XMM0 + (*nf)++;
      else if (cls[i] == KI8 && *ni < NINT)
         r[i] = intregs[(*ni)++];
      else { /* MEMORY */
         *ni = ni_save, *nf = nf_save;
         return cls[0] = cls[1] = 0;
      }
   }
   return ret;
}

static int
retabi(short r[2], uchar cls[2], union irtype typ)
{
   int ret;

   if (!typ.isagg) return kisflt(typ.cls) ? XMM0 : RAX;
   cls[0] = cls[1] = 0;
   ret = classify(cls, &typedata[typ.dat], 0);
   if (!ret) { /* MEMORY */
      r[0] = RDI; /* register for caller-owned result location argument */
      return 0;
   }
   assert(ret <= 2);
   for (int i = 0; i < ret; ++i) {
      assert(cls[i]);
      if (cls[i] == KF8) /* SSE (XMM0, XMM1) */
         r[i] = XMM0 + i;
      else if (cls[i] == KI8) /* INTEGER (RAX, RDX) */
         r[i] = i == 0 ? RAX : RDX;
      else assert(0);
   }
   return ret;
}

const char amd64_rnames[][6] = {
#define R(r) #r,
   LIST_REGS(R)
#undef R
};

const struct mctarg t_amd64_sysv = {
   .gpr0 = RAX, .ngpr = R15 - RAX + 1,
   .fpr0 = XMM0, .nfpr = XMM15 - XMM0 + 1,
   .rcallee = {{1<<RBX | 1<<R12 | 1<<R13 | 1<<R14 | 1<<R15}},
   .rglob = {{1<<RSP | 1<<RBP}},
   .rnames = amd64_rnames,
   .abi_argregs = argabi,
   .abi_retregs = retabi,
};

/* vim:set ts=3 sw=3 expandtab: */