aboutsummaryrefslogtreecommitdiffhomepage
path: root/amd64
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2023-06-01 23:16:48 +0200
committerlemon <lsof@mailbox.org>2023-06-01 23:27:20 +0200
commit65ace14e184807df026e985e073b3b5c5aaf576c (patch)
treed4554e0eef30b6f8771bfa90835ff6dcb95198a7 /amd64
parenta98075934ece8c7ff351f8449f6515c12b9feec8 (diff)
basic ABI lowering of aggregates
Diffstat (limited to 'amd64')
-rw-r--r--amd64/all.h15
-rw-r--r--amd64/sysv.c103
2 files changed, 103 insertions, 15 deletions
diff --git a/amd64/all.h b/amd64/all.h
index fdd759a..915d93a 100644
--- a/amd64/all.h
+++ b/amd64/all.h
@@ -1,6 +1,5 @@
#include "../ir.h"
-
#define LIST_REGS(_) \
_(RAX) _(RCX) _(RDX) _(RBX) _(RSP) _(RBP) _(RSI) _(RDI) \
_(R8) _(R9) _(R10) _(R11) _(R12) _(R13) _(R14) _(R15) \
@@ -13,18 +12,4 @@ enum {
#undef R
};
-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,
-};
-
/* vim:set ts=3 sw=3 expandtab: */
diff --git a/amd64/sysv.c b/amd64/sysv.c
index e998036..55739e8 100644
--- a/amd64/sysv.c
+++ b/amd64/sysv.c
@@ -1,3 +1,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: */