From 3db2e548d80d0bfa213d0df73833b1b1b4e0a4f7 Mon Sep 17 00:00:00 2001 From: WormHeamer Date: Mon, 4 Aug 2025 04:48:50 -0400 Subject: stuffs --- ir.c | 107 ++++++++++++++++++++++++++++++++++++-------------------------- test.lang | 4 +-- 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) } -- cgit v1.2.3