aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-03-25 16:36:29 +0100
committerlemon <lsof@mailbox.org>2026-03-25 16:36:29 +0100
commit79d6ac719042371d255ed1cf412e3232d13d1e56 (patch)
treef7d7ac5b94f68575bbfbf43f5f295c8a6c146b8f
parent3eb74e33d9fb2fa1bfe3ba4757c79ed13330c104 (diff)
aarch64 struct arg passing ABI wip
-rw-r--r--src/ir_abi0.c9
-rw-r--r--src/t_aarch64_aapcs.c108
-rw-r--r--src/t_aarch64_emit.c6
-rw-r--r--src/t_aarch64_isel.c12
-rw-r--r--src/t_x86-64_sysv.c3
5 files changed, 127 insertions, 11 deletions
diff --git a/src/ir_abi0.c b/src/ir_abi0.c
index 74a9d62..8722438 100644
--- a/src/ir_abi0.c
+++ b/src/ir_abi0.c
@@ -45,8 +45,13 @@ abiarg(ABIArgVec *abiargs, uchar *r2off, int *ni, int *nf, int *ns, IRType ty)
int ret = mctarg->abiarg(r, cls, r2off, ni, nf, ns, ty);
if (!ret) { /* in stack */
vpush(abiargs, ((ABIArg) { ty, .isstk = 1, .stk = r[0] }));
- } else if (ret == 1 && ty.isagg && cls[0] == KPTR) { /* aggregate by pointer */
- vpush(abiargs, ((ABIArg) { cls2type(cls[0]), .reg = r[0] }));
+ } else if (ty.isagg && cls[0] == KPTR) { /* aggregate by pointer */
+ ABIArg a = { cls2type(KPTR) };
+ if (ret < 0) /* stack */
+ a.isstk = 1, a.stk = r[0];
+ else /* reg */
+ a.isstk = 0, a.reg = r[0];
+ vpush(abiargs, a);
} else { /* by regs */
vpush(abiargs, ((ABIArg) { cls2type(cls[0]), .reg = r[0] }));
if (ret == 2)
diff --git a/src/t_aarch64_aapcs.c b/src/t_aarch64_aapcs.c
index 1bfd23e..a321f5b 100644
--- a/src/t_aarch64_aapcs.c
+++ b/src/t_aarch64_aapcs.c
@@ -1,5 +1,60 @@
#include "t_aarch64.h"
+/* Ref: https://github.com/ARM-software/abi-aa/blob/2025Q4/aapcs64/aapcs64.rst */
+
+static bool
+hfa_scalar(enum typetag *hfa_t, enum typetag t)
+{
+ if (!isfltt(t)) return 0;
+ if (!*hfa_t) *hfa_t = t;
+ else if (*hfa_t != t) return 0;
+ return 1;
+}
+
+static bool cls_hfa(enum typetag *, const TypeData *td);
+
+static bool
+hfa_arr(enum typetag *hfa_t, Type ty)
+{
+ Type chld = typechild(ty);
+ if (isagg(chld))
+ return cls_hfa(hfa_t, &typedata[chld.dat]);
+ if (chld.t == TYARRAY)
+ return hfa_arr(hfa_t, chld);
+ return hfa_scalar(hfa_t, scalartypet(chld));
+}
+
+static bool
+cls_hfa(enum typetag *hfa_t, const TypeData *td)
+{
+ assert(isaggt(td->t));
+ for (int i = 0; i < td->nmemb; ++i) {
+ FieldData *fld = &td->fld[i].f;
+ if (isagg(fld->t)) {
+ if (!cls_hfa(hfa_t, &typedata[fld->t.dat]))
+ return 0;
+ } else if (fld->t.t == TYARRAY) {
+ if (isincomplete(fld->t)) continue;
+ if (!hfa_arr(hfa_t, fld->t))
+ return 0;
+ } else {
+ if (!hfa_scalar(hfa_t, scalartypet(fld->t)))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static enum irclass
+classify(const TypeData *td)
+{
+ if (td->siz > 16) return 0;
+ enum typetag hfa_t = 0;
+ return cls_hfa(&hfa_t, td) ? type2cls[hfa_t] : (td->siz > 4 ? KI64 : KI32);
+}
+
+/* XXX types with alignment >= 16 */
+
static int
abiarg(short r[2], uchar cls[2], uchar *r2off, int *ni, int *nf, int *ns, IRType typ)
{
@@ -9,13 +64,60 @@ abiarg(short r[2], uchar cls[2], uchar *r2off, int *ni, int *nf, int *ns, IRType
r[0] = V(0) + (*nf)++;
} else if (kisint(cls[0]) && *ni < NINT) {
r[0] = R0 + (*ni)++;
- } else {
+ } else { /* passed on the stack */
r[0] = *ns;
*ns += 8;
- return 0; /* MEMORY */
+ return 0;
}
return 1;
- } else assert(!"nyi");
+ }
+ cls[0] = cls[1] = 0;
+ enum irclass k = classify(&typedata[typ.dat]);
+ if (!k) { /* copied to caller memory and passed as a pointer */
+ cls[0] = KPTR;
+ if (*ni < NINT) { /* in a gpr */
+ r[0] = R0 + (*ni)++;
+ return 1;
+ } else { /* that pointer, passed on the stack */
+ r[0] = *ns;
+ *ns += 8;
+ return -1;
+ }
+ }
+ *r2off = cls2siz[k];
+ int n;
+ uint tsiz = typedata[typ.dat].siz;
+ if (kisflt(k)) { /* HFAA ([1..4]f32 or [1..2]f64) */
+ n = tsiz / cls2siz[k];
+ assert(n <= 2 && "oops");
+ if (n <= NFLT - *nf) {
+ for (int i = 0; i < n; ++i) {
+ r[i] = V(0) + *nf + i;
+ cls[i] = type2cls[k];
+ }
+ *nf += n;
+ } else { /* stack */
+ *nf = NFLT;
+ Stack:
+ r[0] = *ns;
+ *ns = alignup(*ns + tsiz, 8);
+ r[1] = -1;
+ return cls[0] = cls[1] = 0;
+ }
+ } else { /* Composite Type <= 16 bytes */
+ n = 1 + (tsiz > 8);
+ if (n <= NINT - *ni) {
+ r[0] = R0 + *ni;
+ if (n > 1) r[1] = r[0] + 1;
+ *ni += n;
+ cls[0] = tsiz > 4 ? KI64 : KI32;
+ if (n > 1) cls[1] = KI64;
+ } else {
+ *ni = NINT;
+ goto Stack;
+ }
+ }
+ return n;
}
static int
diff --git a/src/t_aarch64_emit.c b/src/t_aarch64_emit.c
index f413f98..307890b 100644
--- a/src/t_aarch64_emit.c
+++ b/src/t_aarch64_emit.c
@@ -277,7 +277,7 @@ encode(uchar **pcode, const EncDesc *tab, int ntab, enum irclass k, Oper o[3])
break;
case EN_ADDSYMLO12:
ins |= sf<<31 | o[1].reg<<5 | o[0].reg;
- objrelocxcon(o[2].con, REL_ADD_ABS_LO12_NC, Stext, *pcode - objout.textbegin, o[1].cdisp);
+ objrelocxcon(o[2].con, REL_ADD_ABS_LO12_NC, Stext, *pcode - objout.textbegin, o[2].cdisp);
break;
case EN_LDSYMLO19:
ins |= o[0].reg;
@@ -329,7 +329,7 @@ DEFINSTR2(Xadrp,
{8, {PGPRZ, PSYM}, 0x90000000, EN_ADRSYMPGHI21} /* ADR (sym pg hi21) */
)
DEFINSTR2(Xadr,
- {8, {PGPRZ, PSYM}, 0x10000000, EN_ADRSYMLO21} /* ADR (sym pg hi21) */
+ {8, {PGPRZ, PSYM}, 0x10000000, EN_ADRSYMLO21} /* ADR (sym lo21) */
)
DEFINSTR3(Xadd,
@@ -418,6 +418,8 @@ DEFINSTR2(Xfldr,
{8, {PFPR, PMEMAIMMX}, 0xFD400000, EN_MEMAIMMX},
{4, {PFPR, PMEMAREG}, 0xBC600800, EN_MEMAREG}, /* LDR (register) */
{8, {PFPR, PMEMAREG}, 0xFC600800, EN_MEMAREG},
+ {4, {PFPR, PSYM}, 0x1C000000, EN_LDSYMLO19}, /* LDR (literal) */
+ {8, {PFPR, PSYM}, 0x5C000000, EN_LDSYMLO19},
{4, {PFPR, PMEMPREPOST}, 0xBC400000, EN_MEMAPREPOST}, /* LDR (immediate, (pre/postinc)) */
{8, {PFPR, PMEMPREPOST}, 0xFC400000, EN_MEMAPREPOST},
)
diff --git a/src/t_aarch64_isel.c b/src/t_aarch64_isel.c
index 0e43ea7..4490831 100644
--- a/src/t_aarch64_isel.c
+++ b/src/t_aarch64_isel.c
@@ -343,14 +343,18 @@ static void
loadstoreaddr(Block *blk, Ref *r, int *curi, enum op op)
{
uint siz = oisload(op) ? loadsz[op-Oloads8] : storesz[op-Ostorei8];
+ bool pcrelok = in_range(op, Oloads32, Oloadf64); /* LDR-LDRSW have PC-relative literal form */
if (isimm32(*r)) {
- *r = mkaddr((IRAddr){.base = *r});
+ regarg(r, KPTR, blk, curi);
} else if (isaddrcon(*r, 0)) {
- bool pcrelok = in_range(op, Oloads32, Oloadi64); /* LDR-LDRSW have PC-relative literal form */
if (!pcrelok || !(contab.p[r->i].flag & SLOCAL))
regarg(r, KPTR, blk, curi);
} else if (r->t == RTMP || r->t == RSTACK) {
- fuseaddr(r, blk, curi, siz);
+ Ref b;
+ if (fuseaddr(r, blk, curi, siz)
+ && isaddrcon(b = addrtab.p[r->i].base,0)
+ && (!pcrelok || !(contab.p[b.i].flag & SLOCAL)))
+ regarg(r, KPTR, blk, curi);
} else if (r->t != RREG) {
*r = insertinstr(blk, (*curi)++, mkinstr1(Ocopy, KPTR, *r));
}
@@ -369,7 +373,7 @@ sel(Function *fn, Instr *ins, Block *blk, int *curi)
}
switch (op) {
- //default: assert(0);
+ default: assert(0);
case Onop: break;
case Oalloca1: case Oalloca2: case Oalloca4: case Oalloca8: case Oalloca16:
assert(!"unlowered alloca");
diff --git a/src/t_x86-64_sysv.c b/src/t_x86-64_sysv.c
index 852aa24..96f40d6 100644
--- a/src/t_x86-64_sysv.c
+++ b/src/t_x86-64_sysv.c
@@ -40,12 +40,15 @@ classifyarr(uchar cls[2], Type ty, uint off)
return !!cls[0] + !!cls[1];
}
+/* XXX types with alignment >= 16 */
+
static int
classify(uchar cls[2], const TypeData *td, uint off)
{
uint siz = alignup(td->siz, 4);
if (siz > 16) /* MEMORY */
return 0;
+ assert(isaggt(td->t));
for (int i = 0; i < td->nmemb; ++i) {
FieldData *fld = &td->fld[i].f;
uint align = typealign(fld->t);