diff options
| author | 2025-12-06 18:59:53 +0100 | |
|---|---|---|
| committer | 2025-12-06 18:59:53 +0100 | |
| commit | f7d68175fc2b52230b8f78bf78145c7f1d0ad9c5 (patch) | |
| tree | 099243c78aaef479daee0b2ab5e8dc8215cea9e3 /amd64 | |
| parent | d82f3052c813f671561362126d0fbe08568542d3 (diff) | |
abi: fix aggregate passed by regs 2nd reg offset
It was broken for example `struct { i32 a; f64 b; }` (would try to
load/store b from byte offset 4, not 8). Introduce r2off, realize in
x86-64 it's always 8; even `struct {i32 a; f32 b;}` gets passed in one
(integer) register. But not so in (future) ABIs like RISC-V, I believe
there `{i32, f32}` would get passed in 1 integer and 1 float register
(r2off = 4).
Diffstat (limited to 'amd64')
| -rw-r--r-- | amd64/sysv.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/amd64/sysv.c b/amd64/sysv.c index 299d35c..020f597 100644 --- a/amd64/sysv.c +++ b/amd64/sysv.c @@ -39,6 +39,7 @@ classifyarr(uchar cls[2], union type ty, uint off) } return !!cls[0] + !!cls[1]; } + static int classify(uchar cls[2], const struct typedata *td, uint off) { @@ -65,7 +66,7 @@ classify(uchar cls[2], const struct typedata *td, uint off) } static int -abiarg(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype typ) +abiarg(short r[2], uchar cls[2], uchar *r2off, int *ni, int *nf, int *ns, union irtype typ) { static const uchar intregs[] = { RDI, RSI, RDX, RCX, R8, R9 }; enum { NINT = arraylength(intregs), NFLT = 8 }; @@ -92,6 +93,7 @@ abiarg(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype typ) } assert(ret <= 2); ni_save = *ni, nf_save = *nf; + *r2off = 8; for (int i = 0; i < ret; ++i) { assert(cls[i]); if (kisflt(cls[i]) && *nf < NFLT) @@ -110,7 +112,7 @@ abiarg(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype typ) } static int -abiret(short r[2], uchar cls[2], int *ni, union irtype typ) +abiret(short r[2], uchar cls[2], uchar *r2off, int *ni, union irtype typ) { int ret; @@ -129,6 +131,7 @@ abiret(short r[2], uchar cls[2], int *ni, union irtype typ) return 0; } assert(ret <= 2); + *r2off = 8; for (int i = 0, ni = 0, nf = 0; i < ret; ++i) { assert(cls[i]); if (kisflt(cls[i])) /* SSE (XMM0, XMM1) */ @@ -215,6 +218,7 @@ vaarg(struct function *fn, struct block *blk, int *curi) uchar cls[2]; union ref tmp; int ni = 0, nf = 0, ns = 0; + uchar r2off; int var = blk->ins.p[*curi]; union ref ap = instrtab[var].l; union irtype ty = ref2type(instrtab[var].r); @@ -222,7 +226,7 @@ vaarg(struct function *fn, struct block *blk, int *curi) assert(instrtab[var].op == Ovaarg); blk->ins.p[*curi] = newinstr(blk, (struct instr){Onop}); - int ret = abiarg(r, cls, &ni, &nf, &ns, ty); + int ret = abiarg(r, cls, &r2off, &ni, &nf, &ns, ty); if (ret == 2) assert(!"nyi"); else if (ret == 1) { |