From 79d6ac719042371d255ed1cf412e3232d13d1e56 Mon Sep 17 00:00:00 2001 From: lemon Date: Wed, 25 Mar 2026 16:36:29 +0100 Subject: aarch64 struct arg passing ABI wip --- src/ir_abi0.c | 9 ++++- src/t_aarch64_aapcs.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/t_aarch64_emit.c | 6 ++- src/t_aarch64_isel.c | 12 ++++-- src/t_x86-64_sysv.c | 3 ++ 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); -- cgit v1.2.3