summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ir.c107
-rw-r--r--test.lang4
2 files changed, 64 insertions, 47 deletions
diff --git a/ir.c b/ir.c
index c64001e..2e1fe8e 100644
--- a/ir.c
+++ b/ir.c
@@ -412,6 +412,22 @@ static inline int node_equiv_input(Node *a, Node *b) {
return 1;
}
+Node *node_new_zero(Proc *p, Node *n) {
+ Value v = {
+ .type = {
+ .lvl = T_CONST,
+ .t = n->val.type.t,
+ },
+ .i = 0
+ };
+ Node *r = node_new_lit(p, v);
+ return r;
+}
+
+static inline int is_zero(Node *n) {
+ return n->val.type.lvl == T_CONST && (n->val.type.t == T_INT || n->val.type.t == T_BOOL) && !n->val.i;
+}
+
/* needs lexer for error reporting */
Node *node_idealize(Node *n, Proc *p, Lexer *l) {
if (!type_check(n)) {
@@ -454,9 +470,46 @@ Node *node_idealize(Node *n, Proc *p, Lexer *l) {
return node_peephole(r, p, l);
}
+ /* transformations to help encourage constant folding */
+ /* the overall trend is to move them rightwards */
+
+ /* need to check for type compatibility */
+ #define C(a, b) type_eql(&(a)->val.type, &(b)->val.type)
+ if (node_op_communative(n->type)) {
+ /* op(lit, X) -> op(X, lit) */
+ if (T(CAR(n), N_LIT) && !T(CDR(n), N_LIT)) return OP(CDR(n), CAR(n));
+
+ /* op(X, op(Y,Z)) -> op(op(Y,Z), X) */
+ if (!T(CAR(n), n->type) && T(CDR(n), n->type)
+ && C(CAR(n), CDAR(n))) return OP(CDR(n), CAR(n));
+
+ /* op(op(X,Y), op(Z, lit)) -> op(op(X, op(Y, Z)), lit) */
+ if (T(CAR(n), n->type) && T(CDR(n), n->type) && T(CDDR(n), N_LIT)
+ && C(CAAR(n), CDAR(n)) && C(CAR(n), CDR(n))) {
+ return OP(OP(CAAR(n), OP(CADR(n), CDAR(n))), CDDR(n));
+ }
+
+ /* op(op(X, lit), lit) -> op(X, op(lit, lit)) */
+ if (T(CDR(n), N_LIT) && T(CAR(n), n->type)
+ && !T(CAAR(n), N_LIT) && T(CADR(n), N_LIT)
+ && C(CADR(n), CDR(n))) {
+ return OP(CAAR(n), OP(CADR(n), CDR(n)));
+ }
+
+ /* op(op(X, lit), Y) -> op(op(X, Y), lit) */
+ if (T(CAR(n), n->type) && !T(CAAR(n), N_LIT)
+ && T(CADR(n), N_LIT) && !T(CDR(n), N_LIT)
+ && C(CADR(n), CDR(n))) {
+ return OP(OP(CAAR(n), CDR(n)), CADR(n));
+ }
+ }
+
/* optimize based on situations where the input is partly known (e.g.
* one constant input and one not, or identical inputs) */
+#define INT_EQ(n, v) ((n)->val.type.lvl == T_CONST && (n)->val.type.t == T_INT && (n)->val.i == v)
+#define BOOL_EQ(n, v) ((n)->val.type.lvl == T_CONST && (n)->val.type.t == T_BOOL && (n)->val.i == v)
+
switch (n->type) {
case N_OP_NOT:
case N_OP_NEG:
@@ -487,30 +540,24 @@ Node *node_idealize(Node *n, Proc *p, Lexer *l) {
break;
case N_OP_OR:
if (same) return CAR(n);
+ if (is_zero(CDR(n))) return CAR(n);
+ if (BOOL_EQ(CDR(n), 1)) return CDR(n);
if (node_cmp_opposite(CAR(n)->type, CDR(n)->type) && node_equiv_input(CAR(n), CDR(n))) {
return node_new_lit_bool(p, 1);
}
goto zero_no_effect;
case N_OP_AND:
if (same) return CAR(n);
- if (node_eql_i64(CAR(n), 0)) return node_new_lit_i64(p, 0);
- if (node_eql_i64(CDR(n), 0)) return node_new_lit_i64(p, 0);
+ if (BOOL_EQ(CDR(n), 1)) return CAR(n);
+ if (is_zero(CDR(n))) return node_new_zero(p, CDR(n));
+ if (T(CAR(n), N_OP_NOT) && node_equiv(CAAR(n), CDR(n))) return node_new_zero(p, CDR(n));
+ if (T(CDR(n), N_OP_NOT) && node_equiv(CDAR(n), CAR(n))) return node_new_zero(p, CAR(n));
if (node_cmp_incompat(CAR(n)->type, CDR(n)->type) && node_equiv_input(CAR(n), CDR(n))) {
return node_new_lit_bool(p, 0);
}
- if (CAR(n)->val.type.t == T_INT) {
- if (T(CAR(n), N_OP_NOT) && node_equiv(CAAR(n), CDR(n))) return node_new_lit_i64(p, 0);
- if (T(CDR(n), N_OP_NOT) && node_equiv(CDAR(n), CAR(n))) return node_new_lit_i64(p, 0);
- }
break;
case N_OP_XOR:
- if (same) {
- switch (CAR(n)->val.type.t) {
- case T_INT: return node_new_lit_i64(p, 0); break;
- case T_BOOL: return node_new_lit_bool(p, 0); break;
- default: break;
- }
- }
+ if (same) return node_new_zero(p, CAR(n));
if (node_cmp_opposite(CAR(n)->type, CDR(n)->type) && node_equiv_input(CAR(n), CDR(n))) {
return node_new_lit_bool(p, 1);
}
@@ -519,6 +566,8 @@ zero_no_effect: if (node_eql_i64(CAR(n), 0)) return CDR(n);
break;
case N_CMP_EQL:
if (same) return node_new_lit_bool(p, 1);
+ if (BOOL_EQ(CDR(n), 1)) return CAR(n);
+ if (BOOL_EQ(CDR(n), 0)) return NODE(N_OP_NOT, CAR(n));
break;
case N_CMP_NEQ:
if (same) return node_new_lit_bool(p, 0);
@@ -539,39 +588,7 @@ zero_no_effect: if (node_eql_i64(CAR(n), 0)) return CDR(n);
break;
}
- /* transformations to help encourage constant folding */
- /* the overall trend is to move them rightwards */
- /* need to check for type compatibility */
- #define C(a, b) type_eql(&(a)->val.type, &(b)->val.type)
- if (node_op_communative(n->type)) {
- /* op(lit, X) -> op(X, lit) */
- if (T(CAR(n), N_LIT) && !T(CDR(n), N_LIT)) return OP(CDR(n), CAR(n));
-
- /* op(X, op(Y,Z)) -> op(op(Y,Z), X) */
- if (!T(CAR(n), n->type) && T(CDR(n), n->type)
- && C(CAR(n), CDAR(n))) return OP(CDR(n), CAR(n));
-
- /* op(op(X,Y), op(Z, lit)) -> op(op(X, op(Y, Z)), lit) */
- if (T(CAR(n), n->type) && T(CDR(n), n->type) && T(CDDR(n), N_LIT)
- && C(CAAR(n), CDAR(n)) && C(CAR(n), CDR(n))) {
- return OP(OP(CAAR(n), OP(CADR(n), CDAR(n))), CDDR(n));
- }
-
- /* op(op(X, lit), lit) -> op(X, op(lit, lit)) */
- if (T(CDR(n), N_LIT) && T(CAR(n), n->type)
- && !T(CAAR(n), N_LIT) && T(CADR(n), N_LIT)
- && C(CADR(n), CDR(n))) {
- return OP(CAAR(n), OP(CADR(n), CDR(n)));
- }
-
- /* op(op(X, lit), Y) -> op(op(X, Y), lit) */
- if (T(CAR(n), n->type) && !T(CAAR(n), N_LIT)
- && T(CADR(n), N_LIT) && !T(CDR(n), N_LIT)
- && C(CADR(n), CDR(n))) {
- return OP(OP(CAAR(n), CDR(n)), CADR(n));
- }
- }
return NULL;
}
diff --git a/test.lang b/test.lang
index bda2c90..9e9dd9b 100644
--- a/test.lang
+++ b/test.lang
@@ -8,7 +8,7 @@
// also single-line now
-proc main(a i64, b i64) {
- return (a = a) & (b = a)
+proc main(a i64) {
+ return a xor ~a
// (true = 0) = (a xor b)
}