~mcf/cproc

a5261af896d2cefc3c026a03e1c2c0beb3a77d7d — Michael Forney 2 months ago e07ea69 vararg-call
qbe: Use ... to separate named and variadic arguments

This requires a not-yet-upstream QBE patch, and is needed for riscv64
support, since the calling convention may be different depending
on whether the argument is named or variadic.
6 files changed, 20 insertions(+), 12 deletions(-)

M cc.h
M decl.c
M ops.h
M qbe
M qbe.c
M test/float-promote.qbe
M cc.h => cc.h +1 -0
@@ 219,6 219,7 @@ struct type {
		struct {
			_Bool isprototype, isvararg, isnoreturn, paraminfo;
			struct param *params;
			size_t nparam;
		} func;
		struct {
			char *tag;

M decl.c => decl.c +2 -0
@@ 517,6 517,7 @@ declaratortypes(struct scope *s, struct list *result, char **name, bool allowabs
			t->func.isvararg = false;
			t->func.isnoreturn = false;
			t->func.params = NULL;
			t->func.nparam = 0;
			p = &t->func.params;
			switch (tok.kind) {
			case TIDENT:


@@ 535,6 536,7 @@ declaratortypes(struct scope *s, struct list *result, char **name, bool allowabs
				for (;;) {
					*p = parameter(s);
					p = &(*p)->next;
					++t->func.nparam;
					if (!consume(TCOMMA))
						break;
					if (consume(TELLIPSIS)) {

M ops.h => ops.h +0 -1
@@ 93,7 93,6 @@ OP(ICOPY,    "copy")

/* call */
OP(ICALL,    "call")
OP(IVACALL,  "call")

/* variadic */
OP(IVASTART, "vastart")

M qbe => qbe +1 -1
@@ 1,1 1,1 @@
Subproject commit 59e8ceaa5f8d6da1524cce8ea94c8ab1bb76b98f
Subproject commit 1b9474acd2a3fb6d883bb87620aa55d6d2b9651b

M qbe.c => qbe.c +15 -9
@@ 42,6 42,7 @@ enum instkind {
#undef OP

	IARG,
	IVARARG,
};

struct qbetype {


@@ 709,7 710,7 @@ funcexpr(struct func *f, struct expr *e)
	struct lvalue lval;
	struct expr *arg;
	struct block *b[3];
	struct type *t;
	struct type *t, *functype;
	size_t i;

	switch (e->kind) {


@@ 748,7 749,6 @@ funcexpr(struct func *f, struct expr *e)
		v = funcstore(f, e->type, e->qual, lval, v);
		return e->incdec.post ? l : v;
	case EXPRCALL:
		op = e->base->type->base->func.isvararg ? IVACALL : ICALL;
		argvals = xreallocarray(NULL, e->call.nargs, sizeof(argvals[0]));
		for (arg = e->call.args, i = 0; arg; arg = arg->next, ++i) {
			emittype(arg->type);


@@ 756,12 756,15 @@ funcexpr(struct func *f, struct expr *e)
		}
		t = e->type;
		emittype(t);
		v = funcinst(f, op, qbetype(t).base, funcexpr(f, e->base), t->value);
		v = funcinst(f, ICALL, qbetype(t).base, funcexpr(f, e->base), t->value);
		functype = e->base->type->base;
		for (arg = e->call.args, i = 0; arg; arg = arg->next, ++i) {
			if (functype->func.isvararg && i == functype->func.nparam)
				funcinst(f, IVARARG, 0, NULL, NULL);
			t = arg->type;
			funcinst(f, IARG, qbetype(t).base, argvals[i], t->value);
		}
		//if (e->base->type->base->func.isnoreturn)
		//if (functype->func.isnoreturn)
		//	funcret(f, NULL);
		return v;
	case EXPRUNARY:


@@ 1161,20 1164,23 @@ emitinst(struct inst **instp, struct inst **instend)
	op = inst->kind;
	switch (op) {
	case ICALL:
	case IVACALL:
		putchar('(');
		for (first = 1; instp != instend && (*instp)->kind == IARG; ++instp) {
		for (first = 1; instp != instend; ++instp) {
			inst = *instp;
			if (inst->kind == IVARARG) {
				fputs(", ...", stdout);
				continue;
			}
			if (inst->kind != IARG)
				break;
			if (first)
				first = 0;
			else
				fputs(", ", stdout);
			inst = *instp;
			emitclass(inst->class, inst->arg[1]);
			putchar(' ');
			emitvalue(inst->arg[0]);
		}
		if (op == IVACALL)
			fputs(", ...", stdout);
		putchar(')');
		break;
	default:

M test/float-promote.qbe => test/float-promote.qbe +1 -1
@@ 5,7 5,7 @@ function $f() {
	%.1 =d exts s_1
	call $g1(d %.1)
	%.2 =d exts s_1
	call $g2(w 0, d %.2, ...)
	call $g2(w 0, ..., d %.2)
	call $g3(s s_1)
	ret
}