aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-09-05 12:01:26 -0700
committerMichael Forney <mforney@mforney.org>2021-10-25 10:18:18 -0700
commit9540626e5793583b6feb36d025dc640c7cb97cc8 (patch)
tree348f347f43b764bc08a84f8ed0daef9476864200
parentb764d2eaff0d2031bbc823bfe1eb76531b3335af (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.h1
-rw-r--r--decl.c2
-rw-r--r--ops.h1
-rw-r--r--qbe.c24
-rw-r--r--test/float-promote.qbe2
5 files changed, 19 insertions, 11 deletions
diff --git a/cc.h b/cc.h
index f98f6aa..14b71b0 100644
--- a/cc.h
+++ b/cc.h
@@ -219,6 +219,7 @@ struct type {
struct {
_Bool isprototype, isvararg, isnoreturn, paraminfo;
struct param *params;
+ size_t nparam;
} func;
struct {
char *tag;
diff --git a/decl.c b/decl.c
index c570efa..c673463 100644
--- a/decl.c
+++ b/decl.c
@@ -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)) {
diff --git a/ops.h b/ops.h
index be588a1..b8b461a 100644
--- a/ops.h
+++ b/ops.h
@@ -93,7 +93,6 @@ OP(ICOPY, "copy")
/* call */
OP(ICALL, "call")
-OP(IVACALL, "call")
/* variadic */
OP(IVASTART, "vastart")
diff --git a/qbe.c b/qbe.c
index f9a6f08..78a2feb 100644
--- a/qbe.c
+++ b/qbe.c
@@ -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
}