summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWormHeamer2025-08-30 23:20:51 -0400
committerWormHeamer2025-08-30 23:20:51 -0400
commitcbca8b454309122632615f0bcb787bc898503df9 (patch)
tree5b888ba81858df7f45baffe4a760d816cd59cd08
parent6e419a23faf6550c3d3e986796ccf33bdec79c74 (diff)
separate IR graph parts of Proc into a Graph struct
-rw-r--r--ir.c149
-rw-r--r--ir.h94
-rw-r--r--main.c177
-rw-r--r--peephole.c6
-rw-r--r--peephole.h2
-rw-r--r--proc.c113
-rw-r--r--proc.h51
7 files changed, 306 insertions, 286 deletions
diff --git a/ir.c b/ir.c
index e3cb679..12b641b 100644
--- a/ir.c
+++ b/ir.c
@@ -15,12 +15,12 @@ const char *node_type_name(NodeType t) {
return names[t];
}
-void node_die(Node *n, Proc *p) {
+void node_die(Node *n, Graph *p) {
assert(n->refs == 0);
assert(n->op != N_DEAD);
n->op = N_DEAD;
- n->prev_free = p->free_list;
- p->free_list = n;
+ n->prev_free = p->pool->free_list;
+ p->pool->free_list = n;
}
void node_del_out(Node *n, Node *p) {
@@ -49,7 +49,7 @@ void node_del_in(Node *n, Node *p) {
}
}
-void node_kill(Node *n, Proc *p) {
+void node_kill(Node *n, Graph *p) {
if (p->ctrl == n) {
/* probably this is fine */
p->ctrl = CTRL(n);
@@ -59,17 +59,17 @@ void node_kill(Node *n, Proc *p) {
assert(n->refs == 0);
}
-void node_add_out(Proc *p, Node *a, Node *b) {
- ZDA_PUSH(&p->perm, &a->out, b);
+void node_add_out(Graph *p, Node *a, Node *b) {
+ ZDA_PUSH(p->pool->arena, &a->out, b);
if (b) b->refs++;
}
-void node_add_in(Proc *p, Node *a, Node *b) {
- ZDA_PUSH(&p->perm, &a->in, b);
+void node_add_in(Graph *p, Node *a, Node *b) {
+ ZDA_PUSH(p->pool->arena, &a->in, b);
if (b) b->refs++;
}
-void node_set_in(Proc *p, Node *n, int idx, Node *to) {
+void node_set_in(Graph *p, Node *n, int idx, Node *to) {
Node *in = n->in.data[idx];
if (in) in->refs--;
node_add_out(p, to, n);
@@ -78,7 +78,7 @@ void node_set_in(Proc *p, Node *n, int idx, Node *to) {
if (in->out.len < 1) node_kill(in, p);
}
-void node_add(Proc *p, Node *src, Node *dest) {
+void node_add(Graph *p, Node *src, Node *dest) {
if (src) assert(src->op != N_DEAD);
if (dest) assert(dest->op != N_DEAD);
node_add_in(p, dest, src);
@@ -92,7 +92,7 @@ void node_add(Proc *p, Node *src, Node *dest) {
}
}
-void node_remove(Proc *p, Node *src, Node *dest) {
+void node_remove(Graph *p, Node *src, Node *dest) {
assert(dest->op != N_DEAD);
node_del_in(dest, src);
if (dest->refs < 1) node_die(dest, p);
@@ -105,22 +105,22 @@ void node_remove(Proc *p, Node *src, Node *dest) {
static int global_node_count = 0;
-Node *node_new_empty(Proc *p, NodeType t) {
+Node *node_new_empty(Graph *p, NodeType t) {
Node *n;
- if (p->free_list) {
- n = p->free_list;
+ if (p->pool->free_list) {
+ n = p->pool->free_list;
assert(n->op == N_DEAD);
- p->free_list = n->prev_free;
+ p->pool->free_list = n->prev_free;
memset(n, 0, sizeof(Node));
} else {
- n = new(&p->perm, Node);
+ n = new(p->pool->arena, Node);
}
n->op = t;
n->id = global_node_count++;
return n;
}
-Node *node_newv(Proc *p, NodeType t, Node *ctrl, ...) {
+Node *node_newv(Graph *p, NodeType t, Node *ctrl, ...) {
Node *node = node_new_empty(p, t);
va_list ap;
va_start(ap, ctrl);
@@ -134,7 +134,7 @@ Node *node_newv(Proc *p, NodeType t, Node *ctrl, ...) {
return node;
}
-Node *node_dedup_lit(Proc *p, Value v) {
+Node *node_dedup_lit(Graph *p, Value v) {
/* TODO: this is probably real inefficient for large procedure graphs,
* but does it matter? how many nodes are direct children of the start node?
* how many literals even usually occur in a procedure? */
@@ -147,7 +147,7 @@ Node *node_dedup_lit(Proc *p, Value v) {
return NULL;
}
-Node *node_new_lit(Proc *p, Value v) {
+Node *node_new_lit(Graph *p, Value v) {
Node *t = node_dedup_lit(p, v);
if (t) return t;
Node *n = node_new(p, N_LIT, NULL, p->start);
@@ -155,121 +155,14 @@ Node *node_new_lit(Proc *p, Value v) {
return n;
}
-Node *node_new_lit_i64(Proc *p, int64_t i) {
+Node *node_new_lit_i64(Graph *p, int64_t i) {
return node_new_lit(p, (Value) { { .lvl = T_CONST, .t = T_INT }, { .i = i } });
}
-Node *node_new_lit_bool(Proc *p, int b) {
+Node *node_new_lit_bool(Graph *p, int b) {
return node_new_lit(p, (Value) { { .lvl = T_CONST, .t = T_BOOL }, { .i = b } });
}
-/* procedures */
-
-void proc_init(Proc *proc, Str name) {
- memset(proc, 0, sizeof(Proc));
- proc->start = node_new(proc, N_START, NULL);
- proc->start->type = (Type) {
- .lvl = T_BOT,
- .t = T_TUPLE,
- .next = NULL
- };
- proc->stop = node_new_empty(proc, N_STOP);
- proc->ctrl = proc->start;
- proc->keepalive = node_new(proc, N_KEEPALIVE, NULL);
- proc->name = name;
-}
-
-void proc_free(Proc *proc) {
- arena_free(&proc->perm);
- arena_free(&proc->scratch);
-}
-
-/* scope */
-
-NameBinding *scope_find(Scope *scope, Str name) {
- for (ScopeFrame *f = scope->tail; f; f = f->prev) {
- for (NameBinding *b = f->latest; b; b = b->prev) {
- if (str_eql(b->name, name)) {
- return b;
- }
- }
- }
- return NULL;
-}
-
-ScopeFrame *scope_push(Scope *scope, Proc *proc) {
- ScopeFrame *f;
- if (scope->free_scope) {
- f = scope->free_scope;
- *f = (ScopeFrame) { 0 };
- scope->free_scope = f->prev;
- } else {
- f = new(&proc->perm, ScopeFrame);
- }
- f->prev = scope->tail;
- scope->tail = f;
- return f;
-}
-
-ScopeFrame *scope_pop(Scope *scope, Proc *proc) {
- ScopeFrame *f = scope->tail;
- scope->tail = f->prev;
- f->prev = scope->free_scope;
- scope->free_scope = f;
- for (NameBinding *b = f->latest; b; ) {
- NameBinding *p = b->prev;
- b->prev = scope->free_bind;
- scope->free_bind = b;
- node_remove(proc, b->node, proc->keepalive);
- b = p;
- }
- return scope->tail;
-}
-
-/* returns previous value */
-NameBinding *scope_bind(Scope *scope, Str name, Node *value, LexSpan pos, Proc *proc) {
- NameBinding *prev = scope_find(scope, name);
- NameBinding *b;
- if (scope->free_bind) {
- b = scope->free_bind;
- *b = (NameBinding) { 0 };
- scope->free_bind = b->prev;
- } else {
- b = new(&proc->perm, NameBinding);
- }
- b->name = name;
- b->prev = scope->tail->latest;
- scope->tail->latest = b;
- b->node = value;
- b->src_pos = pos;
- node_add(proc, value, proc->keepalive);
- return prev;
-}
-
-NameBinding *scope_update(NameBinding *b, Node *to, Proc *proc) {
- Node *n = b->node;
- node_add(proc, to, proc->keepalive);
- b->node = to;
- node_remove(proc, n, proc->keepalive);
- return b;
-}
-
-/* adds to keepalive so these aren't invalidated */
-void scope_collect(Scope *scope, Proc *proc, ScopeNameList *nl, Arena *arena) {
- for (ScopeFrame *f = scope->tail; f; f = f->prev) {
- for (NameBinding *b = f->latest; b; b = b->prev) {
- node_add(proc, b->node, proc->keepalive);
- ZDA_PUSH(arena, nl, (ScopeName) { b->name, b->node });
- }
- }
-}
-
-void scope_uncollect(Scope *scope, Proc *proc, ScopeNameList *nl) {
- for (int i = 0; i < nl->len; i++) {
- node_remove(proc, nl->data[i].node, proc->keepalive);
- }
-}
-
/* types */
int type_eql(Type *a, Type *b) {
diff --git a/ir.h b/ir.h
index 0e30a06..d640f5a 100644
--- a/ir.h
+++ b/ir.h
@@ -141,98 +141,48 @@ typedef struct Node {
#define T(a,b) ((a)->op == b)
#define T2(a,b,t) ((a)->op == t && (b)->op == t)
-
-
-/* procedure graph */
-
-typedef struct NameBinding {
- struct NameBinding *prev;
- LexSpan src_pos;
- Str name;
- Node *node;
-} NameBinding;
-
-typedef struct ScopeFrame {
- struct ScopeFrame *prev;
- NameBinding *latest;
-} ScopeFrame;
-
-typedef struct {
- ScopeFrame *tail, *free_scope;
- NameBinding *free_bind;
-} Scope;
+/* node graph */
typedef struct {
- Str name;
- Node *node;
-} ScopeName;
-
-typedef DYNARR(ScopeName) ScopeNameList;
-
-/*
- * TODO: move to having
- typedef struct {
- Arena *arena;
- Node *start, *stop, *ctrl, *keepalive;
- Node *free_list;
- } Graph;
- typedef struct {
- Arena arena;
- Str name;
- Graph graph;
- Scope scope;
- } Proc;
- * so that scope handling can be separated from the rest of IR
- */
+ Arena *arena;
+ Node *free_list;
+} NodePool;
typedef struct {
- Arena perm, scratch;
- Str name;
+ /* pointer so that e.g. there can be one pool per worker thread,
+ * instead of one per procedure graph */
+ NodePool *pool;
Node *start, *stop, *ctrl, *keepalive;
- Node *free_list;
- Type ret_type;
- Scope scope;
-} Proc;
+} Graph;
#define NODE_KEEP(p, n, ...)\
do { Node *keep_node = n;\
node_add_out(p, keep_node, p->keepalive); __VA_ARGS__;\
node_del_out(keep_node, p->keepalive); } while(0)
-void node_kill(Node *n, Proc *p);
-void node_die(Node *n, Proc *p);
+void node_kill(Node *n, Graph *p);
+void node_die(Node *n, Graph *p);
void node_del_out(Node *n, Node *p);
void node_del_in(Node *n, Node *p);
-void node_kill(Node *n, Proc *p);
+void node_kill(Node *n, Graph *p);
-void node_add(Proc *p, Node *src, Node *dest);
-void node_add_out(Proc *p, Node *a, Node *b);
-void node_add_in(Proc *p, Node *a, Node *b);
-void node_set_in(Proc *p, Node *n, int idx, Node *to);
+void node_add(Graph *p, Node *src, Node *dest);
+void node_add_out(Graph *p, Node *a, Node *b);
+void node_add_in(Graph *p, Node *a, Node *b);
+void node_set_in(Graph *p, Node *n, int idx, Node *to);
-void node_remove(Proc *p, Node *src, Node *dest);
-Node *node_new_empty(Proc *p, NodeType t);
-Node *node_newv(Proc *p, NodeType t, Node *ctrl, ...);
-Node *node_dedup_lit(Proc *p, Value v);
+void node_remove(Graph *p, Node *src, Node *dest);
+Node *node_new_empty(Graph *p, NodeType t);
+Node *node_newv(Graph *p, NodeType t, Node *ctrl, ...);
+Node *node_dedup_lit(Graph *p, Value v);
-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);
+Node *node_new_lit(Graph *p, Value v);
+Node *node_new_lit_bool(Graph *p, int b);
+Node *node_new_lit_i64(Graph *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);
-void proc_free(Proc *proc);
-
-ScopeFrame *scope_push(Scope *scope, Proc *proc);
-ScopeFrame *scope_pop(Scope *scope, Proc *proc);
-NameBinding *scope_find(Scope *scope, Str name);
-NameBinding *scope_bind(Scope *scope, Str name, Node *value, LexSpan pos, Proc *proc);
-NameBinding *scope_update(NameBinding *b, Node *to, Proc *proc);
-void scope_collect(Scope *scope, Proc *proc, ScopeNameList *nl, Arena *arena);
-void scope_uncollect(Scope *scope, Proc *proc, ScopeNameList *nl);
-
#endif
diff --git a/main.c b/main.c
index 1787245..debb0ae 100644
--- a/main.c
+++ b/main.c
@@ -12,6 +12,7 @@
#include "strio.h"
#include "ir.h"
#include "peephole.h"
+#include "proc.h"
int no_opt = 0;
@@ -41,7 +42,7 @@ Node *parse_expr(Lexer *l, Proc *p, Type *twant);
* graph has been generated.
*/
-Node *ctrl(Proc *p, Node *n) {
+Node *ctrl(Graph *p, Node *n) {
if (!n) {
p->ctrl = node_new_lit(p, (Value) {
.type = { .lvl = T_XCTRL, .t = T_NONE }
@@ -55,18 +56,19 @@ Node *ctrl(Proc *p, Node *n) {
void parse_return(Lexer *l, Proc *p) {
lex_next(l);
Node *n;
+ Graph *g = &p->graph;
if (p->ret_type.t == T_NONE) {
- n = node_new(p, N_RETURN, p->ctrl);
+ n = node_new(g, N_RETURN, g->ctrl);
} else {
Node *e = parse_expr(l, p, &p->ret_type);
- n = node_new(p, N_RETURN, p->ctrl, e);
+ n = node_new(g, N_RETURN, g->ctrl, e);
}
- n = node_peephole(n, p, l);
+ n = node_peephole(n, g, l);
if (n->type.lvl != T_XCTRL) {
- node_add(p, n, p->stop);
+ node_add(g, n, g->stop);
}
- ctrl(p, n);
- ctrl(p, NULL);
+ ctrl(g, n);
+ ctrl(g, NULL);
}
Type parse_type(Lexer *l, Proc *proc) {
@@ -94,6 +96,7 @@ Type parse_type(Lexer *l, Proc *proc) {
}
void parse_let(Lexer *l, Proc *p) {
+ Graph *g = &p->graph;
recurse:
lex_expect(l, TM_IDENT);
Str name = l->ident;
@@ -104,7 +107,7 @@ recurse:
if (l->tok != TOK_EQL) {
t = parse_type(l, p);
if (l->tok != TOK_EQL) {
- rhs = node_new(p, N_UNINIT, p->start);
+ rhs = node_new(g, N_UNINIT, g->start);
rhs->type = t;
}
}
@@ -112,11 +115,12 @@ recurse:
lex_next(l);
rhs = parse_expr(l, p, t.t == T_NONE ? NULL : &t);
}
- NameBinding *b = scope_bind(&p->scope, name, rhs, pos, p);
+ NameBinding *b = scope_bind(&p->scope, name, rhs, pos, g);
if (b) {
lex_error_at(l, pos, LE_WARN, S("shadowing previous declaration"));
lex_error_at(l, b->src_pos, LE_WARN, S("declared here"));
}
+ /* TODO: isn't this just a do while loop */
if (l->tok == TOK_COMMA) goto recurse;
}
@@ -124,17 +128,18 @@ void parse_stmt(Lexer *l, Proc *p);
/* TODO: return node from this! */
void parse_block(Lexer *l, Proc *p, ScopeNameList *nl) {
+ Graph *g = &p->graph;
lex_next(l);
arena_reset(&p->scratch);
- scope_push(&p->scope, p);
+ scope_push(&p->scope);
while (l->tok != TOK_RBRACE) {
lex_expected_not(l, TM_EOF);
parse_stmt(l, p);
}
if (nl) {
- scope_collect(&p->scope, p, nl, &p->scratch);
+ scope_collect(&p->scope, g, nl, &p->scratch);
}
- scope_pop(&p->scope, p);
+ scope_pop(&p->scope, g);
lex_expected(l, TM_RBRACE);
lex_next(l);
}
@@ -158,7 +163,7 @@ void parse_assign(Lexer *l, Proc *p) {
str_fmt(&p->scratch, "possibly uninitialized %S",
type_desc(&e->type, &p->scratch)));
}
- scope_update(b, e, p);
+ scope_update(b, e, &p->graph);
}
/* TODO: Implement a better system for this.
@@ -195,6 +200,7 @@ void parse_assign(Lexer *l, Proc *p) {
*/
void merge_scope(Lexer *l, Proc *p, Node *region, ScopeNameList *before, ScopeNameList *ntrue, ScopeNameList *nfalse) {
+ Graph *g = &p->graph;
for (int i = 0; i < before->len; i++) {
int j, k;
ScopeName *b4 = &before->data[i];
@@ -206,18 +212,18 @@ void merge_scope(Lexer *l, Proc *p, Node *region, ScopeNameList *before, ScopeNa
Node *phi;
if (!no) {
if (yes->node == b4->node) continue;
- phi = node_new(p, N_PHI, region, yes->node, b4->node);
+ phi = node_new(g, N_PHI, region, yes->node, b4->node);
} else if (!yes) {
if (no->node == b4->node) continue;
- phi = node_new(p, N_PHI, region, b4->node, no->node);
+ phi = node_new(g, N_PHI, region, b4->node, no->node);
} else {
if (yes->node == b4->node && no->node == b4->node) continue;
- phi = node_new(p, N_PHI, region, yes->node, no->node);
+ phi = node_new(g, N_PHI, region, yes->node, no->node);
}
- phi = node_peephole(phi, p, l);
+ phi = node_peephole(phi, g, l);
NameBinding *b = scope_find(&p->scope, b4->name);
assert(b);
- scope_update(b, phi, p);
+ scope_update(b, phi, g);
}
}
@@ -242,85 +248,86 @@ void merge_scope(Lexer *l, Proc *p, Node *region, ScopeNameList *before, ScopeNa
*/
void parse_if(Lexer *l, Proc *p) {
+ Graph *g = &p->graph;
lex_next(l);
Node *cond = parse_expr(l, p, &(Type) { .t = T_BOOL });
Node *ctrl_if = NULL, *ctrl_else = NULL;
- Node *if_node = node_new(p, N_IF_ELSE, p->ctrl, cond);
+ Node *if_node = node_new(g, N_IF_ELSE, g->ctrl, cond);
if_node->val = (Value) {
.type = { .lvl = T_TOP, .t = T_TUPLE },
.tuple = { 0 }
};
- ZDA_PUSH(&p->perm, &if_node->val.tuple, (Value) { .type = { .lvl = T_CTRL, .t = T_NONE } });
- ZDA_PUSH(&p->perm, &if_node->val.tuple, (Value) { .type = { .lvl = T_CTRL, .t = T_NONE } });
- if_node = node_peephole(if_node, p, l);
- node_add(p, if_node, p->keepalive);
- Node *if_true = node_new(p, N_PROJ, if_node);
- Node *if_false = node_new(p, N_PROJ, if_node);
+ ZDA_PUSH(g->pool->arena, &if_node->val.tuple, (Value) { .type = { .lvl = T_CTRL, .t = T_NONE } });
+ ZDA_PUSH(g->pool->arena, &if_node->val.tuple, (Value) { .type = { .lvl = T_CTRL, .t = T_NONE } });
+ if_node = node_peephole(if_node, g, l);
+ node_add(g, if_node, g->keepalive);
+ Node *if_true = node_new(g, N_PROJ, if_node);
+ Node *if_false = node_new(g, N_PROJ, if_node);
if_true->val.i = 0;
if_false->val.i = 1;
- if_true = node_peephole(if_true, p, l);
- if_false = node_peephole(if_false, p, l);
- node_remove(p, if_node, p->keepalive);
+ if_true = node_peephole(if_true, g, l);
+ if_false = node_peephole(if_false, g, l);
+ node_remove(g, if_node, g->keepalive);
assert(if_true->in.len > 0);
assert(if_false->in.len > 0);
- node_add(p, if_true, p->keepalive);
- node_add(p, if_false, p->keepalive);
+ node_add(g, if_true, g->keepalive);
+ node_add(g, if_false, g->keepalive);
ScopeNameList scope_before = { 0 }, scope_true = { 0 }, scope_false = { 0 };
- scope_collect(&p->scope, p, &scope_before, &p->scratch);
+ scope_collect(&p->scope, g, &scope_before, &p->scratch);
if (cond->type.lvl == T_CONST) {
if (cond->val.i) if_false->type.lvl = T_XCTRL;
else if_true->type.lvl = T_XCTRL;
}
- ctrl(p, if_true);
+ ctrl(g, if_true);
lex_expected(l, TM_LBRACE);
int pos = l->pos.ofs;
parse_block(l, p, &scope_true);
if_true->src_pos = (LexSpan) { .ofs = pos, .n = l->pos.ofs - pos };
- ctrl_if = p->ctrl;
- node_add(p, ctrl_if, p->keepalive);
+ ctrl_if = g->ctrl;
+ node_add(g, ctrl_if, g->keepalive);
if (l->tok == TOK_ELSE) {
for (int i = 0; i < scope_before.len; i++) {
- scope_update(scope_find(&p->scope, scope_before.data[i].name), scope_before.data[i].node, p);
+ scope_update(scope_find(&p->scope, scope_before.data[i].name), scope_before.data[i].node, g);
}
- ctrl(p, if_false);
+ ctrl(g, if_false);
lex_expect(l, TM_LBRACE);
pos = l->pos.ofs;
parse_block(l, p, &scope_false);
if_false->src_pos = (LexSpan) { .ofs = pos, .n = l->pos.ofs - pos };
- ctrl_else = p->ctrl;
- node_add(p, ctrl_else, p->keepalive);
+ ctrl_else = g->ctrl;
+ node_add(g, ctrl_else, g->keepalive);
}
Node *region;
if (ctrl_else) {
assert(ctrl_if);
assert(ctrl_else);
- region = node_new(p, N_REGION, ctrl_if, ctrl_else);
- node_add_out(p, region, p->keepalive);
- node_remove(p, ctrl_if, p->keepalive);
- node_remove(p, ctrl_else, p->keepalive);
+ region = node_new(g, N_REGION, ctrl_if, ctrl_else);
+ node_add_out(g, region, g->keepalive);
+ node_remove(g, ctrl_if, g->keepalive);
+ node_remove(g, ctrl_else, g->keepalive);
} else {
assert(ctrl_if);
assert(if_false);
- region = node_new(p, N_REGION, ctrl_if, if_false);
- node_add_out(p, region, p->keepalive);
- node_remove(p, ctrl_if, p->keepalive);
+ region = node_new(g, N_REGION, ctrl_if, if_false);
+ node_add_out(g, region, g->keepalive);
+ node_remove(g, ctrl_if, g->keepalive);
assert(if_true->refs > 0);
assert(if_false->refs > 0);
}
- ctrl(p, region);
- node_remove(p, if_true, p->keepalive);
- node_remove(p, if_false, p->keepalive);
- assert(p->ctrl->in.len > 0);
+ ctrl(g, region);
+ node_remove(g, if_true, g->keepalive);
+ node_remove(g, if_false, g->keepalive);
+ assert(g->ctrl->in.len > 0);
assert(region->in.data[0]);
assert(region->in.data[1]);
merge_scope(l, p, region, &scope_before, &scope_true, &scope_false);
- scope_uncollect(&p->scope, p, &scope_true);
- scope_uncollect(&p->scope, p, &scope_false);
- scope_uncollect(&p->scope, p, &scope_before);
- node_del_out(region, p->keepalive);
+ scope_uncollect(&p->scope, g, &scope_true);
+ scope_uncollect(&p->scope, g, &scope_false);
+ scope_uncollect(&p->scope, g, &scope_before);
+ node_del_out(region, g->keepalive);
/* make sure we're not orphaning any phi nodes*/
- if (p->ctrl->out.len < 1) {
- ctrl(p, node_peephole(p->ctrl, p, l));
+ if (g->ctrl->out.len < 1) {
+ ctrl(g, node_peephole(g->ctrl, g, l));
}
}
@@ -350,7 +357,8 @@ void parse_stmt(Lexer *l, Proc *p) {
}
void parse_args_list(Lexer *l, Proc *proc) {
- Node *start = proc->start;
+ Node *start = proc->graph.start;
+ Graph *g = &proc->graph;
int i = 0;
struct {
Str name;
@@ -371,11 +379,11 @@ void parse_args_list(Lexer *l, Proc *proc) {
Value v = (Value) { .type = parse_type(l, proc) };
lex_expected(l, TM_RPAREN | TM_COMMA);
for (int j = 0; j < id; j++) {
- Node *proj = node_new(proc, N_PROJ, proc->start);
+ Node *proj = node_new(g, N_PROJ, start);
proj->type = v.type;
proj->val.i = i++;
ZDA_PUSH(&proc->perm, &start->val.tuple, v);
- scope_bind(&proc->scope, idbuf[j].name, proj, idbuf[j].pos, proc);
+ scope_bind(&proc->scope, idbuf[j].name, proj, idbuf[j].pos, g);
}
id = 0;
}
@@ -393,6 +401,7 @@ Node *find_return(Node *n) {
}
void proc_opt_fwd(Proc *p, Lexer *l, Node *n) {
+ Graph *g = &p->graph;
if (n->walked == 2) return;
n->walked = 2;
switch (n->op) {
@@ -427,7 +436,7 @@ void proc_opt_fwd(Proc *p, Lexer *l, Node *n) {
assert(n->out.data[0]->in.data[0] == n);
Node *new_ctrl = CTRL(CTRL(CTRL(n)));
Node *out = n->out.data[0];
- node_set_in(p, out, 0, new_ctrl);
+ node_set_in(g, out, 0, new_ctrl);
proc_opt_fwd(p, l, new_ctrl);
return;
}
@@ -443,19 +452,20 @@ void proc_opt_fwd(Proc *p, Lexer *l, Node *n) {
}
void proc_opt(Proc *p, Lexer *l) {
- if (p->stop->in.len == 0) {
+ Graph *g = &p->graph;
+ if (g->stop->in.len == 0) {
if (p->ret_type.t != T_NONE) {
lex_error(l, LE_ERROR, str_fmt(&p->scratch, "no return statement in function expecting %S", type_desc(&p->ret_type, &p->scratch)));
}
}
- for (int i = 0; i < p->start->out.len; i++) {
- Node *n = p->start->out.data[i];
+ for (int i = 0; i < g->start->out.len; i++) {
+ Node *n = g->start->out.data[i];
if (n->op == N_LIT && n->out.len < 1) {
- node_kill(n, p);
+ node_kill(n, g);
i--;
}
}
- proc_opt_fwd(p, l, p->start);
+ proc_opt_fwd(p, l, g->start);
}
Proc *parse_proc(Lexer *l, Unit *u) {
@@ -464,7 +474,7 @@ Proc *parse_proc(Lexer *l, Unit *u) {
Proc *proc = &u->procs.data[u->procs.len++];
lex_expect(l, TM_IDENT);
proc_init(proc, l->ident);
- scope_push(&proc->scope, proc);
+ scope_push(&proc->scope);
lex_next(l);
if (l->tok == TOK_LPAREN) {
parse_args_list(l, proc);
@@ -480,22 +490,22 @@ Proc *parse_proc(Lexer *l, Unit *u) {
lex_expected_not(l, TM_EOF);
parse_stmt(l, proc);
}
- scope_pop(&proc->scope, proc);
+ scope_pop(&proc->scope, &proc->graph);
lex_expected(l, TM_RBRACE);
lex_next(l);
proc_opt(proc, l);
return proc;
}
-void uninit_check(Lexer *l, Proc *p, Node *n, LexSpan pos) {
+void uninit_check(Lexer *l, Node *n, LexSpan pos) {
if (node_uninit(n)) {
lex_error_at(l, pos, LE_ERROR,
- str_fmt(&p->scratch, "uninitialized %S",
- type_desc(&n->type, &p->scratch)));
+ str_fmt(&l->arena, "uninitialized %S",
+ type_desc(&n->type, &l->arena)));
} else if (node_maybe_uninit(n)) {
lex_error_at(l, pos, LE_WARN,
- str_fmt(&p->scratch, "possibly uninitialized %S",
- type_desc(&n->type, &p->scratch)));
+ str_fmt(&l->arena, "possibly uninitialized %S",
+ type_desc(&n->type, &l->arena)));
}
}
@@ -503,6 +513,7 @@ Node *parse_term(Lexer *l, Proc *p, Type *twant) {
(void)twant; /* to be used for .ENUM_TYPE and stuff */
Node *node = NULL;
NodeType op_after = N_START;
+ Graph *g = &p->graph;
if (TMASK(l->tok) & (TM_MINUS | TM_PLUS | TM_NOT)) {
Token t = l->tok;
lex_next(l);
@@ -514,7 +525,7 @@ Node *parse_term(Lexer *l, Proc *p, Type *twant) {
default: return node;
}
if (post_op == N_START) return node;
- return node_peephole(node_new(p, post_op, NULL, node), p, l);
+ return node_peephole(node_new(g, post_op, NULL, node), g, l);
}
if (l->tok == TOK_LPAREN) {
lex_next(l);
@@ -530,10 +541,10 @@ Node *parse_term(Lexer *l, Proc *p, Type *twant) {
} else {
lex_error(l, LE_ERROR, S("undeclared identifier"));
}
- uninit_check(l, p, node, l->pos);
+ uninit_check(l, node, l->pos);
lex_next(l);
} else if (TMASK(l->tok) & (TM_TRUE | TM_FALSE)) {
- node = node_new_lit_bool(p, l->tok == TOK_TRUE);
+ node = node_new_lit_bool(g, l->tok == TOK_TRUE);
lex_next(l);
} else {
lex_expected(l, TM_LIT_NUM);
@@ -545,14 +556,14 @@ Node *parse_term(Lexer *l, Proc *p, Type *twant) {
}
val = (val * 10) + (l->ident.s[i] - '0');
}
- node = node_new_lit_i64(p, val);
+ node = node_new_lit_i64(g, val);
node->src_pos = l->pos;
lex_next(l);
}
if (op_after != N_START) {
- node = node_new(p, op_after, NULL, node_peephole(node, p, l));
+ node = node_new(g, op_after, NULL, node_peephole(node, g, l));
}
- return node_peephole(node, p, l);
+ return node_peephole(node, g, l);
}
NodeType tok_to_bin_op(Token t) {
@@ -580,6 +591,7 @@ NodeType tok_to_bin_op(Token t) {
/* TODO: operator precedence would be kinda nice actually, sad to say */
Node *parse_expr(Lexer *l, Proc *p, Type *twant) {
LexSpan pos = l->pos;
+ Graph *g = &p->graph;
Node *lhs = parse_term(l, p, twant);
NodeType nt = tok_to_bin_op(l->tok);;
if (lhs->refs <= 0) lex_error(l, LE_ERROR, S("dead lhs"));
@@ -589,10 +601,10 @@ Node *parse_expr(Lexer *l, Proc *p, Type *twant) {
/* necessary because if lhs is a deduplicated literal, it may be an input to rhs
* and therefore culled by peephole optimizations */
Node *rhs;
- NODE_KEEP(p, lhs, {
+ NODE_KEEP(g, lhs, {
rhs = parse_expr(l, p, &lhs->type);
});
- lhs = node_peephole(node_new(p, nt, NULL, lhs, rhs), p, l);
+ lhs = node_peephole(node_new(g, nt, NULL, lhs, rhs), g, l);
}
lhs->src_pos = (LexSpan) { pos.ofs, l->pos.ofs - pos.ofs };
if (twant) type_expected(twant, lhs, l);
@@ -689,10 +701,11 @@ void node_print(Node *n, Proc *p) {
}
void proc_print(Proc *p) {
- if (p->start) {
+ Graph *g = &p->graph;
+ if (g->start) {
Str d = type_desc(&p->ret_type, &p->scratch);
- printf("\t\"%.*s %.*s\" -> %d\n", (int)p->name.n, p->name.s, (int)d.n, d.s, p->start->id);
- node_print(p->start, p);
+ printf("\t\"%.*s %.*s\" -> %d\n", (int)p->name.n, p->name.s, (int)d.n, d.s, g->start->id);
+ node_print(g->start, p);
if (no_opt) {
for (NameBinding *b = p->scope.free_bind; b; b = b->prev) {
uint64_t id = (uintptr_t)b->node;
diff --git a/peephole.c b/peephole.c
index b30a052..71acd77 100644
--- a/peephole.c
+++ b/peephole.c
@@ -240,7 +240,7 @@ static int node_equiv_input(Node *a, Node *b) {
return 1;
}
-Node *node_new_zero(Proc *p, Node *n) {
+Node *node_new_zero(Graph *p, Node *n) {
Value v = {
.type = {
.lvl = T_CONST,
@@ -257,7 +257,7 @@ static inline int is_zero(Node *n) {
}
/* needs lexer for error reporting */
-Node *node_idealize(Node *n, Proc *p, Lexer *l) {
+Node *node_idealize(Node *n, Graph *p, Lexer *l) {
type_check(n, l);
/* stuff that needs to happen even if optimizations are disabled */
@@ -613,7 +613,7 @@ zero_no_effect: if (node_eql_i64(CAR(n), 0)) return CDR(n);
return NULL;
}
-Node *node_peephole(Node *n, Proc *p, Lexer *l) {
+Node *node_peephole(Node *n, Graph *p, Lexer *l) {
assert(n->refs > 0);
Node *r = node_idealize(n, p, l);
if (r) {
diff --git a/peephole.h b/peephole.h
index e9a2cab..11c0961 100644
--- a/peephole.h
+++ b/peephole.h
@@ -4,6 +4,6 @@
#include "ir.h"
Value node_compute(Node *n, Lexer *l);
-Node *node_peephole(Node *n, Proc *p, Lexer *l);
+Node *node_peephole(Node *n, Graph *p, Lexer *l);
#endif
diff --git a/proc.c b/proc.c
new file mode 100644
index 0000000..ff1197f
--- /dev/null
+++ b/proc.c
@@ -0,0 +1,113 @@
+#include <string.h>
+#include "proc.h"
+
+/* procedures */
+
+void proc_init(Proc *proc, Str name) {
+ memset(proc, 0, sizeof(Proc));
+ Graph *g = &proc->graph;
+ proc->pool.arena = &proc->perm;
+ proc->scope.arena = &proc->perm;
+ g->pool = &proc->pool;
+ g->start = node_new(g, N_START, NULL);
+ g->start->type = (Type) {
+ .lvl = T_BOT,
+ .t = T_TUPLE,
+ .next = NULL
+ };
+ g->stop = node_new_empty(g, N_STOP);
+ g->ctrl = g->start;
+ g->keepalive = node_new(g, N_KEEPALIVE, NULL);
+ proc->name = name;
+}
+
+void proc_free(Proc *proc) {
+ arena_free(&proc->perm);
+ arena_free(&proc->scratch);
+}
+
+/* scope */
+
+NameBinding *scope_find(Scope *scope, Str name) {
+ for (ScopeFrame *f = scope->tail; f; f = f->prev) {
+ for (NameBinding *b = f->latest; b; b = b->prev) {
+ if (str_eql(b->name, name)) {
+ return b;
+ }
+ }
+ }
+ return NULL;
+}
+
+ScopeFrame *scope_push(Scope *scope) {
+ ScopeFrame *f;
+ if (scope->free_scope) {
+ f = scope->free_scope;
+ *f = (ScopeFrame) { 0 };
+ scope->free_scope = f->prev;
+ } else {
+ f = new(scope->arena, ScopeFrame);
+ }
+ f->prev = scope->tail;
+ scope->tail = f;
+ return f;
+}
+
+ScopeFrame *scope_pop(Scope *scope, Graph *g) {
+ ScopeFrame *f = scope->tail;
+ scope->tail = f->prev;
+ f->prev = scope->free_scope;
+ scope->free_scope = f;
+ for (NameBinding *b = f->latest; b; ) {
+ NameBinding *p = b->prev;
+ b->prev = scope->free_bind;
+ scope->free_bind = b;
+ node_remove(g, b->node, g->keepalive);
+ b = p;
+ }
+ return scope->tail;
+}
+
+/* returns previous value */
+NameBinding *scope_bind(Scope *scope, Str name, Node *value, LexSpan pos, Graph *g) {
+ NameBinding *prev = scope_find(scope, name);
+ NameBinding *b;
+ if (scope->free_bind) {
+ b = scope->free_bind;
+ *b = (NameBinding) { 0 };
+ scope->free_bind = b->prev;
+ } else {
+ b = new(scope->arena, NameBinding);
+ }
+ b->name = name;
+ b->prev = scope->tail->latest;
+ scope->tail->latest = b;
+ b->node = value;
+ b->src_pos = pos;
+ node_add(g, value, g->keepalive);
+ return prev;
+}
+
+NameBinding *scope_update(NameBinding *b, Node *to, Graph *g) {
+ Node *n = b->node;
+ node_add(g, to, g->keepalive);
+ b->node = to;
+ node_remove(g, n, g->keepalive);
+ return b;
+}
+
+/* adds to keepalive so these aren't invalidated */
+void scope_collect(Scope *scope, Graph *g, ScopeNameList *nl, Arena *arena) {
+ for (ScopeFrame *f = scope->tail; f; f = f->prev) {
+ for (NameBinding *b = f->latest; b; b = b->prev) {
+ node_add(g, b->node, g->keepalive);
+ ZDA_PUSH(arena, nl, (ScopeName) { b->name, b->node });
+ }
+ }
+}
+
+void scope_uncollect(Scope *scope, Graph *g, ScopeNameList *nl) {
+ for (int i = 0; i < nl->len; i++) {
+ node_remove(g, nl->data[i].node, g->keepalive);
+ }
+}
diff --git a/proc.h b/proc.h
new file mode 100644
index 0000000..ec3687f
--- /dev/null
+++ b/proc.h
@@ -0,0 +1,51 @@
+#ifndef PROC_H
+#define PROC_H
+
+#include "ir.h"
+
+typedef struct NameBinding {
+ struct NameBinding *prev;
+ LexSpan src_pos;
+ Str name;
+ Node *node;
+} NameBinding;
+
+typedef struct ScopeFrame {
+ struct ScopeFrame *prev;
+ NameBinding *latest;
+} ScopeFrame;
+
+typedef struct {
+ Arena *arena;
+ ScopeFrame *tail, *free_scope;
+ NameBinding *free_bind;
+} Scope;
+
+typedef struct {
+ Str name;
+ Node *node;
+} ScopeName;
+
+typedef DYNARR(ScopeName) ScopeNameList;
+
+typedef struct {
+ Str name;
+ Type ret_type;
+ Arena perm, scratch;
+ NodePool pool;
+ Graph graph;
+ Scope scope;
+} Proc;
+
+void proc_init(Proc *proc, Str name);
+void proc_free(Proc *proc);
+
+ScopeFrame *scope_push(Scope *scope);
+ScopeFrame *scope_pop(Scope *scope, Graph *g);
+NameBinding *scope_find(Scope *scope, Str name);
+NameBinding *scope_bind(Scope *scope, Str name, Node *value, LexSpan pos, Graph *g);
+NameBinding *scope_update(NameBinding *b, Node *to, Graph *g);
+void scope_collect(Scope *scope, Graph *g, ScopeNameList *nl, Arena *arena);
+void scope_uncollect(Scope *scope, Graph *g, ScopeNameList *nl);
+
+#endif