From c9980711ce42de9cf58db35f41ce1ac42bfea0c7 Mon Sep 17 00:00:00 2001 From: WormHeamer Date: Sun, 10 Aug 2025 04:46:09 -0400 Subject: fix peephole bug (communative(phi(a,b), phi(a,b)) =/= communative(a,b)) --- ir.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- ir.h | 3 +++ main.c | 11 +++++++++-- peephole.c | 21 ++++++++++++++++++--- test.lang | 6 ++++-- 5 files changed, 80 insertions(+), 14 deletions(-) diff --git a/ir.c b/ir.c index 125e882..b0b90f5 100644 --- a/ir.c +++ b/ir.c @@ -4,8 +4,6 @@ #include "ir.h" #include "strio.h" -extern int no_opt; - /* nodes */ const char *node_type_name(NodeType t) { @@ -361,13 +359,54 @@ static int type_ok(Node *n) { } } -void type_check(Node *n, Lexer *l) { +/* TODO: make it so + * func foo(a, b i64) i64 { + * let x i64 + * if a < b { + * return 0 + * } else { + * x := 3 + * } + * return x + * } + * doesn't throw warnings (e.g. don't generate phi nodes if one scope is + * guaranteed to return early) + */ + +int node_uninit(Node *n) { + return n->op == N_UNINIT; +} + +int node_maybe_uninit(Node *n) { + if (node_uninit(n)) return 1; for (int i = 0; i < n->in.len; i++) { - if (IN(n,i) && IN(n,i)->op == N_UNINIT) { - lex_error_at(l, n->src_pos, LE_ERROR, - str_fmt(&l->arena, "attempt to use uninitialized %S value", - type_desc(&IN(n,i)->type, &l->arena))); + if (IN(n,i) && node_maybe_uninit(IN(n,i))) { + return 1; } } + return 0; +} + +void uninit_check(Node *n, Lexer *l) { + if (NMASK(n->op) & ~NM_PHI) { + for (int i = 0; i < n->in.len; i++) { + Node *o = IN(n, i); + if (!o) continue; + if (node_uninit(o)) { + fprintf(stderr, "%s\n", node_type_name(n->op)); + lex_error_at(l, o->src_pos, LE_WARN, + str_fmt(&l->arena, "uninitialized %S", + type_desc(&IN(n,i)->type, &l->arena))); + } else if (node_maybe_uninit(o)) { + lex_error_at(l, o->src_pos, LE_WARN, + str_fmt(&l->arena, "possibly uninitialized %S", + type_desc(&o->type, &l->arena))); + } + } + } +} + +void type_check(Node *n, Lexer *l) { + uninit_check(n, l); if (!type_ok(n)) type_err(n, l); } diff --git a/ir.h b/ir.h index 0ae71c8..8923607 100644 --- a/ir.h +++ b/ir.h @@ -203,6 +203,9 @@ Node *node_new_lit(Proc *p, Value v); Node *node_new_lit_bool(Proc *p, int b); Node *node_new_lit_i64(Proc *p, int64_t i); +int node_uninit(Node *n); +int node_maybe_uninit(Node *n); + #define node_new(...) node_newv(__VA_ARGS__, NULL) void proc_init(Proc *proc, Str name); diff --git a/main.c b/main.c index ae19e7a..fa00bad 100644 --- a/main.c +++ b/main.c @@ -161,9 +161,13 @@ void parse_assign(Lexer *l, Proc *p) { type_desc(&e->type, &p->arena), type_desc(&b->node->type, &p->arena))); } - if (e->op == N_UNINIT) { + if (node_uninit(e)) { lex_error_at(l, e->src_pos, LE_ERROR, - str_fmt(&p->arena, "assigning from uninitialized %S value", + str_fmt(&p->arena, "uninitialized %S", + type_desc(&e->type, &p->arena))); + } else if (node_maybe_uninit(e)) { + lex_error_at(l, e->src_pos, LE_WARN, + str_fmt(&p->arena, "possibly uninitialized %S", type_desc(&e->type, &p->arena))); } scope_update(b, e, p); @@ -659,6 +663,9 @@ void node_print(Node *n, Proc *p) { } else if (n->op == N_PROJ) { Str d = type_desc(&n->in.data[0]->val.tuple.data[n->val.i].type, &p->arena); printf("\t%d [label=\"%.*s(%ld)\", shape=record]", n->id, (int)d.n, d.s, n->val.i); + } else if (n->op == N_UNINIT) { + Str s = type_desc(&n->type, &p->arena); + printf("\t%d [label=\"uninitialized %.*s\", shape=record]", n->id, (int)s.n, s.s); } else { printf("\t%d [label=\"%s\", shape=record]", n->id, node_type_name(n->op)); } diff --git a/peephole.c b/peephole.c index b8118db..76d1fbd 100644 --- a/peephole.c +++ b/peephole.c @@ -251,6 +251,22 @@ static inline int is_zero(Node *n) { /* needs lexer for error reporting */ Node *node_idealize(Node *n, Proc *p, Lexer *l) { type_check(n, l); + + /* stuff that needs to happen even if optimizations are disabled */ + + /*switch (n->op) { + case N_PHI: + for (int i = 0; i < n->in.len; i++) { + if (IN(n,i) && IN(n,i)->op == N_UNINIT) { + Node *r = node_new(p, N_UNINIT, p->start); + r->type = n->type; + return r; + } + } + default: + break; + }*/ + if (no_opt) return NULL; /* try to compute a literal value */ @@ -302,9 +318,8 @@ Node *node_idealize(Node *n, Proc *p, Lexer *l) { } if (T(CAR(n), N_PHI) && T(CDR(n), N_PHI) && CTRL(CAR(n)) == CTRL(CDR(n)) - && ((node_equiv(CAAR(n), CDAR(n)) && node_equiv(CADR(n), CDDR(n))) - || (node_equiv(CADR(n), CDAR(n)) && node_equiv(CAAR(n), CDDR(n))))) { - return OP(CAAR(n), CDAR(n)); + && (node_equiv(CADR(n), CDAR(n)) && node_equiv(CAAR(n), CDDR(n)))) { + return OP(CAAR(n), CADR(n)); } } diff --git a/test.lang b/test.lang index 2de85c1..d461439 100644 --- a/test.lang +++ b/test.lang @@ -1,9 +1,11 @@ func main(a, b i64) i64 { let x i64, y bool - if a = b { + if a < b { let t = a a := b b := t + } else { + x := 2 } - return a + return (a + b) + x } -- cgit v1.2.3