aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-09-28 17:35:46 -0700
committerMichael Forney <mforney@mforney.org>2021-09-28 17:39:59 -0700
commite196f1607a9f07198653431681617a601edc07f3 (patch)
treea60f64f7ae58f0acba64b263bd1ed3496eb02c0d
parentf4161c24d903fd4ecfd130d00fb410ef7b70eb16 (diff)
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.c72
-rw-r--r--test/conditional-compound-literal.c2
-rw-r--r--test/conditional-compound-literal.qbe19
-rw-r--r--test/conditional-constant.c6
-rw-r--r--test/conditional-constant.qbe16
5 files changed, 71 insertions, 44 deletions
diff --git a/expr.c b/expr.c
index 2bf711a..182972e 100644
--- a/expr.c
+++ b/expr.c
@@ -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
+}