summary refs log tree commit diff
path: root/amd64
diff options
context:
space:
mode:
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;