summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWormHeamer2025-08-02 03:12:32 -0400
committerWormHeamer2025-08-02 03:12:32 -0400
commit2da04d09fdb20756b59813e18ad2aa81daeea960 (patch)
tree650ef1c459ea839c3200786948965acae891a7b4
parent91fa8591204386b8e471e5fadc9843362fa10d87 (diff)
highly speculative peephole stuff
-rw-r--r--main.c77
1 files changed, 55 insertions, 22 deletions
diff --git a/main.c b/main.c
index 12e43bd..2642fac 100644
--- a/main.c
+++ b/main.c
@@ -217,35 +217,68 @@ Node *node_new_lit_i64(Proc *p, int64_t i) {
return n;
}
+static inline int node_op_communative(NodeType t) {
+ NodeType ops[] = { N_OP_ADD, N_OP_MUL, N_OP_AND, N_OP_XOR, N_OP_OR };
+ for (unsigned i = 0; i < sizeof ops / sizeof *ops; i++) {
+ if (ops[i] == t) return 1;
+ }
+ return 0;
+}
+
/* needs lexer for error reporting */
Node *node_peephole(Node *n, Proc *p, Lexer *l) {
return n;
- for (int i = 0; i < n->in.len; i++) {
- if (n->in.data[i]->type != N_LIT) return n;
- }
+ /*
+ * Is there a method to convey these transformations a little more nicely?
+ *
+ * add(lit, lit) -> lit
+ * add(lit, add(N, lit)) -> add(N, add(lit, lit))
+ *
+ */
+
Node **in = n->in.data;
Node *r = n;
- switch (n->type) {
- case N_OP_NEG: r = node_new_lit_i64(p, -in[0]->lit.i); break;
- case N_OP_NOT: r = node_new_lit_i64(p, ~in[0]->lit.i); break;
- case N_OP_ADD: r = node_new_lit_i64(p, in[0]->lit.i + in[1]->lit.i); break;
- case N_OP_SUB: r = node_new_lit_i64(p, in[0]->lit.i - in[1]->lit.i); break;
- case N_OP_MUL: r = node_new_lit_i64(p, in[0]->lit.i * in[1]->lit.i); break;
- case N_OP_DIV:
- if (in[1]->lit.i == 0) {
- lex_error_at(l, n->src_pos, LE_ERROR, S("Division by zero"));
+
+ int all_lit = 1;
+ for (int i = 0; i < n->in.len; i++) {
+ if (n->in.data[i]->type != N_LIT) all_lit = 0;
+ }
+
+ if (all_lit) {
+ switch (n->type) {
+ case N_OP_NEG: r = node_new_lit_i64(p, -in[0]->lit.i); break;
+ case N_OP_NOT: r = node_new_lit_i64(p, ~in[0]->lit.i); break;
+ case N_OP_ADD: r = node_new_lit_i64(p, in[0]->lit.i + in[1]->lit.i); break;
+ case N_OP_SUB: r = node_new_lit_i64(p, in[0]->lit.i - in[1]->lit.i); break;
+ case N_OP_MUL: r = node_new_lit_i64(p, in[0]->lit.i * in[1]->lit.i); break;
+ case N_OP_DIV:
+ if (in[1]->lit.i == 0) {
+ lex_error_at(l, n->src_pos, LE_ERROR, S("Division by zero"));
+ }
+ r = node_new_lit_i64(p, in[0]->lit.i / in[1]->lit.i);
+ break;
+ case N_OP_AND: r = node_new_lit_i64(p, in[0]->lit.i & in[1]->lit.i); break;
+ case N_OP_OR: r = node_new_lit_i64(p, in[0]->lit.i | in[1]->lit.i); break;
+ case N_OP_XOR: r = node_new_lit_i64(p, in[0]->lit.i ^ in[1]->lit.i); break;
+ default: break;
}
- r = node_new_lit_i64(p, in[0]->lit.i / in[1]->lit.i);
- break;
- case N_OP_AND: r = node_new_lit_i64(p, in[0]->lit.i & in[1]->lit.i); break;
- case N_OP_OR: r = node_new_lit_i64(p, in[0]->lit.i | in[1]->lit.i); break;
- case N_OP_XOR: r = node_new_lit_i64(p, in[0]->lit.i ^ in[1]->lit.i); break;
- default:
- return n;
- break;
+ } else {
+ if (node_op_communative(n->type)
+ && in[0]->type == N_LIT
+ && in[1]->type == n->type
+ && in[1]->in.data[0]->type != N_LIT
+ && in[1]->in.data[1]->type == N_LIT) {
+ /* op(lit, op(X, lit)) -> op(X, op(lit, lit)) */
+ Node *tmp = in[1]->in.data[0];
+ in[1]->in.data[0] = in[0];
+ in[0] = tmp;
+ }
+ }
+
+ if (r != n) {
+ r->src_pos = n->src_pos;
+ if (n->out.len == 0) node_kill(n, p);
}
- r->src_pos = n->src_pos;
- if (n->out.len == 0) node_kill(n, p);
return r;
}