diff options
author | Michael Forney <mforney@mforney.org> | 2021-09-05 12:01:26 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2021-10-25 10:18:18 -0700 |
commit | 9540626e5793583b6feb36d025dc640c7cb97cc8 (patch) | |
tree | 348f347f43b764bc08a84f8ed0daef9476864200 | |
parent | b764d2eaff0d2031bbc823bfe1eb76531b3335af (diff) |
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.
-rw-r--r-- | cc.h | 1 | ||||
-rw-r--r-- | decl.c | 2 | ||||
-rw-r--r-- | ops.h | 1 | ||||
-rw-r--r-- | qbe.c | 24 | ||||
-rw-r--r-- | test/float-promote.qbe | 2 |
5 files changed, 19 insertions, 11 deletions
@@ -219,6 +219,7 @@ struct type { struct { _Bool isprototype, isvararg, isnoreturn, paraminfo; struct param *params; + size_t nparam; } func; struct { char *tag; @@ -516,6 +516,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: @@ -534,6 +535,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)) { @@ -93,7 +93,6 @@ OP(ICOPY, "copy") /* call */ OP(ICALL, "call") -OP(IVACALL, "call") /* variadic */ OP(IVASTART, "vastart") @@ -40,6 +40,7 @@ enum instkind { #undef OP IARG, + IVARARG, }; struct qbetype { @@ -722,7 +723,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) { @@ -761,7 +762,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); @@ -769,12 +769,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: @@ -1181,20 +1184,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: diff --git a/test/float-promote.qbe b/test/float-promote.qbe index 5dad07c..97638e7 100644 --- a/test/float-promote.qbe +++ b/test/float-promote.qbe @@ -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 } |