summaryrefslogtreecommitdiff
path: root/peephole.c
diff options
context:
space:
mode:
Diffstat (limited to 'peephole.c')
-rw-r--r--peephole.c38
1 files 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));