cproc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/cproc
Log | Files | Refs | Submodules | README | LICENSE

commit e70ee0ec1a0f7784dac638ac2d782afec4dd7a4c
parent f7b471b8576846e575f8c73ef6b70c4b06ff377d
Author: Michael Forney <mforney@mforney.org>
Date:   Sun, 12 May 2019 15:37:10 -0700

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.

Diffstat:
Mcc.h | 7++++++-
Meval.c | 20++++++++++++--------
Mexpr.c | 8++++----
Mqbe.c | 2+-
Atest/conditional-compound-literal.c | 4++++
Atest/conditional-compound-literal.qbe | 25+++++++++++++++++++++++++
6 files changed, 52 insertions(+), 14 deletions(-)

diff --git 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 +}