aboutsummaryrefslogtreecommitdiffhomepage
path: root/amd64/sysv.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-12-06 18:59:53 +0100
committerlemon <lsof@mailbox.org>2025-12-06 18:59:53 +0100
commitf7d68175fc2b52230b8f78bf78145c7f1d0ad9c5 (patch)
tree099243c78aaef479daee0b2ab5e8dc8215cea9e3 /amd64/sysv.c
parentd82f3052c813f671561362126d0fbe08568542d3 (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/sysv.c')
-rw-r--r--amd64/sysv.c10
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) {