220 lines
6.0 KiB
C
220 lines
6.0 KiB
C
#include"usedef.h"
|
|
|
|
#include"ast.h"
|
|
#include"ntc.h"
|
|
#include<stdlib.h>
|
|
#include<assert.h>
|
|
#include"reporting.h"
|
|
#include"scope.h"
|
|
|
|
static void rd_kill(ReachingDefs *a, ScopeItem *var) {
|
|
for(size_t i = a->defCount; i --> 0;) {
|
|
AST *def = a->defs[i];
|
|
|
|
assert(def->nodeKind == AST_STMT_ASSIGN);
|
|
assert(def->stmtAssign.what->nodeKind == AST_EXPR_VAR);
|
|
assert(def->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR);
|
|
|
|
if(def->stmtAssign.what->exprVar.thing == var) {
|
|
memmove(&a->defs[i], &a->defs[i + 1], sizeof(*a->defs) * (a->defCount - i - 1));
|
|
a->defCount--;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool rd_equal(ReachingDefs *a, ReachingDefs *b) {
|
|
if(a->defCount != b->defCount) {
|
|
return false;
|
|
}
|
|
|
|
for(size_t i = 0; i < a->defCount; i++) {
|
|
if(a->defs[i] != b->defs[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int compar_ptr(const void *a, const void *b) {
|
|
return *(uintptr_t*) a - *(uintptr_t*) b;
|
|
}
|
|
|
|
static bool rd_find(ReachingDefs *dest, union AST *ast) {
|
|
return !!bsearch(&ast, dest->defs, dest->defCount, sizeof(*dest->defs), compar_ptr);
|
|
}
|
|
|
|
static void rd_add(ReachingDefs *dest, union AST *ast) {
|
|
if(rd_find(dest, ast)) {
|
|
return;
|
|
}
|
|
|
|
dest->defs = realloc(dest->defs, sizeof(*dest->defs) * (++dest->defCount));
|
|
dest->defs[dest->defCount - 1] = ast;
|
|
qsort(dest->defs, dest->defCount, sizeof(*dest->defs), compar_ptr);
|
|
}
|
|
|
|
static void rd_union(ReachingDefs *dest, ReachingDefs *src) {
|
|
for(size_t i = 0; i < src->defCount; i++) {
|
|
rd_add(dest, src->defs[i]);
|
|
}
|
|
}
|
|
|
|
static ReachingDefs rd_compute_in(AST *tlc, AST *stmt, AST *stmtPrev) {
|
|
ReachingDefs rd = {};
|
|
|
|
// The previous statement is a predecessor unless it's an unconditional jump statement
|
|
if(stmtPrev && (stmtPrev->nodeKind != AST_STMT_JUMP || stmtPrev->stmtJump.condition)) {
|
|
rd_union(&rd, &stmtPrev->statement.rd);
|
|
}
|
|
|
|
// If this is a label statement, then all jumps to this statement are predecessors
|
|
if(stmt->nodeKind == AST_STMT_LABEL) {
|
|
for(AST *s = tlc->chunk.statementFirst; s; s = s->statement.next) {
|
|
if(s->nodeKind == AST_STMT_JUMP && !strcmp(s->stmtJump.label, stmt->stmtLabel.name)) {
|
|
rd_union(&rd, &s->statement.rd);
|
|
}
|
|
}
|
|
}
|
|
|
|
return rd;
|
|
}
|
|
|
|
static void rd_step(AST *tlc, AST *stmt, AST *stmtPrev) {
|
|
stmt->statement.dirty = false;
|
|
|
|
ReachingDefs rd = rd_compute_in(tlc, stmt, stmtPrev);
|
|
|
|
if(stmt->nodeKind == AST_STMT_ASSIGN && stmt->stmtAssign.what->nodeKind == AST_EXPR_VAR && stmt->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR) {
|
|
rd_kill(&rd, stmt->stmtAssign.what->exprVar.thing);
|
|
rd_add(&rd, stmt);
|
|
}
|
|
|
|
if(!rd_equal(&rd, &stmt->statement.rd)) {
|
|
// Set dirty flag on all successors
|
|
|
|
// The next statement is a successor unless it's an unconditional jump statement
|
|
if(stmt->statement.next && (stmt->nodeKind != AST_STMT_JUMP || stmt->stmtJump.condition)) {
|
|
stmt->statement.next->statement.dirty = true;
|
|
}
|
|
|
|
// If this is a jump statement, the target label is a successor
|
|
if(stmt->nodeKind == AST_STMT_JUMP) {
|
|
AST *label = ast_get_label_by_name(tlc, stmt->stmtJump.label);
|
|
label->statement.dirty = true;
|
|
}
|
|
|
|
stmt->statement.rd = rd;
|
|
}
|
|
}
|
|
|
|
static void usedef_generation_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
|
AST *n = *nptr;
|
|
|
|
if(n->nodeKind == AST_EXPR_VAR) {
|
|
ReachingDefs *rd = &stmt->statement.rd;
|
|
|
|
ScopeItem *si = n->exprVar.thing;
|
|
|
|
for(size_t rdi = 0; rdi < rd->defCount; rdi++) {
|
|
AST *def = rd->defs[rdi];
|
|
|
|
if(def->stmtAssign.what->exprVar.thing == si) {
|
|
UseDef *ud = calloc(1, sizeof(*ud));
|
|
ud->def = def;
|
|
ud->use = n;
|
|
ud->stmt = stmt;
|
|
|
|
if(!si->data.var.usedefFirst) {
|
|
si->data.var.usedefFirst = si->data.var.usedefLast = ud;
|
|
} else {
|
|
si->data.var.usedefLast->next = ud;
|
|
si->data.var.usedefLast = ud;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void ast_usedef_reset(AST *chu) {
|
|
for(size_t i = 0; i < chu->chunk.varCount; i++) {
|
|
ScopeItem *vte = chu->chunk.vars[i];
|
|
|
|
assert(vte->kind == SCOPEITEM_VAR);
|
|
|
|
vte->data.var.usedefFirst = NULL;
|
|
vte->data.var.usedefLast = NULL;
|
|
vte->data.var.liveRangeStart = NULL;
|
|
vte->data.var.liveRangeEnd = NULL;
|
|
}
|
|
|
|
for(AST *s = chu->chunk.statementFirst; s; s = s->statement.next) {
|
|
if(s->nodeKind == AST_STMT_IF || s->nodeKind == AST_STMT_LOOP) {
|
|
stahp(0, 0, "UD-chain generation requires a completely linear IR");
|
|
}
|
|
|
|
s->statement.dirty = true;
|
|
|
|
s->statement.rd.defCount = 0;
|
|
free(s->statement.rd.defs);
|
|
s->statement.rd.defs = NULL;
|
|
}
|
|
|
|
for(size_t rdsteps = 0;; rdsteps++) {
|
|
//fprintf(stderr, "RD step %lu\n", rdsteps);
|
|
|
|
AST *prev = NULL;
|
|
AST *dirty = NULL;
|
|
|
|
// Find at least one dirty statement
|
|
for(AST *s = chu->chunk.statementFirst; s; prev = s, s = s->statement.next) {
|
|
if(s->statement.dirty) {
|
|
dirty = s;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!dirty) {
|
|
// Completed reaching definition computation
|
|
break;
|
|
}
|
|
|
|
rd_step(chu, dirty, prev);
|
|
}
|
|
|
|
generic_visitor(&chu, NULL, NULL, chu, chu, NULL, usedef_generation_visitor, NULL);
|
|
|
|
for(size_t i = 0; i < chu->chunk.varCount; i++) {
|
|
ScopeItem *vte = chu->chunk.vars[i];
|
|
|
|
assert(vte->kind == SCOPEITEM_VAR);
|
|
|
|
assert(!!vte->data.var.usedefFirst == !!vte->data.var.usedefLast);
|
|
|
|
vte->data.var.liveRangeStart = vte->data.var.usedefFirst->stmt;
|
|
vte->data.var.liveRangeEnd = vte->data.var.usedefLast->stmt;
|
|
}
|
|
|
|
// fix liveRangeStart and/or liveRangeEnd depending on goto targets
|
|
for(AST *s = chu->chunk.statementFirst; s; s = s->statement.next) {
|
|
if(s->nodeKind == AST_STMT_JUMP) {
|
|
AST *target = ast_get_label_by_name(chu, s->stmtJump.label);
|
|
|
|
for(size_t sii = 0; sii < chu->chunk.varCount; sii++) {
|
|
ScopeItem *si = chu->chunk.vars[sii];
|
|
|
|
if(ast_stmt_is_after(chu, si->data.var.liveRangeEnd, s) == 0 && ast_stmt_is_after(chu, target, si->data.var.liveRangeEnd) == 0 && ast_stmt_is_after(chu, si->data.var.declaration, target) == 0) {
|
|
|
|
si->data.var.liveRangeEnd = s;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ntc_get_int("pdbg")) {
|
|
char *astdump = ast_dump(chu);
|
|
fprintf(stderr, "### USEDEF GENERATED ###\n%s\n", astdump);
|
|
free(astdump);
|
|
}
|
|
}
|