aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-11-12 17:58:51 +0100
committerlemon <lsof@mailbox.org>2025-11-12 18:03:42 +0100
commit82a3c1cd8d00bc342752c31116c497c52f6d8933 (patch)
tree9b4256a83c68b6569a75d08307a50a5662f2cfb2
parent070bf6f223b6cc6f3d7a6c28c1afce8c0bc8a72e (diff)
implement argument passing in stack
-rw-r--r--amd64/isel.c24
-rw-r--r--ir/abi0.c1
-rw-r--r--ir/ir.h1
3 files changed, 20 insertions, 6 deletions
diff --git a/amd64/isel.c b/amd64/isel.c
index 8108ec4..c0c6054 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -106,20 +106,32 @@ selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi)
const struct call *call = &calltab.p[ins->r.i];
int iarg = *curi - 1;
enum irclass cls;
+ uint argstksiz = alignup(call->argstksiz, 16);
for (int i = call->narg - 1; i >= 0; --i) {
+ struct abiarg abi = call->abiarg[i];
struct instr *arg;
- for (;;) {
- assert(i >= 0 && "arg?");
- if ((arg = &instrtab[blk->ins.p[iarg--]])->op == Oarg)
+ for (;; --iarg) {
+ assert(iarg >= 0 && i >= 0 && "arg?");
+ if ((arg = &instrtab[blk->ins.p[iarg]])->op == Oarg)
break;
}
- if (call->abiarg[i].reg >= 0) {
- assert(!call->abiarg[i].ty.isagg);
- *arg = mkinstr(Omove, call->abiarg[i].ty.cls, mkref(RREG, call->abiarg[i].reg), arg->r);
+ assert(!abi.ty.isagg);
+ if (abi.reg >= 0) {
+ assert(!abi.ty.isagg);
+ *arg = mkinstr(Omove, call->abiarg[i].ty.cls, mkref(RREG, abi.reg), arg->r);
+ } else {
+ union ref adr = mkaddr((struct addr){mkref(RREG, RSP), .disp = argstksiz+abi.stk});
+ *arg = mkinstr(Ostore1+ilog2(cls2siz[abi.ty.cls]), 0, adr, arg->r);
}
}
+ if (call->argstksiz) {
+ union ref disp = mkref(RICON, argstksiz);
+ insertinstr(blk, iarg--, (struct instr){Osub, KPTR, .keep=1, .reg = RSP+1, .l=mkref(RREG,RSP), disp});
+ ++*curi;
+ insertinstr(blk, *curi+1, (struct instr){Oadd, KPTR, .keep=1, .reg = RSP+1, .l=mkref(RREG,RSP), disp});
+ }
cls = ins->cls;
ins->cls = 0;
if (cls) {
diff --git a/ir/abi0.c b/ir/abi0.c
index 515ba1a..404947e 100644
--- a/ir/abi0.c
+++ b/ir/abi0.c
@@ -276,6 +276,7 @@ abi0_call(struct function *fn, struct instr *ins, struct block *blk, int *curi)
if (call->vararg == i) vararg = i2;
i2 += ret;
}
+ call->argstksiz = ns;
/* adjust return */
if (call->ret.isagg) {
ins->cls = 0;
diff --git a/ir/ir.h b/ir/ir.h
index 4c369a1..66fc56d 100644
--- a/ir/ir.h
+++ b/ir/ir.h
@@ -46,6 +46,7 @@ struct call {
union irtype ret;
ushort narg;
short vararg; /* first variadic arg or -1 */
+ ushort argstksiz;
struct abiarg *abiarg;
struct abiarg abiret[2];
};