From 6baa342580d525250f0842015b8f59ad19b7d540 Mon Sep 17 00:00:00 2001 From: WormHeamer Date: Sun, 10 Aug 2025 23:34:23 -0400 Subject: idempotent operation (& and |) peepholes --- peephole.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/peephole.c b/peephole.c index d994356..947ab1a 100644 --- a/peephole.c +++ b/peephole.c @@ -10,6 +10,7 @@ extern int no_opt; #define NM_COMMUNATIVE (NM_OP_ADD | NM_OP_MUL | NM_OP_AND | NM_OP_XOR | NM_OP_OR | NM_CMP_EQL | NM_CMP_NEQ) #define NM_ASSOCIATIVE (NM_OP_ADD | NM_OP_MUL | NM_OP_AND | NM_OP_XOR | NM_OP_OR) #define NM_COMPARISON (NM_CMP_EQL | NM_CMP_NEQ | NM_CMP_LES | NM_CMP_GTR | NM_CMP_LTE | NM_CMP_GTE) +#define NM_IDEMPOTENT (NM_OP_AND | NM_OP_OR) #define C(a, b) type_base_eql(&(a)->type, &(b)->type) #define INT_EQ(n, v) ((n)->type.lvl == T_CONST && (n)->type.t == T_INT && (n)->val.i == v) @@ -201,7 +202,9 @@ static int node_equiv(Node *a, Node *b) { if (a->op != b->op) return 0; if (a->in.len != b->in.len) return 0; if (!value_eql(&a->val, &b->val)) return 0; - if (!node_equiv_input(a, b)) return 0; + for (int i = 1; i < a->in.len; i++) { + if (!node_equiv(IN(a, i), IN(b, i))) return 0; + } return 1; } @@ -219,13 +222,14 @@ static inline int node_known_not_equiv(Node *a, Node *b) { static int node_equiv_input(Node *a, Node *b) { if (a->in.len != b->in.len) return 0; - if (CTRL(a) != CTRL(b)) return 0; + //if (CTRL(a) != CTRL(b)) return 0; /* note that this means the order of inputs isn't guaranteed, so be * careful what you use this procedure for */ if (((NMASK(a->op) | NMASK(b->op)) & NM_COMMUNATIVE) - && node_equiv(CDR(a), CAR(b)) - && node_equiv(CAR(a), CDR(b))) { + && ((node_equiv(CDR(a), CAR(b)) && node_equiv(CAR(a), CDR(b))) + || (node_equiv(CAR(a), CDR(b)) && node_equiv(CDR(a), CAR(b))))) { /* assuming input count is 2 */ + fprintf(stderr, "equiv\n"); return 1; } for (int i = 1; i < a->in.len; i++) { @@ -308,7 +312,6 @@ Node *node_idealize(Node *n, Proc *p, Lexer *l) { /* transformations to help encourage constant folding */ /* the overall trend is to move them rightwards */ - /* need to check for type compatibility */ if (NMASK(n->op) & NM_COMMUNATIVE) { /* op(lit, X) -> op(X, lit) */ if (T(CAR(n), N_LIT) && !T(CDR(n), N_LIT)) return OP(CDR(n), CAR(n)); @@ -360,6 +363,29 @@ Node *node_idealize(Node *n, Proc *p, Lexer *l) { } } + if (NMASK(n->op) & NM_IDEMPOTENT) { + /* op(X, X) -> X */ + if (node_equiv(CAR(n), CDR(n))) return CAR(n); + + /* op(op(X, Y), X | Y) -> op(X, Y) */ + if (T(CAR(n), n->op) && (node_equiv(CDR(n), CAAR(n)) || node_equiv(CDR(n), CADR(n)))) { + return CAR(n); + } + + /* op(op(X, Y), op(X, Y)) -> op(X, Y) */ + if (T(CAR(n), n->op) && T(CDR(n), n->op) && node_equiv_input(CAR(n), CDR(n))) { + return CAR(n); + } + + /* op(phi(C, A, B), op(A, B)) -> op(A, B) */ + if (T(CAR(n), N_PHI) && T(CDR(n), n->op) && node_equiv_input(CAR(n), CDR(n))) { + return CDR(n); + } + if (T(CDR(n), N_PHI) && T(CAR(n), n->op) && node_equiv_input(CAR(n), CDR(n))) { + return CAR(n); + } + } + /* optimize based on situations where the input is partly known (e.g. * one constant input and one not, or identical inputs) */ @@ -414,7 +440,6 @@ 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 (CDR(n)->op == node_cmp_opposite(CAR(n)->op) && node_equiv_input(CAR(n), CDR(n))) { @@ -434,7 +459,6 @@ Node *node_idealize(Node *n, Proc *p, Lexer *l) { } goto zero_no_effect; case N_OP_AND: - if (same) return CAR(n); 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)); -- cgit v1.2.3