diff options
| author | Michael Forney <mforney@mforney.org> | 2021-09-28 17:35:46 -0700 | 
|---|---|---|
| committer | Michael Forney <mforney@mforney.org> | 2021-09-28 17:39:59 -0700 | 
| commit | e196f1607a9f07198653431681617a601edc07f3 (patch) | |
| tree | a60f64f7ae58f0acba64b263bd1ed3496eb02c0d | |
| parent | f4161c24d903fd4ecfd130d00fb410ef7b70eb16 (diff) | |
| download | cproc-e196f1607a9f07198653431681617a601edc07f3.tar.xz | |
expr: Skip codegen for unused expression in conditional with constant expression
This compiles `0 ? e1 : e2` as `e2`, and `1 ? e1 : e2` as `e1`
(while still adjusting the type as necessary).
| -rw-r--r-- | expr.c | 72 | ||||
| -rw-r--r-- | test/conditional-compound-literal.c | 2 | ||||
| -rw-r--r-- | test/conditional-compound-literal.qbe | 19 | ||||
| -rw-r--r-- | test/conditional-constant.c | 6 | ||||
| -rw-r--r-- | test/conditional-constant.qbe | 16 | 
5 files changed, 71 insertions, 44 deletions
| @@ -1007,49 +1007,53 @@ binaryexpr(struct scope *s, struct expr *l, int i)  static struct expr *  condexpr(struct scope *s)  { -	struct expr *r, *e; -	struct type *t, *f; +	struct expr *e, *l, *r; +	struct type *t, *lt, *rt;  	enum typequal tq; -	r = binaryexpr(s, NULL, 0); +	e = binaryexpr(s, NULL, 0);  	if (!consume(TQUESTION)) -		return r; -	e = mkexpr(EXPRCOND, NULL, r); -	e->cond.t = expr(s); +		return e; +	l = expr(s);  	expect(TCOLON, "in conditional expression"); -	e->cond.f = condexpr(s); -	t = e->cond.t->type; -	f = e->cond.f->type; -	if (t == f) { -		e->type = t; -	} else if (t->prop & PROPARITH && f->prop & PROPARITH) { -		e->type = commonreal(&e->cond.t, &e->cond.f); -	} else if (t == &typevoid && f == &typevoid) { -		e->type = &typevoid; +	r = condexpr(s); + +	lt = l->type; +	rt = r->type; +	if (lt == rt) { +		t = lt; +	} else if (lt->prop & PROPARITH && rt->prop & PROPARITH) { +		t = commonreal(&l, &r); +	} else if (lt == &typevoid && rt == &typevoid) { +		t = &typevoid;  	} else { -		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) { -			e->type = t; -		} else if (t->kind == TYPEPOINTER && f->kind == TYPEPOINTER) { -			tq = t->qual | f->qual; -			t = t->base; -			f = f->base; -			if (t == &typevoid || f == &typevoid) { -				e->type = &typevoid; -			} else { -				if (!typecompatible(t, f)) -					error(&tok.loc, "operands of conditional operator must have compatible types"); -				e->type = typecomposite(t, f); -			} -			e->type = mkpointertype(e->type, tq); +		l = eval(l, EVALARITH); +		r = eval(r, EVALARITH); +		if (nullpointer(l) && rt->kind == TYPEPOINTER) { +			t = rt; +		} else if (nullpointer(r) && lt->kind == TYPEPOINTER) { +			t = lt; +		} else if (lt->kind == TYPEPOINTER && rt->kind == TYPEPOINTER) { +			tq = lt->qual | rt->qual; +			lt = lt->base; +			rt = rt->base; +			if (lt == &typevoid || rt == &typevoid) +				t = &typevoid; +			else if (typecompatible(lt, rt)) +				t = typecomposite(lt, rt); +			else +				error(&tok.loc, "operands of conditional operator must have compatible types"); +			t = mkpointertype(t, tq);  		} else {  			error(&tok.loc, "invalid operands to conditional operator");  		}  	} - +	e = eval(e, EVALARITH); +	if (e->kind == EXPRCONST && e->type->prop & PROPINT) +		return exprconvert(e->constant.i ? l : r, t); +	e = mkexpr(EXPRCOND, t, e); +	e->cond.t = l; +	e->cond.f = r;  	return e;  } diff --git a/test/conditional-compound-literal.c b/test/conditional-compound-literal.c index 33a5416..40b8ad6 100644 --- a/test/conditional-compound-literal.c +++ b/test/conditional-compound-literal.c @@ -1,4 +1,4 @@  int main(void) { -	int x = 0, *p = 0 ? 0 : &(int){x}; +	int x = 0, *p = x ? 0 : &(int){x};  	return *p;  } diff --git a/test/conditional-compound-literal.qbe b/test/conditional-compound-literal.qbe index 739eea4..d2265c6 100644 --- a/test/conditional-compound-literal.qbe +++ b/test/conditional-compound-literal.qbe @@ -3,19 +3,20 @@ function w $main() {  @start.1  	%.1 =l alloc4 4  	%.2 =l alloc8 8 -	%.3 =l alloc4 4 +	%.4 =l alloc4 4  @body.2  	storew 0, %.1 -	jnz 0, @cond_true.3, @cond_false.4 +	%.3 =w loadw %.1 +	jnz %.3, @cond_true.3, @cond_false.4  @cond_true.3  	jmp @cond_join.5  @cond_false.4 -	%.4 =w loadw %.1 -	storew %.4, %.3 +	%.5 =w loadw %.1 +	storew %.5, %.4  @cond_join.5 -	%.5 =l phi @cond_true.3 0, @cond_false.4 %.3 -	storel %.5, %.2 -	%.6 =l loadl %.2 -	%.7 =w loadw %.6 -	ret %.7 +	%.6 =l phi @cond_true.3 0, @cond_false.4 %.4 +	storel %.6, %.2 +	%.7 =l loadl %.2 +	%.8 =w loadw %.7 +	ret %.8  } diff --git a/test/conditional-constant.c b/test/conditional-constant.c new file mode 100644 index 0000000..8ebb2a4 --- /dev/null +++ b/test/conditional-constant.c @@ -0,0 +1,6 @@ +int main(void) { +	if ((0 ? 0 : 123) != 123) +		return 1; +	if ((1 ? 456 : 0) != 456) +		return 1; +} diff --git a/test/conditional-constant.qbe b/test/conditional-constant.qbe new file mode 100644 index 0000000..a14e050 --- /dev/null +++ b/test/conditional-constant.qbe @@ -0,0 +1,16 @@ +export +function w $main() { +@start.1 +@body.2 +	%.1 =w cnew 123, 123 +	jnz %.1, @if_true.3, @if_false.4 +@if_true.3 +	ret 1 +@if_false.4 +	%.2 =w cnew 456, 456 +	jnz %.2, @if_true.5, @if_false.6 +@if_true.5 +	ret 1 +@if_false.6 +	ret 0 +} | 
