~mcf/cproc

e70ee0ec1a0f7784dac638ac2d782afec4dd7a4c — Michael Forney 1 year, 6 months ago f7b471b
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.
6 files changed, 52 insertions(+), 14 deletions(-)

M cc.h
M eval.c
M expr.c
M qbe.c
A test/conditional-compound-literal.c
A test/conditional-compound-literal.qbe
M cc.h => cc.h +6 -1
@@ 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 */


M eval.c => eval.c +12 -8
@@ 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;

M expr.c => expr.c +4 -4
@@ 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

M qbe.c => qbe.c +1 -1
@@ 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);

A test/conditional-compound-literal.c => test/conditional-compound-literal.c +4 -0
@@ 0,0 1,4 @@
int main(void) {
	int x = 0, *p = 0 ? 0 : &(int){x};
	return *p;
}

A test/conditional-compound-literal.qbe => test/conditional-compound-literal.qbe +25 -0
@@ 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
}