From e70ee0ec1a0f7784dac638ac2d782afec4dd7a4c Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sun, 12 May 2019 15:37:10 -0700 Subject: eval: Keep track of kind of constant expression we are evaluating When we are evaluating an arithmetic constant expression, we don't want to indroduce static data definitions for string or compound literals. Fixes #59. --- cc.h | 7 ++++++- eval.c | 20 ++++++++++++-------- expr.c | 8 ++++---- qbe.c | 2 +- test/conditional-compound-literal.c | 4 ++++ test/conditional-compound-literal.qbe | 25 +++++++++++++++++++++++++ 6 files changed, 52 insertions(+), 14 deletions(-) create mode 100644 test/conditional-compound-literal.c create mode 100644 test/conditional-compound-literal.qbe diff --git a/cc.h b/cc.h index 4a97a99..03ae663 100644 --- a/cc.h +++ b/cc.h @@ -442,7 +442,12 @@ struct expr *exprpromote(struct expr *); /* eval */ -struct expr *eval(struct expr *); +enum evalkind { + EVALARITH, /* arithmetic constant expression */ + EVALINIT, /* initializer constant expression */ +}; + +struct expr *eval(struct expr *, enum evalkind); /* init */ diff --git a/eval.c b/eval.c index 1d19180..63047d8 100644 --- a/eval.c +++ b/eval.c @@ -87,7 +87,7 @@ binary(struct expr *expr, enum tokenkind op, struct expr *l, struct expr *r) #undef S struct expr * -eval(struct expr *expr) +eval(struct expr *expr, enum evalkind kind) { struct expr *l, *r, *c; struct decl *d; @@ -100,6 +100,8 @@ eval(struct expr *expr) expr->constant.i = intconstvalue(expr->ident.decl->value); break; case EXPRCOMPOUND: + if (kind != EVALINIT) + break; d = mkdecl(DECLOBJECT, expr->type, expr->qual, LINKNONE); d->value = mkglobal(NULL, true); emitdata(d, expr->compound.init); @@ -107,13 +109,15 @@ eval(struct expr *expr) expr->ident.decl = d; break; case EXPRUNARY: - l = eval(expr->base); + if (kind != EVALINIT) + break; + l = eval(expr->base, kind); if (expr->op != TBAND) break; switch (l->kind) { case EXPRUNARY: if (l->op == TMUL) - expr = eval(l->base); + expr = eval(l->base, kind); break; case EXPRSTRING: l->ident.decl = stringdecl(l); @@ -123,7 +127,7 @@ eval(struct expr *expr) } break; case EXPRCAST: - l = eval(expr->base); + l = eval(expr->base, kind); if (l->kind == EXPRCONST) { expr->kind = EXPRCONST; if (l->type->prop & PROPINT && expr->type->prop & PROPFLOAT) @@ -138,8 +142,8 @@ eval(struct expr *expr) } break; case EXPRBINARY: - l = eval(expr->binary.l); - r = eval(expr->binary.r); + l = eval(expr->binary.l, kind); + r = eval(expr->binary.r, kind); expr->binary.l = l; expr->binary.r = r; switch (expr->op) { @@ -176,10 +180,10 @@ eval(struct expr *expr) case EXPRCOND: l = expr->cond.t; r = expr->cond.f; - c = eval(expr->base); + c = eval(expr->base, kind); if (c->kind != EXPRCONST) break; - return eval(c->constant.i ? l : r); + return eval(c->constant.i ? l : r, kind); } return expr; diff --git a/expr.c b/expr.c index 49e01c0..2e74ba4 100644 --- a/expr.c +++ b/expr.c @@ -557,7 +557,7 @@ builtinfunc(struct scope *s, enum builtinkind kind) e->base = exprconvert(assignexpr(s), &typeulong); break; case BUILTINCONSTANTP: - e = mkconstexpr(&typeint, eval(condexpr(s))->kind == EXPRCONST); + e = mkconstexpr(&typeint, eval(condexpr(s), EVALARITH)->kind == EXPRCONST); break; case BUILTININFF: e = mkexpr(EXPRCONST, &typefloat); @@ -969,8 +969,8 @@ condexpr(struct scope *s) } else if (t == &typevoid && f == &typevoid) { e->type = &typevoid; } else { - e->cond.t = eval(e->cond.t); - e->cond.f = eval(e->cond.f); + e->cond.t = eval(e->cond.t, EVALARITH); + e->cond.f = eval(e->cond.f, EVALARITH); if (nullpointer(e->cond.t) && f->kind == TYPEPOINTER) { e->type = f; } else if (nullpointer(e->cond.f) && t->kind == TYPEPOINTER) { @@ -998,7 +998,7 @@ condexpr(struct scope *s) struct expr * constexpr(struct scope *s) { - return eval(condexpr(s)); + return eval(condexpr(s), EVALARITH); } uint64_t diff --git a/qbe.c b/qbe.c index 4389e27..5135eca 100644 --- a/qbe.c +++ b/qbe.c @@ -1269,7 +1269,7 @@ emitdata(struct decl *d, struct init *init) else if (d->align < d->type->align) error(&tok.loc, "object requires alignment %d, which is stricter than %d", d->type->align, d->align); for (cur = init; cur; cur = cur->next) - cur->expr = eval(cur->expr); + cur->expr = eval(cur->expr, EVALINIT); if (d->linkage == LINKEXTERN) fputs("export ", stdout); fputs("data ", stdout); diff --git a/test/conditional-compound-literal.c b/test/conditional-compound-literal.c new file mode 100644 index 0000000..33a5416 --- /dev/null +++ b/test/conditional-compound-literal.c @@ -0,0 +1,4 @@ +int main(void) { + int x = 0, *p = 0 ? 0 : &(int){x}; + return *p; +} diff --git a/test/conditional-compound-literal.qbe b/test/conditional-compound-literal.qbe new file mode 100644 index 0000000..9e9c5f7 --- /dev/null +++ b/test/conditional-compound-literal.qbe @@ -0,0 +1,25 @@ +export +function w $main() { +@start.1 + %.1 =l alloc4 4 + %.3 =l alloc8 8 + %.6 =l alloc4 4 +@body.2 + %.2 =l add %.1, 0 + storew 0, %.2 + %.4 =l add %.3, 0 + %.5 =w cnew 0, 0 + jnz %.5, @cond_true.3, @cond_false.4 +@cond_true.3 + jmp @cond_join.5 +@cond_false.4 + %.7 =l add %.6, 0 + %.8 =w loadsw %.1 + storew %.8, %.7 +@cond_join.5 + %.9 =l phi @cond_true.3 0, @cond_false.4 %.6 + storel %.9, %.4 + %.10 =l loadl %.3 + %.11 =w loadsw %.10 + ret %.11 +} -- cgit v1.2.3