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: */
|