summary refs log tree commit diff
path: root/amd64
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin@c9x.me>2021-10-18 21:04:10 +0200
committerQuentin Carbonneaux <quentin@c9x.me>2021-10-22 23:53:25 +0200
commitfcdef10dae54d7124aca9ccbefe53baa8e67267d (patch)
tree1215b60f1f3a31d38ee37228dd37bcc4a6a61f99 /amd64
parent9858a12730717d9c5e5deec4264d7041d75fc947 (diff)
downloadroux-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.c34
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;