summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--all.h3
-rw-r--r--amd64/sysv.c34
-rw-r--r--arm64/abi.c17
-rw-r--r--doc/il.txt6
-rw-r--r--live.c2
-rw-r--r--load.c2
-rw-r--r--ops.h2
-rw-r--r--parse.c48
-rw-r--r--test/_slow.qbe10
-rw-r--r--test/abi5.ssa18
-rw-r--r--test/abi6.ssa4
-rw-r--r--test/echo.ssa2
-rw-r--r--test/vararg2.ssa28
13 files changed, 101 insertions, 75 deletions
diff --git a/all.h b/all.h
index 4b9eb0e..37980d3 100644
--- a/all.h
+++ b/all.h
@@ -171,12 +171,11 @@ enum {
 };
 
 #define INRANGE(x, l, u) ((unsigned)(x) - l <= u - l) /* linear in x */
-#define iscall(o) INRANGE(o, Ocall, Ovacall)
 #define isstore(o) INRANGE(o, Ostoreb, Ostored)
 #define isload(o) INRANGE(o, Oloadsb, Oload)
 #define isext(o) INRANGE(o, Oextsb, Oextuw)
 #define ispar(o) INRANGE(o, Opar, Opare)
-#define isarg(o) INRANGE(o, Oarg, Oarge)
+#define isarg(o) INRANGE(o, Oarg, Oargv)
 #define isret(j) INRANGE(j, Jret0, Jretc)
 
 enum Class {
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;
diff --git a/arm64/abi.c b/arm64/abi.c
index 5fe9553..d38dcf5 100644
--- a/arm64/abi.c
+++ b/arm64/abi.c
@@ -255,6 +255,10 @@ argsclass(Ins *i0, Ins *i1, Class *carg, Ref *env)
 		case Oarge:
 			*env = i->arg[0];
 			break;
+		case Oargv:
+			break;
+		default:
+			die("unreachable");
 		}
 
 	return ((gp-gpreg) << 5) | ((fp-fpreg) << 9);
@@ -371,10 +375,11 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
 		}
 	}
 
+	emit(Ocall, 0, R, i1->arg[0], CALL(cty));
+
 	envc = !req(R, env);
 	if (envc)
 		die("todo (arm abi): env calls");
-	emit(Ocall, 0, R, i1->arg[0], CALL(cty));
 
 	if (cty & (1 << 13))
 		/* struct return argument */
@@ -383,9 +388,9 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
 	for (i=i0, c=ca; i<i1; i++, c++) {
 		if ((c->class & Cstk) != 0)
 			continue;
-		if (i->op != Oargc)
+		if (i->op == Oarg)
 			emit(Ocopy, *c->cls, TMP(*c->reg), i->arg[0], R);
-		else
+		if (i->op == Oargc)
 			ldregs(c->reg, c->cls, c->nreg, i->arg[1], fn);
 	}
 
@@ -393,11 +398,12 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
 	for (i=i0, c=ca; i<i1; i++, c++) {
 		if ((c->class & Cstk) == 0)
 			continue;
-		if (i->op != Oargc) {
+		if (i->op == Oarg) {
 			r = newtmp("abi", Kl, fn);
 			emit(Ostorel, 0, R, i->arg[0], r);
 			emit(Oadd, Kl, r, TMP(SP), getcon(off, fn));
-		} else
+		}
+		if (i->op == Oargc)
 			blit(TMP(SP), off, i->arg[1], c->size, fn);
 		off += c->size;
 	}
@@ -675,7 +681,6 @@ arm64_abi(Fn *fn)
 				emiti(*i);
 				break;
 			case Ocall:
-			case Ovacall:
 				for (i0=i; i0>b->ins; i0--)
 					if (!isarg((i0-1)->op))
 						break;
diff --git a/doc/il.txt b/doc/il.txt
index d1ed755..87a4d9f 100644
--- a/doc/il.txt
+++ b/doc/il.txt
@@ -751,7 +751,7 @@ single-precision floating point number `%f` into `%rs`.
     ARG :=
         ABITY VAL  # Regular argument
       | 'env' VAL  # Environment argument (first)
-      | '...'      # Variadic marker (last)
+      | '...'      # Variadic marker
 
     ABITY := BASETY | :IDENT
 
@@ -778,8 +778,8 @@ integer.  If the called function does not expect an environment
 parameter, it will be safely discarded.  See the <@ Functions >
 section for more information about environment parameters.
 
-When the called function is variadic, the last argument
-must be `...`.
+When the called function is variadic, there must be a `...`
+marker separating the named and variadic arguments.
 
 ~ Variadic
 ~~~~~~~~~~
diff --git a/live.c b/live.c
index c22e063..4198995 100644
--- a/live.c
+++ b/live.c
@@ -82,7 +82,7 @@ Again:
 		for (k=0; k<2; k++)
 			b->nlive[k] = nlv[k];
 		for (i=&b->ins[b->nins]; i!=b->ins;) {
-			if (iscall((--i)->op) && rtype(i->arg[1]) == RCall) {
+			if ((--i)->op == Ocall && rtype(i->arg[1]) == RCall) {
 				b->in->t[0] &= ~T.retregs(i->arg[1], m);
 				for (k=0; k<2; k++) {
 					nlv[k] -= m[k];
diff --git a/load.c b/load.c
index f3a695b..5d61a6c 100644
--- a/load.c
+++ b/load.c
@@ -234,7 +234,7 @@ def(Slice sl, bits msk, Blk *b, Ins *i, Loc *il)
 	while (i > b->ins) {
 		--i;
 		if (killsl(i->to, sl)
-		|| (iscall(i->op) && escapes(sl.ref, curf)))
+		|| (i->op == Ocall && escapes(sl.ref, curf)))
 			goto Load;
 		ld = isload(i->op);
 		if (ld) {
diff --git a/ops.h b/ops.h
index 114310c..535be71 100644
--- a/ops.h
+++ b/ops.h
@@ -137,8 +137,8 @@ O(pare,    T(e,x,e,e, e,x,e,e), 0) X(0, 0, 0)
 O(arg,     T(w,l,s,d, x,x,x,x), 0) X(0, 0, 0)
 O(argc,    T(e,x,e,e, e,l,e,e), 0) X(0, 0, 0)
 O(arge,    T(e,l,e,e, e,x,e,e), 0) X(0, 0, 0)
+O(argv,    T(x,x,x,x, x,x,x,x), 0) X(0, 0, 0)
 O(call,    T(m,m,m,m, x,x,x,x), 0) X(0, 0, 0)
-O(vacall,  T(m,m,m,m, x,x,x,x), 0) X(0, 0, 0)
 
 /* Flags Setting */
 O(flagieq,  T(x,x,e,e, x,x,e,e), 0) X(0, 0, 1)
diff --git a/parse.c b/parse.c
index da88f58..104ca1d 100644
--- a/parse.c
+++ b/parse.c
@@ -450,25 +450,44 @@ parsecls(int *tyn)
 static int
 parserefl(int arg)
 {
-	int k, ty, env, hasenv;
+	int k, ty, env, hasenv, vararg;
 	Ref r;
 
 	hasenv = 0;
+	vararg = 0;
 	expect(Tlparen);
-	while (peek() != Trparen && peek() != Tdots) {
+	while (peek() != Trparen) {
 		if (curi - insb >= NIns)
 			err("too many instructions (1)");
-		env = peek() == Tenv;
-		if (env) {
+		if (!arg && vararg)
+			err("no parameters allowed after '...'");
+		switch (peek()) {
+		case Tdots:
+			if (vararg)
+				err("only one '...' allowed");
+			vararg = 1;
+			if (arg) {
+				*curi = (Ins){.op = Oargv};
+				curi++;
+			}
+			next();
+			goto Next;
+		case Tenv:
+			if (hasenv)
+				err("only one environment allowed");
+			hasenv = 1;
+			env = 1;
 			next();
 			k = Kl;
-		} else
+			break;
+		default:
+			env = 0;
 			k = parsecls(&ty);
+			break;
+		}
 		r = parseref();
 		if (req(r, R))
 			err("invalid argument");
-		if (hasenv && env)
-			err("only one environment allowed");
 		if (!arg && rtype(r) != RTmp)
 			err("invalid function parameter");
 		if (k == 4)
@@ -487,16 +506,13 @@ parserefl(int arg)
 			else
 				*curi = (Ins){Opar, k, r, {R}};
 		curi++;
-		hasenv |= env;
+	Next:
 		if (peek() == Trparen)
 			break;
 		expect(Tcomma);
 	}
-	if (next() == Tdots) {
-		expect(Trparen);
-		return 1;
-	}
-	return 0;
+	expect(Trparen);
+	return vararg;
 }
 
 static Blk *
@@ -621,10 +637,8 @@ DoOp:
 	}
 	if (op == Tcall) {
 		arg[0] = parseref();
-		if (parserefl(1))
-			op = Ovacall;
-		else
-			op = Ocall;
+		parserefl(1);
+		op = Ocall;
 		expect(Tnl);
 		if (k == 4) {
 			k = Kl;
diff --git a/test/_slow.qbe b/test/_slow.qbe
index 2d107ae..a411e41 100644
--- a/test/_slow.qbe
+++ b/test/_slow.qbe
@@ -3408,7 +3408,7 @@ function $transparent_crc(l %.1, l %.3, w %.5) {
 	%.9 =l copy $.Lstring.93
 	%.10 =l loadl %.4
 	%.11 =l loadl %.2
-	%.12 =w call $printf(l %.9, l %.10, l %.11, ...)
+	%.12 =w call $printf(l %.9, ..., l %.10, l %.11)
 @if_false.679
 	%.13 =l loadl $crc32_context
 	%.14 =l loadl %.2
@@ -3461,7 +3461,7 @@ function $transparent_crc_bytes(l %.1, w %.3, l %.5, w %.7) {
 	%.28 =l loadl $crc32_context
 	%.29 =l copy 4294967295
 	%.30 =l xor %.28, %.29
-	%.31 =w call $printf(l %.26, l %.27, l %.30, ...)
+	%.31 =w call $printf(l %.26, ..., l %.27, l %.30)
 @if_false.687
 	ret
 }
@@ -3480,7 +3480,7 @@ function $platform_main_end(l %.1, w %.3) {
 @if_true.690
 	%.8 =l copy $.Lstring.97
 	%.9 =l loadl %.2
-	%.10 =w call $printf(l %.8, l %.9, ...)
+	%.10 =w call $printf(l %.8, ..., l %.9)
 @if_false.691
 	ret
 }
@@ -35219,7 +35219,7 @@ function w $main(w %.1, l %.3) {
 	%.53 =w loadsw %.5
 	%.54 =w loadsw %.6
 	%.55 =w loadsw %.7
-	%.56 =w call $printf(l %.52, w %.53, w %.54, w %.55, ...)
+	%.56 =w call $printf(l %.52, ..., w %.53, w %.54, w %.55)
 @if_false.1519
 @for_cont.1516
 	%.57 =w loadsw %.7
@@ -35338,7 +35338,7 @@ function w $main(w %.1, l %.3) {
 @if_true.1524
 	%.138 =l copy $.Lstring.129
 	%.139 =w loadsw %.5
-	%.140 =w call $printf(l %.138, w %.139, ...)
+	%.140 =w call $printf(l %.138, ..., w %.139)
 @if_false.1525
 @for_cont.1522
 	%.141 =w loadsw %.5
diff --git a/test/abi5.ssa b/test/abi5.ssa
index edfda4e..1d823b1 100644
--- a/test/abi5.ssa
+++ b/test/abi5.ssa
@@ -25,41 +25,41 @@ export
 function $test() {
 @start
 	%r1 =:st1 call $t1()
-	%i1 =w call $printf(l $fmt1, l %r1, ...)
+	%i1 =w call $printf(l $fmt1, ..., l %r1)
 
 	%r2 =:st2 call $t2()
 	%w2 =w loadw %r2
-	%i2 =w call $printf(l $fmt2, w %w2, ...)
+	%i2 =w call $printf(l $fmt2, ..., w %w2)
 
 	%r3 =:st3 call $t3()
 	%s3 =s loads %r3
 	%r34 =l add %r3, 4
 	%w3 =w loadw %r34
 	%p3 =d exts %s3
-	%i3 =w call $printf(l $fmt3, d %p3, w %w3, ...)
+	%i3 =w call $printf(l $fmt3, ..., d %p3, w %w3)
 
 	%r4 =:st4 call $t4()
 	%w4 =w loadw %r4
 	%r48 =l add 8, %r4
 	%d4 =d loadd %r48
-	%i4 =w call $printf(l $fmt4, w %w4, d %d4, ...)
+	%i4 =w call $printf(l $fmt4, ..., w %w4, d %d4)
 
 	%r5 =:st5 call $t5()
 	%s5 =s loads %r5
 	%d5 =d exts %s5
 	%r58 =l add %r5, 8
 	%l5 =l loadl %r58
-	%i5 =w call $printf(l $fmt5, d %d5, l %l5, ...)
+	%i5 =w call $printf(l $fmt5, ..., d %d5, l %l5)
 
 	%r6 =:st6 call $t6()
-	%i6 =w call $printf(l $fmt6, l %r6, ...)
+	%i6 =w call $printf(l $fmt6, ..., l %r6)
 
 	%r7 =:st7 call $t7()
 	%s7 =s loads %r7
 	%d71 =d exts %s7
 	%r78 =l add %r7, 8
 	%d72 =d loadd %r78
-	%i7 =w call $printf(l $fmt7, d %d71, d %d72, ...)
+	%i7 =w call $printf(l $fmt7, ..., d %d71, d %d72)
 
 	%r8 =:st8 call $t8()
 	%r84 =l add 4, %r8
@@ -69,14 +69,14 @@ function $test() {
 	%w82 =w loadw %r84
 	%w83 =w loadw %r88
 	%w84 =w loadw %r812
-	%i8 =w call $printf(l $fmt8, w %w81, w %w82, w %w83, w %w84, ...)
+	%i8 =w call $printf(l $fmt8, ..., w %w81, w %w82, w %w83, w %w84)
 
 	%r9 =:st9 call $t9()
 	%r94 =l add 4, %r9
 	%w9 =w loadw %r9
 	%s9 =s loads %r94
 	%d9 =d exts %s9
-	%i9 =w call $printf(l $fmt9, w %w9, d %d9, ...)
+	%i9 =w call $printf(l $fmt9, ..., w %w9, d %d9)
 
 	ret
 }
diff --git a/test/abi6.ssa b/test/abi6.ssa
index 0870031..da2370c 100644
--- a/test/abi6.ssa
+++ b/test/abi6.ssa
@@ -13,8 +13,8 @@ function $f(:hfa3 %h1, :hfa3 %h2, d %d1, :hfa3 %h3, d %d2) {
         call $phfa3(:hfa3 %h1)
         call $phfa3(:hfa3 %h2)
         call $phfa3(:hfa3 %h3)
-        call $printf(l $dfmt, d %d1, ...)
-        call $printf(l $dfmt, d %d2, ...)
+        call $printf(l $dfmt, ..., d %d1)
+        call $printf(l $dfmt, ..., d %d2)
         ret
 }
 
diff --git a/test/echo.ssa b/test/echo.ssa
index 6010986..5e48b0e 100644
--- a/test/echo.ssa
+++ b/test/echo.ssa
@@ -20,7 +20,7 @@ function w $main(w %argc, l %argv) {
 @loop2
 	%sep =w phi @last 10, @nolast 32
 	%arg =l loadl %av
-	%r =w call $printf(l %fmt, l %arg, w %sep, ...)
+	%r =w call $printf(l %fmt, ..., l %arg, w %sep)
 	%av1 =l add %av, 8
 	%ac1 =w sub %ac, 1
 	jmp @loop
diff --git a/test/vararg2.ssa b/test/vararg2.ssa
index 7e85774..0b2eb53 100644
--- a/test/vararg2.ssa
+++ b/test/vararg2.ssa
@@ -19,11 +19,11 @@ export function $qbeprint0(l %fmt, ...) {
 	jnz %isg, @casef, @cased
 @casef
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 @cased
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 @end
 	%r =w call $puts(l %emptys)
@@ -59,11 +59,11 @@ export function $qbeprint1(w %argw0, l %fmt, ...) {
 	jnz %isg, @casef, @cased
 @casef
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 @cased
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 @end
 	%r =w call $puts(l %emptys)
@@ -99,11 +99,11 @@ export function $qbeprint2(d %argd0, l %fmt, ...) {
 	jnz %isg, @casef, @cased
 @casef
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 @cased
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 @end
 	%r =w call $puts(l %emptys)
@@ -139,11 +139,11 @@ export function $qbeprint3(w %argw0, w %argw1, w %argw2, w %argw3, l %fmt, ...)
 	jnz %isg, @casef, @cased
 @casef
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 @cased
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 @end
 	%r =w call $puts(l %emptys)
@@ -179,11 +179,11 @@ export function $qbeprint4(d %argd0, d %argd1, d %argd2, d %argd3, d %argd4, d %
 	jnz %isg, @casef, @cased
 @casef
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 @cased
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 @end
 	%r =w call $puts(l %emptys)
@@ -219,11 +219,11 @@ export function $qbeprint5(w %argw0, w %argw1, w %argw2, w %argw3, w %argw4, d %
 	jnz %isg, @casef, @cased
 @casef
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 @cased
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 @end
 	%r =w call $puts(l %emptys)
@@ -259,11 +259,11 @@ export function $qbeprint6(w %argw0, w %argw1, w %argw2, w %argw3, w %argw4, w %
 	jnz %isg, @casef, @cased
 @casef
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 @cased
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 @end
 	%r =w call $puts(l %emptys)