Browse Source

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.
Quentin Carbonneaux 4 years ago
parent
commit
fcdef10dae
13 changed files with 101 additions and 75 deletions
  1. 1 2
      all.h
  2. 21 13
      amd64/sysv.c
  3. 11 6
      arm64/abi.c
  4. 3 3
      doc/il.txt
  5. 1 1
      live.c
  6. 1 1
      load.c
  7. 1 1
      ops.h
  8. 31 17
      parse.c
  9. 5 5
      test/_slow.qbe
  10. 9 9
      test/abi5.ssa
  11. 2 2
      test/abi6.ssa
  12. 1 1
      test/echo.ssa
  13. 14 14
      test/vararg2.ssa

+ 1 - 2
all.h

@@ -171,12 +171,11 @@ enum {
 };
 };
 
 
 #define INRANGE(x, l, u) ((unsigned)(x) - l <= u - l) /* linear in x */
 #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 isstore(o) INRANGE(o, Ostoreb, Ostored)
 #define isload(o) INRANGE(o, Oloadsb, Oload)
 #define isload(o) INRANGE(o, Oloadsb, Oload)
 #define isext(o) INRANGE(o, Oextsb, Oextuw)
 #define isext(o) INRANGE(o, Oextsb, Oextuw)
 #define ispar(o) INRANGE(o, Opar, Opare)
 #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)
 #define isret(j) INRANGE(j, Jret0, Jretc)
 
 
 enum Class {
 enum Class {

+ 21 - 13
amd64/sysv.c

@@ -153,7 +153,7 @@ selret(Blk *b, Fn *fn)
 static int
 static int
 argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret, Ref *env)
 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;
 	AClass *a;
 	Ins *i;
 	Ins *i;
 
 
@@ -162,6 +162,8 @@ argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret, Ref *env)
 	else
 	else
 		nint = 6;
 		nint = 6;
 	nsse = 8;
 	nsse = 8;
+	varc = 0;
+	envc = 0;
 	for (i=i0, a=ac; i<i1; i++, a++)
 	for (i=i0, a=ac; i<i1; i++, a++)
 		switch (i->op - op + Oarg) {
 		switch (i->op - op + Oarg) {
 		case Oarg:
 		case Oarg:
@@ -196,14 +198,23 @@ argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret, Ref *env)
 				a->inmem = 1;
 				a->inmem = 1;
 			break;
 			break;
 		case Oarge:
 		case Oarge:
+			envc = 1;
 			if (op == Opar)
 			if (op == Opar)
 				*env = i->to;
 				*env = i->to;
 			else
 			else
 				*env = i->arg[0];
 				*env = i->arg[0];
 			break;
 			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[] = {
 int amd64_sysv_rsave[] = {
@@ -290,7 +301,7 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap)
 {
 {
 	Ins *i;
 	Ins *i;
 	AClass *ac, *a, aret;
 	AClass *ac, *a, aret;
-	int ca, ni, ns, al, varc, envc;
+	int ca, ni, ns, al;
 	uint stk, off;
 	uint stk, off;
 	Ref r, r1, r2, reg[2], env;
 	Ref r, r1, r2, reg[2], env;
 	RAlloc *ra;
 	RAlloc *ra;
@@ -358,22 +369,20 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap)
 			ca += 1 << 2;
 			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));
 	emit(Ocall, i1->cls, R, i1->arg[0], CALL(ca));
-	if (envc)
+
+	if (!req(R, env))
 		emit(Ocopy, Kl, TMP(RAX), env, R);
 		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);
 		emit(Ocopy, Kw, TMP(RAX), getcon((ca >> 8) & 15, fn), R);
 
 
 	ni = ns = 0;
 	ni = ns = 0;
 	if (ra && aret.inmem)
 	if (ra && aret.inmem)
 		emit(Ocopy, Kl, rarg(Kl, &ni, &ns), ra->i.to, R); /* pass hidden argument */
 		emit(Ocopy, Kl, rarg(Kl, &ni, &ns), ra->i.to, R); /* pass hidden argument */
+
 	for (i=i0, a=ac; i<i1; i++, a++) {
 	for (i=i0, a=ac; i<i1; i++, a++) {
-		if (a->inmem || i->op == Oarge)
+		if (i->op >= Oarge || a->inmem)
 			continue;
 			continue;
 		r1 = rarg(a->cls[0], &ni, &ns);
 		r1 = rarg(a->cls[0], &ni, &ns);
 		if (i->op == Oargc) {
 		if (i->op == Oargc) {
@@ -393,7 +402,7 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap)
 
 
 	r = newtmp("abi", Kl, fn);
 	r = newtmp("abi", Kl, fn);
 	for (i=i0, a=ac, off=0; i<i1; i++, a++) {
 	for (i=i0, a=ac, off=0; i<i1; i++, a++) {
-		if (!a->inmem)
+		if (i->op >= Oarge || !a->inmem)
 			continue;
 			continue;
 		if (i->op == Oargc) {
 		if (i->op == Oargc) {
 			if (a->align == 4)
 			if (a->align == 4)
@@ -676,7 +685,6 @@ amd64_sysv_abi(Fn *fn)
 				emiti(*i);
 				emiti(*i);
 				break;
 				break;
 			case Ocall:
 			case Ocall:
-			case Ovacall:
 				for (i0=i; i0>b->ins; i0--)
 				for (i0=i; i0>b->ins; i0--)
 					if (!isarg((i0-1)->op))
 					if (!isarg((i0-1)->op))
 						break;
 						break;

+ 11 - 6
arm64/abi.c

@@ -255,6 +255,10 @@ argsclass(Ins *i0, Ins *i1, Class *carg, Ref *env)
 		case Oarge:
 		case Oarge:
 			*env = i->arg[0];
 			*env = i->arg[0];
 			break;
 			break;
+		case Oargv:
+			break;
+		default:
+			die("unreachable");
 		}
 		}
 
 
 	return ((gp-gpreg) << 5) | ((fp-fpreg) << 9);
 	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);
 	envc = !req(R, env);
 	if (envc)
 	if (envc)
 		die("todo (arm abi): env calls");
 		die("todo (arm abi): env calls");
-	emit(Ocall, 0, R, i1->arg[0], CALL(cty));
 
 
 	if (cty & (1 << 13))
 	if (cty & (1 << 13))
 		/* struct return argument */
 		/* 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++) {
 	for (i=i0, c=ca; i<i1; i++, c++) {
 		if ((c->class & Cstk) != 0)
 		if ((c->class & Cstk) != 0)
 			continue;
 			continue;
-		if (i->op != Oargc)
+		if (i->op == Oarg)
 			emit(Ocopy, *c->cls, TMP(*c->reg), i->arg[0], R);
 			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);
 			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++) {
 	for (i=i0, c=ca; i<i1; i++, c++) {
 		if ((c->class & Cstk) == 0)
 		if ((c->class & Cstk) == 0)
 			continue;
 			continue;
-		if (i->op != Oargc) {
+		if (i->op == Oarg) {
 			r = newtmp("abi", Kl, fn);
 			r = newtmp("abi", Kl, fn);
 			emit(Ostorel, 0, R, i->arg[0], r);
 			emit(Ostorel, 0, R, i->arg[0], r);
 			emit(Oadd, Kl, r, TMP(SP), getcon(off, fn));
 			emit(Oadd, Kl, r, TMP(SP), getcon(off, fn));
-		} else
+		}
+		if (i->op == Oargc)
 			blit(TMP(SP), off, i->arg[1], c->size, fn);
 			blit(TMP(SP), off, i->arg[1], c->size, fn);
 		off += c->size;
 		off += c->size;
 	}
 	}
@@ -675,7 +681,6 @@ arm64_abi(Fn *fn)
 				emiti(*i);
 				emiti(*i);
 				break;
 				break;
 			case Ocall:
 			case Ocall:
-			case Ovacall:
 				for (i0=i; i0>b->ins; i0--)
 				for (i0=i; i0>b->ins; i0--)
 					if (!isarg((i0-1)->op))
 					if (!isarg((i0-1)->op))
 						break;
 						break;

+ 3 - 3
doc/il.txt

@@ -751,7 +751,7 @@ single-precision floating point number `%f` into `%rs`.
     ARG :=
     ARG :=
         ABITY VAL  # Regular argument
         ABITY VAL  # Regular argument
       | 'env' VAL  # Environment argument (first)
       | 'env' VAL  # Environment argument (first)
-      | '...'      # Variadic marker (last)
+      | '...'      # Variadic marker
 
 
     ABITY := BASETY | :IDENT
     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 >
 parameter, it will be safely discarded.  See the <@ Functions >
 section for more information about environment parameters.
 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
 ~ Variadic
 ~~~~~~~~~~
 ~~~~~~~~~~

+ 1 - 1
live.c

@@ -82,7 +82,7 @@ Again:
 		for (k=0; k<2; k++)
 		for (k=0; k<2; k++)
 			b->nlive[k] = nlv[k];
 			b->nlive[k] = nlv[k];
 		for (i=&b->ins[b->nins]; i!=b->ins;) {
 		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);
 				b->in->t[0] &= ~T.retregs(i->arg[1], m);
 				for (k=0; k<2; k++) {
 				for (k=0; k<2; k++) {
 					nlv[k] -= m[k];
 					nlv[k] -= m[k];

+ 1 - 1
load.c

@@ -234,7 +234,7 @@ def(Slice sl, bits msk, Blk *b, Ins *i, Loc *il)
 	while (i > b->ins) {
 	while (i > b->ins) {
 		--i;
 		--i;
 		if (killsl(i->to, sl)
 		if (killsl(i->to, sl)
-		|| (iscall(i->op) && escapes(sl.ref, curf)))
+		|| (i->op == Ocall && escapes(sl.ref, curf)))
 			goto Load;
 			goto Load;
 		ld = isload(i->op);
 		ld = isload(i->op);
 		if (ld) {
 		if (ld) {

+ 1 - 1
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(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(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(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(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 */
 /* Flags Setting */
 O(flagieq,  T(x,x,e,e, x,x,e,e), 0) X(0, 0, 1)
 O(flagieq,  T(x,x,e,e, x,x,e,e), 0) X(0, 0, 1)

+ 31 - 17
parse.c

@@ -450,25 +450,44 @@ parsecls(int *tyn)
 static int
 static int
 parserefl(int arg)
 parserefl(int arg)
 {
 {
-	int k, ty, env, hasenv;
+	int k, ty, env, hasenv, vararg;
 	Ref r;
 	Ref r;
 
 
 	hasenv = 0;
 	hasenv = 0;
+	vararg = 0;
 	expect(Tlparen);
 	expect(Tlparen);
-	while (peek() != Trparen && peek() != Tdots) {
+	while (peek() != Trparen) {
 		if (curi - insb >= NIns)
 		if (curi - insb >= NIns)
 			err("too many instructions (1)");
 			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();
 			next();
 			k = Kl;
 			k = Kl;
-		} else
+			break;
+		default:
+			env = 0;
 			k = parsecls(&ty);
 			k = parsecls(&ty);
+			break;
+		}
 		r = parseref();
 		r = parseref();
 		if (req(r, R))
 		if (req(r, R))
 			err("invalid argument");
 			err("invalid argument");
-		if (hasenv && env)
-			err("only one environment allowed");
 		if (!arg && rtype(r) != RTmp)
 		if (!arg && rtype(r) != RTmp)
 			err("invalid function parameter");
 			err("invalid function parameter");
 		if (k == 4)
 		if (k == 4)
@@ -487,16 +506,13 @@ parserefl(int arg)
 			else
 			else
 				*curi = (Ins){Opar, k, r, {R}};
 				*curi = (Ins){Opar, k, r, {R}};
 		curi++;
 		curi++;
-		hasenv |= env;
+	Next:
 		if (peek() == Trparen)
 		if (peek() == Trparen)
 			break;
 			break;
 		expect(Tcomma);
 		expect(Tcomma);
 	}
 	}
-	if (next() == Tdots) {
-		expect(Trparen);
-		return 1;
-	}
-	return 0;
+	expect(Trparen);
+	return vararg;
 }
 }
 
 
 static Blk *
 static Blk *
@@ -621,10 +637,8 @@ DoOp:
 	}
 	}
 	if (op == Tcall) {
 	if (op == Tcall) {
 		arg[0] = parseref();
 		arg[0] = parseref();
-		if (parserefl(1))
-			op = Ovacall;
-		else
-			op = Ocall;
+		parserefl(1);
+		op = Ocall;
 		expect(Tnl);
 		expect(Tnl);
 		if (k == 4) {
 		if (k == 4) {
 			k = Kl;
 			k = Kl;

+ 5 - 5
test/_slow.qbe

@@ -3408,7 +3408,7 @@ function $transparent_crc(l %.1, l %.3, w %.5) {
 	%.9 =l copy $.Lstring.93
 	%.9 =l copy $.Lstring.93
 	%.10 =l loadl %.4
 	%.10 =l loadl %.4
 	%.11 =l loadl %.2
 	%.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
 @if_false.679
 	%.13 =l loadl $crc32_context
 	%.13 =l loadl $crc32_context
 	%.14 =l loadl %.2
 	%.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
 	%.28 =l loadl $crc32_context
 	%.29 =l copy 4294967295
 	%.29 =l copy 4294967295
 	%.30 =l xor %.28, %.29
 	%.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
 @if_false.687
 	ret
 	ret
 }
 }
@@ -3480,7 +3480,7 @@ function $platform_main_end(l %.1, w %.3) {
 @if_true.690
 @if_true.690
 	%.8 =l copy $.Lstring.97
 	%.8 =l copy $.Lstring.97
 	%.9 =l loadl %.2
 	%.9 =l loadl %.2
-	%.10 =w call $printf(l %.8, l %.9, ...)
+	%.10 =w call $printf(l %.8, ..., l %.9)
 @if_false.691
 @if_false.691
 	ret
 	ret
 }
 }
@@ -35219,7 +35219,7 @@ function w $main(w %.1, l %.3) {
 	%.53 =w loadsw %.5
 	%.53 =w loadsw %.5
 	%.54 =w loadsw %.6
 	%.54 =w loadsw %.6
 	%.55 =w loadsw %.7
 	%.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
 @if_false.1519
 @for_cont.1516
 @for_cont.1516
 	%.57 =w loadsw %.7
 	%.57 =w loadsw %.7
@@ -35338,7 +35338,7 @@ function w $main(w %.1, l %.3) {
 @if_true.1524
 @if_true.1524
 	%.138 =l copy $.Lstring.129
 	%.138 =l copy $.Lstring.129
 	%.139 =w loadsw %.5
 	%.139 =w loadsw %.5
-	%.140 =w call $printf(l %.138, w %.139, ...)
+	%.140 =w call $printf(l %.138, ..., w %.139)
 @if_false.1525
 @if_false.1525
 @for_cont.1522
 @for_cont.1522
 	%.141 =w loadsw %.5
 	%.141 =w loadsw %.5

+ 9 - 9
test/abi5.ssa

@@ -25,41 +25,41 @@ export
 function $test() {
 function $test() {
 @start
 @start
 	%r1 =:st1 call $t1()
 	%r1 =:st1 call $t1()
-	%i1 =w call $printf(l $fmt1, l %r1, ...)
+	%i1 =w call $printf(l $fmt1, ..., l %r1)
 
 
 	%r2 =:st2 call $t2()
 	%r2 =:st2 call $t2()
 	%w2 =w loadw %r2
 	%w2 =w loadw %r2
-	%i2 =w call $printf(l $fmt2, w %w2, ...)
+	%i2 =w call $printf(l $fmt2, ..., w %w2)
 
 
 	%r3 =:st3 call $t3()
 	%r3 =:st3 call $t3()
 	%s3 =s loads %r3
 	%s3 =s loads %r3
 	%r34 =l add %r3, 4
 	%r34 =l add %r3, 4
 	%w3 =w loadw %r34
 	%w3 =w loadw %r34
 	%p3 =d exts %s3
 	%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()
 	%r4 =:st4 call $t4()
 	%w4 =w loadw %r4
 	%w4 =w loadw %r4
 	%r48 =l add 8, %r4
 	%r48 =l add 8, %r4
 	%d4 =d loadd %r48
 	%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()
 	%r5 =:st5 call $t5()
 	%s5 =s loads %r5
 	%s5 =s loads %r5
 	%d5 =d exts %s5
 	%d5 =d exts %s5
 	%r58 =l add %r5, 8
 	%r58 =l add %r5, 8
 	%l5 =l loadl %r58
 	%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()
 	%r6 =:st6 call $t6()
-	%i6 =w call $printf(l $fmt6, l %r6, ...)
+	%i6 =w call $printf(l $fmt6, ..., l %r6)
 
 
 	%r7 =:st7 call $t7()
 	%r7 =:st7 call $t7()
 	%s7 =s loads %r7
 	%s7 =s loads %r7
 	%d71 =d exts %s7
 	%d71 =d exts %s7
 	%r78 =l add %r7, 8
 	%r78 =l add %r7, 8
 	%d72 =d loadd %r78
 	%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()
 	%r8 =:st8 call $t8()
 	%r84 =l add 4, %r8
 	%r84 =l add 4, %r8
@@ -69,14 +69,14 @@ function $test() {
 	%w82 =w loadw %r84
 	%w82 =w loadw %r84
 	%w83 =w loadw %r88
 	%w83 =w loadw %r88
 	%w84 =w loadw %r812
 	%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()
 	%r9 =:st9 call $t9()
 	%r94 =l add 4, %r9
 	%r94 =l add 4, %r9
 	%w9 =w loadw %r9
 	%w9 =w loadw %r9
 	%s9 =s loads %r94
 	%s9 =s loads %r94
 	%d9 =d exts %s9
 	%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
 	ret
 }
 }

+ 2 - 2
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 %h1)
         call $phfa3(:hfa3 %h2)
         call $phfa3(:hfa3 %h2)
         call $phfa3(:hfa3 %h3)
         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
         ret
 }
 }
 
 

+ 1 - 1
test/echo.ssa

@@ -20,7 +20,7 @@ function w $main(w %argc, l %argv) {
 @loop2
 @loop2
 	%sep =w phi @last 10, @nolast 32
 	%sep =w phi @last 10, @nolast 32
 	%arg =l loadl %av
 	%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
 	%av1 =l add %av, 8
 	%ac1 =w sub %ac, 1
 	%ac1 =w sub %ac, 1
 	jmp @loop
 	jmp @loop

+ 14 - 14
test/vararg2.ssa

@@ -19,11 +19,11 @@ export function $qbeprint0(l %fmt, ...) {
 	jnz %isg, @casef, @cased
 	jnz %isg, @casef, @cased
 @casef
 @casef
 	%dbl =d vaarg %vp
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 	jmp @loop
 @cased
 @cased
 	%int =w vaarg %vp
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 	jmp @loop
 @end
 @end
 	%r =w call $puts(l %emptys)
 	%r =w call $puts(l %emptys)
@@ -59,11 +59,11 @@ export function $qbeprint1(w %argw0, l %fmt, ...) {
 	jnz %isg, @casef, @cased
 	jnz %isg, @casef, @cased
 @casef
 @casef
 	%dbl =d vaarg %vp
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 	jmp @loop
 @cased
 @cased
 	%int =w vaarg %vp
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 	jmp @loop
 @end
 @end
 	%r =w call $puts(l %emptys)
 	%r =w call $puts(l %emptys)
@@ -99,11 +99,11 @@ export function $qbeprint2(d %argd0, l %fmt, ...) {
 	jnz %isg, @casef, @cased
 	jnz %isg, @casef, @cased
 @casef
 @casef
 	%dbl =d vaarg %vp
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 	jmp @loop
 @cased
 @cased
 	%int =w vaarg %vp
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 	jmp @loop
 @end
 @end
 	%r =w call $puts(l %emptys)
 	%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
 	jnz %isg, @casef, @cased
 @casef
 @casef
 	%dbl =d vaarg %vp
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 	jmp @loop
 @cased
 @cased
 	%int =w vaarg %vp
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 	jmp @loop
 @end
 @end
 	%r =w call $puts(l %emptys)
 	%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
 	jnz %isg, @casef, @cased
 @casef
 @casef
 	%dbl =d vaarg %vp
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 	jmp @loop
 @cased
 @cased
 	%int =w vaarg %vp
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 	jmp @loop
 @end
 @end
 	%r =w call $puts(l %emptys)
 	%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
 	jnz %isg, @casef, @cased
 @casef
 @casef
 	%dbl =d vaarg %vp
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 	jmp @loop
 @cased
 @cased
 	%int =w vaarg %vp
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 	jmp @loop
 @end
 @end
 	%r =w call $puts(l %emptys)
 	%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
 	jnz %isg, @casef, @cased
 @casef
 @casef
 	%dbl =d vaarg %vp
 	%dbl =d vaarg %vp
-	%r =w call $printf(l %fmtdbl, d %dbl, ...)
+	%r =w call $printf(l %fmtdbl, ..., d %dbl)
 	jmp @loop
 	jmp @loop
 @cased
 @cased
 	%int =w vaarg %vp
 	%int =w vaarg %vp
-	%r =w call $printf(l %fmtint, w %int, ...)
+	%r =w call $printf(l %fmtint, ..., w %int)
 	jmp @loop
 	jmp @loop
 @end
 @end
 	%r =w call $puts(l %emptys)
 	%r =w call $puts(l %emptys)