diff options
author | Quentin Carbonneaux <quentin@c9x.me> | 2021-10-18 21:04:10 +0200 |
---|---|---|
committer | Quentin Carbonneaux <quentin@c9x.me> | 2021-10-22 23:53:25 +0200 |
commit | fcdef10dae54d7124aca9ccbefe53baa8e67267d (patch) | |
tree | 1215b60f1f3a31d38ee37228dd37bcc4a6a61f99 /amd64 | |
parent | 9858a12730717d9c5e5deec4264d7041d75fc947 (diff) | |
download | roux-fcdef10dae54d7124aca9ccbefe53baa8e67267d.tar.gz |
make variadic args explicit
Some abis, like the riscv one, treat arguments differently depending on whether they are variadic or not. To prepare for the upcomming riscv target, we change the variadic call syntax and give meaning to the location of the '...' marker. # new syntax %ret =w call $f(w %regular, ..., w %variadic) By nature of their abis, the change is backwards compatible for existing targets.
Diffstat (limited to 'amd64')
-rw-r--r-- | amd64/sysv.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/amd64/sysv.c b/amd64/sysv.c index 842f645..2e3e4a8 100644 --- a/amd64/sysv.c +++ b/amd64/sysv.c @@ -153,7 +153,7 @@ selret(Blk *b, Fn *fn) static int argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret, Ref *env) { - int nint, ni, nsse, ns, n, *pn; + int varc, envc, nint, ni, nsse, ns, n, *pn; AClass *a; Ins *i; @@ -162,6 +162,8 @@ argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret, Ref *env) else nint = 6; nsse = 8; + varc = 0; + envc = 0; for (i=i0, a=ac; i<i1; i++, a++) switch (i->op - op + Oarg) { case Oarg: @@ -196,14 +198,23 @@ argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret, Ref *env) a->inmem = 1; break; case Oarge: + envc = 1; if (op == Opar) *env = i->to; else *env = i->arg[0]; break; + case Oargv: + varc = 1; + break; + default: + die("unreachable"); } - return (!req(R, *env) << 12) | ((6-nint) << 4) | ((8-nsse) << 8); + if (varc && envc) + err("sysv abi does not support variadic env calls"); + + return ((varc|envc) << 12) | ((6-nint) << 4) | ((8-nsse) << 8); } int amd64_sysv_rsave[] = { @@ -290,7 +301,7 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap) { Ins *i; AClass *ac, *a, aret; - int ca, ni, ns, al, varc, envc; + int ca, ni, ns, al; uint stk, off; Ref r, r1, r2, reg[2], env; RAlloc *ra; @@ -358,22 +369,20 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap) ca += 1 << 2; } } - envc = !req(R, env); - varc = i1->op == Ovacall; - if (varc && envc) - err("sysv abi does not support variadic env calls"); - ca |= varc << 12; /* envc set in argsclass() */ + emit(Ocall, i1->cls, R, i1->arg[0], CALL(ca)); - if (envc) + + if (!req(R, env)) emit(Ocopy, Kl, TMP(RAX), env, R); - if (varc) + else if ((ca >> 12) & 1) /* vararg call */ emit(Ocopy, Kw, TMP(RAX), getcon((ca >> 8) & 15, fn), R); ni = ns = 0; if (ra && aret.inmem) emit(Ocopy, Kl, rarg(Kl, &ni, &ns), ra->i.to, R); /* pass hidden argument */ + for (i=i0, a=ac; i<i1; i++, a++) { - if (a->inmem || i->op == Oarge) + if (i->op >= Oarge || a->inmem) continue; r1 = rarg(a->cls[0], &ni, &ns); if (i->op == Oargc) { @@ -393,7 +402,7 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap) r = newtmp("abi", Kl, fn); for (i=i0, a=ac, off=0; i<i1; i++, a++) { - if (!a->inmem) + if (i->op >= Oarge || !a->inmem) continue; if (i->op == Oargc) { if (a->align == 4) @@ -676,7 +685,6 @@ amd64_sysv_abi(Fn *fn) emiti(*i); break; case Ocall: - case Ovacall: for (i0=i; i0>b->ins; i0--) if (!isarg((i0-1)->op)) break; |