#include #include "proc.h" #include "peephole.h" /* procedures */ /* the tangle of arenas here will need to be sorted out eventually: currently * we have two arenas for every single procedure, a permanent one lasting the * full length of compilation, and a scratch arena reset after every statement. * so, long-lasting node data and very temporary allocations. * * this works fine when there's just one procedure, but long-term there should * be a couple arenas per _worker thread_, not per procedure. and for this, * there's a third kind of data --- stuff that lasts the length of parsing one * procedure, but no longer; scope information, mainly. * * so in the end we might have like * _Thread_local Arena graph_arena, scratch_arena, parse_arena; */ 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->nestlvl = scope->nestlvl; 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(Scope *scope, NameBinding *b, Node *to, Graph *g) { Node *n = b->node; unsigned nestlvl = scope->nestlvl; for (ScopeChangeList *l = scope->changes; l; l = l->prev) { if (b->nestlvl < nestlvl) { scope_changelist_update(l, b, n, to, g); } nestlvl--; } node_add(g, to, g->keepalive); b->node = to; node_remove(g, n, g->keepalive); return b; } void scope_changelist_update(ScopeChangeList *l, NameBinding *b, Node *from, Node *to, Graph *g) { for (unsigned i = 0; i < l->n; i++) { ScopeChange *chg = XAR_GET(l, i); if (chg->bind == b) { node_add(g, to, g->keepalive); node_remove(g, chg->to, g->keepalive); chg->to = to; return; } } ScopeChange *chg = XAR_PUT(l, l->n++, l->arena); node_add(g, from, g->keepalive); node_add(g, to, g->keepalive); chg->bind = b; chg->from = from; chg->to = to; } void scope_changelist_push(Scope *scope, ScopeChangeList *l, Arena *a) { l->arena = a; l->prev = scope->changes; scope->changes = l; scope->nestlvl++; } void scope_changelist_pop(Scope *scope, Graph *g) { ScopeChangeList *l = scope->changes; scope->changes = l->prev; scope->nestlvl--; for (unsigned i = 0; i < l->n; i++) { ScopeChange *chg = XAR_GET(l, i); scope_update(scope, chg->bind, chg->from, g); } } #include #include /* TODO: implement merge, probably will need scratch arena to build up * a Xar of something like struct { NameBinding *b; Node *y, *n; }. if * no match for the given bind is found in the opposite change list, * it gets the "from" value found in the other. **/ typedef struct { NameBinding *b; Node *y, *n; } MergeChange; void scope_changelist_merge(Scope *scope, Lexer *l, ScopeChangeList *y, ScopeChangeList *n, Node *region, Graph *graph, Arena *scratch) { MergeChange *m = new_arr(scratch, MergeChange, y->n + n->n); unsigned c = 0; for (unsigned i = 0; i < y->n; i++) { ScopeChange *chg = XAR_GET(y, i); m[c].b = chg->bind; m[c].y = chg->to; m[c].n = chg->from; c++; } unsigned yc = c; for (unsigned i = 0; i < n->n; i++) { ScopeChange *chg = XAR_GET(n, i); for (unsigned j = 0; j < yc; j++) { if (m[j].b == chg->bind) { m[j].n = chg->to; goto next; } } m[c].b = chg->bind; m[c].y = chg->from; m[c].n = chg->to; c++; next:; } for (unsigned i = 0; i < c; i++) { Node *phi = node_new(graph, N_PHI, region, m[i].y, m[i].n); phi = node_peephole(phi, graph, l); scope_update(scope, m[i].b, phi, graph); } } void scope_changelist_discard(ScopeChangeList *l, Graph *g) { for (unsigned i = 0; i < l->n; i++) { ScopeChange *chg = XAR_GET(l, i); node_remove(g, chg->from, g->keepalive); node_remove(g, chg->to, g->keepalive); } }