summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ir.c53
-rw-r--r--ir.h3
-rw-r--r--main.c11
-rw-r--r--peephole.c21
-rw-r--r--test.lang6
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
}