Despaghettify source

This commit is contained in:
Mid 2025-08-15 17:31:05 +03:00
parent 5196026ed1
commit 7f855f3931
23 changed files with 1369 additions and 1317 deletions

1271
src/ast.c

File diff suppressed because it is too large Load Diff

269
src/ast/ast.c Normal file
View File

@ -0,0 +1,269 @@
#include"ast.h"
#include<stdint.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<stdarg.h>
#include"ntc.h"
#include"reporting.h"
#include"utils.h"
#include"x86/arch.h"
const char *AST_KIND_STR[] = { AST_KINDS(GEN_STRI) };
void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, GenericVisitorHandler preHandler, GenericVisitorHandler postHandler) {
if(preHandler) preHandler(nptr, stmt, stmtPrev, chu, tlc, ud);
AST *n = *nptr;
if(n->nodeKind == AST_CHUNK) {
AST *sPrev = NULL;
AST **s = &n->chunk.statementFirst;
while(*s) {
generic_visitor(s, *s, sPrev, n, tlc, ud, preHandler, postHandler);
sPrev = *s;
s = &sPrev->statement.next;
}
} else if(n->nodeKind == AST_STMT_ASSIGN) {
generic_visitor(&n->stmtAssign.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
if(n->stmtAssign.to) {
generic_visitor(&n->stmtAssign.to, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_IF) {
generic_visitor(&n->stmtIf.expression, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
generic_visitor(&n->stmtIf.then, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
if(n->stmtIf.elss) {
generic_visitor(&n->stmtIf.elss, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_LOOP) {
generic_visitor(&n->stmtLoop.body, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_STMT_BREAK) {
} else if(n->nodeKind == AST_STMT_CONTINUE) {
} else if(n->nodeKind == AST_STMT_EXT_ALIGN) {
} else if(n->nodeKind == AST_STMT_DECL) {
if(n->stmtDecl.expression) {
generic_visitor(&n->stmtDecl.expression, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_EXPR) {
generic_visitor(&n->stmtExpr.expr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_STMT_EXT_ORG) {
} else if(n->nodeKind == AST_STMT_EXT_SECTION) {
} else if(n->nodeKind == AST_STMT_RETURN) {
if(n->stmtReturn.val) {
generic_visitor(&n->stmtReturn.val, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_EXPR_BINARY_OP) {
generic_visitor(&n->exprBinOp.operands[0], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
generic_visitor(&n->exprBinOp.operands[1], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_CALL) {
generic_visitor(&n->exprCall.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
for(size_t i = 0; i < n->exprCall.what->expression.type->pointer.of->function.argCount; i++) {
generic_visitor(&n->exprCall.args[i], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_EXPR_CAST) {
generic_visitor(&n->exprCast.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_FUNC) {
generic_visitor(&n->exprFunc.chunk, NULL, NULL, n->exprFunc.chunk, n->exprFunc.chunk, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_UNARY_OP) {
generic_visitor(&n->exprUnOp.operand, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_VAR) {
} else if(n->nodeKind == AST_EXPR_STACK_POINTER) {
} else if(n->nodeKind == AST_EXPR_PRIMITIVE) {
} else if(n->nodeKind == AST_EXPR_STRING_LITERAL) {
} else if(n->nodeKind == AST_EXPR_ARRAY) {
assert(n->expression.type->type == TYPE_TYPE_ARRAY);
assert(n->expression.type->array.length != 0);
for(size_t i = 0; i < n->expression.type->array.length; i++) {
generic_visitor(&n->exprArray.items[i], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_EXPR_EXT_SALLOC) {
} else if(n->nodeKind == AST_EXPR_DOT) {
generic_visitor(&n->exprDot.a, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_EXT_SIZEOF) {
if(n->exprExtSizeOf.ofExpr) {
generic_visitor(&n->exprExtSizeOf.ofExpr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_JUMP) {
if(n->stmtJump.condition) {
generic_visitor(&n->stmtJump.condition, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_LABEL) {
} else {
stahp_node(n, "generic_visitor: unhandled %s", AST_KIND_STR[n->nodeKind]);
}
if(postHandler) postHandler(nptr, stmt, stmtPrev, chu, tlc, ud);
}
int ast_expression_equal(AST *a, AST *b) {
if(a->nodeKind != b->nodeKind) return 0;
if(a->nodeKind == AST_EXPR_PRIMITIVE) {
return a->exprPrim.val == b->exprPrim.val;
} else if(a->nodeKind == AST_EXPR_VAR) {
return a->exprVar.thing == b->exprVar.thing;
} else if(a->nodeKind == AST_EXPR_UNARY_OP) {
return a->exprUnOp.operator == b->exprUnOp.operator && ast_expression_equal(a->exprUnOp.operand, b->exprUnOp.operand);
} else if(a->nodeKind == AST_EXPR_BINARY_OP) {
return a->exprBinOp.operator == b->exprBinOp.operator && ast_expression_equal(a->exprBinOp.operands[0], b->exprBinOp.operands[0]) && ast_expression_equal(a->exprBinOp.operands[1], b->exprBinOp.operands[1]);
} else if(a->nodeKind == AST_EXPR_STACK_POINTER) {
return 1;
} else if(a->nodeKind == AST_EXPR_CAST) {
return ast_expression_equal(a->exprCast.what, b->exprCast.what) && type_equal(a->exprCast.to, b->exprCast.to) && a->exprCast.reinterpretation == b->exprCast.reinterpretation;
} else {
stahp_node(a, "ast_expression_equal: unhandled %s", AST_KIND_STR[a->nodeKind]);
}
}
// This function may return three values: YES (1), NO (0) or UNKNOWN (-1).
// ... Ew
int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) {
const AST *s = chunk->chunk.statementFirst;
while(1) {
if(s && s->nodeKind == AST_STMT_LOOP) {
int i = ast_stmt_is_after(s->stmtLoop.body, s1, s2);
if(i == 1 || (i == 0 && s1 != NULL)) {
return i;
}
}
if(s == s1) {
return 0;
}
if(s == s2) {
return 1;
}
if(!s) break;
if(s->nodeKind == AST_STMT_IF) {
int i = ast_stmt_is_after(s->stmtIf.then, s1, s2);
if(i == 1 || (i == 0 && s1 != NULL)) {
return i;
}
if(s->stmtIf.elss) {
i = ast_stmt_is_after(s->stmtIf.elss, s1, s2);
if(i == 1 || (i == 0 && s1 != NULL)) {
return i;
}
}
}
s = s->statement.next;
}
return -1;
}
AST *ast_get_label_by_name(AST *tlc, const char *name) {
for(AST *s = tlc->chunk.statementFirst; s; s = s->statement.next) {
if(s->nodeKind == AST_STMT_LABEL && !strcmp(s->stmtLabel.name, name)) {
return s;
}
}
stahp(0, 0, "Label %s not found", name);
}
static void *memdup(void *a, size_t len) {
void *r = malloc(len);
memcpy(r, a, len);
return r;
}
AST *ast_deep_copy(AST *src) {
if(src->nodeKind == AST_EXPR_VAR) {
return memdup(src, sizeof(ASTExprVar));
} else if(src->nodeKind == AST_EXPR_PRIMITIVE) {
return memdup(src, sizeof(ASTExprPrimitive));
}
abort();
}
AST *ast_cast_expr(AST *what, Type *to) {
if(what == NULL) {
stahp(0, 0, "NULL what passed to ast_cast_expr");
goto fail;
}
/* Only exists at parse-time, hence not part of type system and is handled separately */
if(what->nodeKind == AST_EXPR_STRING_LITERAL) {
if(to->type == TYPE_TYPE_ARRAY && type_equal(primitive_parse("u8"), to->array.of) && (to->array.length == what->exprStrLit.length || to->array.length == -1)) {
ASTExprArray *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_ARRAY;
ret->items = calloc(what->exprStrLit.length, sizeof(*ret->items));
ret->type = to;
// If this declaration is of an unknown-length array type (eg u8[?]) then update the length
if(to->array.length == -1) {
to->array.length = what->exprStrLit.length;
}
for(int i = 0; i < what->exprStrLit.length; i++) {
uint8_t bajt = what->exprStrLit.data[i];
ASTExprPrimitive *item = calloc(1, sizeof(*item));
item->nodeKind = AST_EXPR_PRIMITIVE;
item->type = to->array.of;
item->val = bajt;
ret->items[i] = (AST*) item;
}
return (AST*) ret;
} else if(to->type == TYPE_TYPE_PRIMITIVE) {
if(to->primitive.width != what->exprStrLit.length * 8) {
stahp_node(what, "Size mismatch between string literal and target type");
}
ASTExprPrimitive *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = to;
memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val));
return (AST*) ret;
} else abort();
}
// Make sure an unparametrized generic int parameter hasn't sneaked its way in
while(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR && what->exprVar.thing->data.cexpr.concrete) {
what = what->exprVar.thing->data.cexpr.concrete;
}
assert(!(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR));
if(type_equal(what->expression.type, to)) return what;
if(!type_is_castable(what->expression.type, to)) {
goto fail;
}
if(what->nodeKind == AST_EXPR_PRIMITIVE && (to->type == TYPE_TYPE_PRIMITIVE || to->type == TYPE_TYPE_POINTER)) {
ASTExprPrimitive *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = to;
if(to->type == TYPE_TYPE_PRIMITIVE) {
ret->val = what->exprPrim.val & ((1UL << to->primitive.width) - 1);
} else {
ret->val = what->exprPrim.val & ((1UL << (8 * type_size(to))) - 1);
}
return (AST*) ret;
} else {
ASTExprCast *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_CAST;
ret->type = to;
ret->what = what;
ret->to = to;
return (AST*) ret;
}
fail:
stahp_node(what, "Cannot cast type %s into %s", type_to_string(what->expression.type), type_to_string(to));
}

View File

@ -370,28 +370,20 @@ int ast_expression_equal(AST*, AST*);
int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2); int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2);
void ast_usedef_reset(AST *chu);
char *ast_dump(AST *tlc);
AST *ast_deep_copy(AST*); AST *ast_deep_copy(AST*);
AST *ast_cast_expr(AST *what, Type *to); AST *ast_cast_expr(AST *what, Type *to);
void ast_spill_to_stack(AST *tlc, ScopeItem *vte);
void ast_typecheck(AST *tlc); void ast_typecheck(AST *tlc);
void ast_grow_stack_frame(AST *tlc, size_t bytes); AST *ast_get_label_by_name(AST *tlc, const char *name);
void ast_commutativity_pass(AST *tlc); #include"dump.h"
#include"stack.h"
void ast_sroa(AST *tlc); #include"desegment.h"
#include"sroa.h"
// Convert segmented derefences like *x into segment move and *x.offset. #include"linearize.h"
// Must be done before ast_sroa. #include"usedef.h"
void ast_segmented_dereference(AST *tlc); #include"commutativity.h"
void ast_linearize(AST *tlc);
#endif #endif

21
src/ast/commutativity.c Normal file
View File

@ -0,0 +1,21 @@
#include"commutativity.h"
#include"ast.h"
static void commutativity_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
AST *n = *nptr;
if(n->nodeKind == AST_EXPR_BINARY_OP) {
if(binop_is_commutative(n->exprBinOp.operator)) {
if(n->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && n->exprBinOp.operands[1]->nodeKind != AST_EXPR_PRIMITIVE) {
AST *tmp = n->exprBinOp.operands[0];
n->exprBinOp.operands[0] = n->exprBinOp.operands[1];
n->exprBinOp.operands[1] = tmp;
}
}
}
}
void ast_commutativity_pass(AST *tlc) {
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, NULL, commutativity_visitor);
}

8
src/ast/commutativity.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
union AST;
// This pass makes sure that integer literals are always operand 1
// (the right operand) in a commutative binary operation,
// simplifying passes further down.
void ast_commutativity_pass(union AST *chu);

117
src/ast/desegment.c Normal file
View File

@ -0,0 +1,117 @@
#include"desegment.h"
#include"ast.h"
#include"ntc.h"
#include"x86/arch.h"
#include"utils.h"
#include<stdlib.h>
static void ast_tlc_add_var(AST *tlc, ScopeItem *si) {
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * ++tlc->chunk.varCount);
tlc->chunk.vars[tlc->chunk.varCount - 1] = si;
}
/* Split away complex expression into a new local variable */
static AST *varify(AST *tlc, AST *chunk, AST **stmtPrev, AST *stmt, AST *e) {
static size_t idx = 0;
ScopeItem *vte = calloc(1, sizeof(*vte));
vte->kind = SCOPEITEM_VAR;
vte->type = e->expression.type;
vte->data.var.name = malp("$varify_%lu", idx++);
ast_tlc_add_var(tlc, vte);
// Alter AST
ASTExprVar *ev[2];
for(int i = 0; i < 2; i++) {
ev[i] = calloc(1, sizeof(ASTExprVar));
ev[i]->nodeKind = AST_EXPR_VAR;
ev[i]->type = e->expression.type;
ev[i]->thing = vte;
}
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
assign->nodeKind = AST_STMT_ASSIGN;
assign->what = (AST*) ev[0];
assign->to = e;
if(*stmtPrev) {
(*stmtPrev)->statement.next = (AST*) assign;
} else {
chunk->chunk.statementFirst = (AST*) assign;
}
assign->next = stmt;
*stmtPrev = (AST*) assign;
// Reset ud-chain
vte->data.var.usedefFirst = NULL;
vte->data.var.usedefLast = NULL;
return (AST*) ev[1];
}
static void ast_segmented_dereference_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
if(tlc != ud) {
return;
}
AST *n = *aptr;
if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_DEREF && type_is_segmented_pointer(n->exprUnOp.operand->expression.type)) {
static size_t idx = 0;
AST *v;
if(n->exprUnOp.operand->nodeKind == AST_EXPR_VAR)
v = n->exprUnOp.operand;
else
v = varify(tlc, chunk, &stmtPrev, stmt, n->exprUnOp.operand);
ScopeItem *si = calloc(1, sizeof(*si));
si->kind = SCOPEITEM_VAR;
si->type = primitive_parse("u16");
si->data.var.preclassed = true;
si->data.var.registerClass = REG_CLASS_DATASEGS;
si->data.var.precolored = true;
si->data.var.color = 0;
si->data.var.name = malp("$segtemp_%lu", idx++);
ast_tlc_add_var(tlc, si);
ASTExprVar *ev = calloc(1, sizeof(*ev));
ev->nodeKind = AST_EXPR_VAR;
ev->type = si->type;
ev->thing = si;
ASTExprDot *edseg = calloc(1, sizeof(*edseg));
edseg->type = n->exprUnOp.operand->expression.type->record.fieldTypes[0];
edseg->nodeKind = AST_EXPR_DOT;
edseg->a = v;
edseg->b = strdup("segment");
ASTStmtAssign *ass = calloc(1, sizeof(*ass));
ass->nodeKind = AST_STMT_ASSIGN;
ass->what = (AST*) ev;
ass->to = (AST*) edseg;
ass->next = (AST*) stmt;
if(stmtPrev)
stmtPrev->statement.next = (AST*) ass;
else
chunk->chunk.statementFirst = (AST*) ass;
stmtPrev = (AST*) ass;
ASTExprDot *ed = calloc(1, sizeof(*ed));
ed->type = n->exprUnOp.operand->expression.type->record.fieldTypes[1];
ed->nodeKind = AST_EXPR_DOT;
ed->a = ast_deep_copy(v);
ed->b = strdup("offset");
n->exprUnOp.operand = (AST*) ed;
}
}
void ast_segmented_dereference(AST *tlc) {
generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, ast_segmented_dereference_visitor, NULL);
}

7
src/ast/desegment.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
union AST;
// Convert segmented derefences like *x into segment move and *x.offset.
// Must be done before ast_sroa.
void ast_segmented_dereference(union AST *tlc);

327
src/ast/dump.c Normal file
View File

@ -0,0 +1,327 @@
#include"dump.h"
#include"ast.h"
#include"types.h"
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include"utils.h"
char *type_to_string(Type *t) {
if(t->type == TYPE_TYPE_PRIMITIVE) {
char ret[16] = {};
int i = 0;
ret[i++] = t->primitive.isFloat ? 'f' : (t->primitive.isUnsigned ? 'u' : 'i');
snprintf(ret + i, sizeof(ret) - i, "%i", t->primitive.width);
return strdup(ret);
} else if(t->type == TYPE_TYPE_POINTER) {
char *c = type_to_string(t->pointer.of);
char *r = malp("%s*", c);
free(c);
return r;
} else if(t->type == TYPE_TYPE_RECORD) {
return malp("%s", t->record.name);
} else if(t->type == TYPE_TYPE_GENERIC) {
return malp("%s", t->generic.paramName);
} else if(t->type == TYPE_TYPE_ARRAY) {
char *of = type_to_string(t->array.of);
char *len = NULL;
if(t->array.lengthIsGeneric) {
len = malp("");
} else {
len = malp("%li", t->array.length);
}
char *r = malp("%s[%s]", of, len);
free(of);
free(len);
return r;
}
return strdup("@unimp");
}
static char *ast_dumpe(AST *tlc, AST *e) {
if(!e) {
return malp("(null)");
}
if(e->nodeKind == AST_EXPR_PRIMITIVE) {
return malp("%i", e->exprPrim.val);
} else if(e->nodeKind == AST_EXPR_VAR) {
ScopeItem *vte = e->exprVar.thing;
if(vte->kind == SCOPEITEM_VAR) {
return strdup(vte->data.var.name);
} else if(vte->kind == SCOPEITEM_SYMBOL) {
return strdup(vte->data.symbol.name);
} else abort();
} else if(e->nodeKind == AST_EXPR_UNARY_OP) {
const char *op = NULL;
switch(e->exprUnOp.operator) {
case UNOP_REF:
op = "&";
break;
case UNOP_DEREF:
op = "*";
break;
case UNOP_BITWISE_NOT:
op = "~";
break;
case UNOP_NEGATE:
op = "-";
break;
case UNOP_NOT:
op = "!";
break;
default:
abort();
}
char *c = ast_dumpe(tlc, e->exprUnOp.operand);
char *r = malp("%s%s", op, c);
free(c);
return r;
} else if(e->nodeKind == AST_EXPR_BINARY_OP) {
char *a = ast_dumpe(tlc, e->exprBinOp.operands[0]);
char *b = ast_dumpe(tlc, e->exprBinOp.operands[1]);
const char *op;
switch(e->exprBinOp.operator) {
case BINOP_ADD:
op = "+";
break;
case BINOP_SUB:
op = "-";
break;
case BINOP_MUL:
op = "*";
break;
case BINOP_DIV:
op = "/";
break;
case BINOP_BITWISE_AND:
op = "&";
break;
case BINOP_BITWISE_OR:
op = "|";
break;
case BINOP_BITWISE_XOR:
op = "^";
break;
case BINOP_EQUAL:
op = "==";
break;
case BINOP_NEQUAL:
op = "!=";
break;
case BINOP_LESS:
op = "<";
break;
case BINOP_GREATER:
op = ">";
break;
case BINOP_LEQUAL:
op = "<=";
break;
case BINOP_GEQUAL:
op = ">=";
break;
case BINOP_MULHI:
op = "*^";
break;
default:
abort();
}
char *r = malp("(%s %s %s)", a, op, b);
free(a);
free(b);
return r;
} else if(e->nodeKind == AST_EXPR_STACK_POINTER) {
return malp("@stack");
} else if(e->nodeKind == AST_EXPR_FUNC) {
char *out = NULL;
if(type_is_generic(e->expression.type)) {
out = malp("(generic)");
return out;
}
{
char *rettype = type_to_string(e->expression.type->function.ret);
out = malp("%s(", rettype);
free(rettype);
}
for(int i = 0; i < e->expression.type->function.argCount; i++) {
char *argtype = type_to_string(e->expression.type->function.args[i]);
char *out2 = malp(i == e->expression.type->function.argCount - 1 ? "%s%s" : "%s%s, ", out, argtype);
free(out);
free(argtype);
out = out2;
}
{
char *choonk = ast_dumpc(tlc, e->exprFunc.chunk);
char *out2 = malp("%s) {\n%s}", out, choonk);
free(out);
free(choonk);
out = out2;
}
return out;
} else if(e->nodeKind == AST_EXPR_CALL) {
char *w = ast_dumpe(tlc, e->exprCall.what);
char *out = malp("%s(", w);
free(w);
size_t argCount = e->exprCall.what->expression.type->pointer.of->function.argCount;
for(size_t i = 0; i < argCount; i++) {
char *a = ast_dumpe(tlc, e->exprCall.args[i]);
char *out2 = malp(i == argCount - 1 ? "%s%s)" : "%s%s, ", out, a);
free(a);
free(out);
out = out2;
}
return out;
} else if(e->nodeKind == AST_EXPR_EXT_SALLOC) {
char *w = type_to_string(e->exprExtSalloc.size);
char *out = malp("@salloc(%s)", w);
free(w);
return out;
} else if(e->nodeKind == AST_EXPR_CAST) {
char *a = ast_dumpe(tlc, e->exprCast.what);
char *b = type_to_string(e->exprCast.to);
char *out = malp("(%s as %s)", a, b);
free(a);
free(b);
return out;
} else if(e->nodeKind == AST_EXPR_DOT) {
char *a = ast_dumpe(tlc, e->exprDot.a);
char *out = malp(e->nodeKind == AST_EXPR_BINARY_OP ? "(%s).%s" : "%s.%s", a, e->exprDot.b);
free(a);
return out;
}
return malp("@unimp:%s", AST_KIND_STR[e->nodeKind]);
}
static char *ast_dumps(AST *tlc, AST *s) {
if(s->nodeKind == AST_STMT_DECL) {
ScopeItem *vte = s->stmtDecl.thing;
if(vte->kind == SCOPEITEM_SYMBOL) {
char *t = type_to_string(vte->type);
char *e = s->stmtDecl.expression ? ast_dumpe(tlc, s->stmtDecl.expression) : strdup("");
char *r = malp("%s%s %s: %s;", vte->data.symbol.isExternal ? "external " : "", t, vte->data.symbol.name, e);
free(t);
free(e);
return r;
}
} else if(s->nodeKind == AST_STMT_ASSIGN) {
if(s->stmtAssign.to) {
char *a = ast_dumpe(tlc, s->stmtAssign.what);
char *b = ast_dumpe(tlc, s->stmtAssign.to);
char *r = malp("%s = %s;", a, b);
free(a);
free(b);
return r;
} else {
char *a = ast_dumpe(tlc, s->stmtAssign.what);
char *r = malp("%s = ; /* fake def */", a);
free(a);
return r;
}
} else if(s->nodeKind == AST_STMT_JUMP) {
char *a = ast_dumpe(tlc, s->stmtJump.condition);
char *r = malp("jump %s if %s;", s->stmtJump.label, a);
free(a);
return r;
} else if(s->nodeKind == AST_STMT_LABEL) {
return malp("@label %s;", s->stmtLabel.name);
} else if(s->nodeKind == AST_STMT_LOOP) {
char *inner = ast_dumpc(tlc, s->stmtLoop.body);
char *c = malp("loop {\n%s}", inner);
free(inner);
return c;
} else if(s->nodeKind == AST_STMT_IF) {
char *cond = ast_dumpe(tlc, s->stmtIf.expression);
char *inner = ast_dumpc(tlc, s->stmtIf.then);
char *elss = s->stmtIf.elss ? ast_dumpc(tlc, s->stmtIf.elss) : NULL;
char *c;
if(elss) {
c = malp("if(%s) {\n%s} else {\n%s}", cond, inner, elss);
free(elss);
} else {
c = malp("if(%s) {\n%s}", cond, inner);
}
free(cond);
free(inner);
return c;
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_VAR) {
const char *name;
if(s->stmtExpr.expr->exprVar.thing->kind == SCOPEITEM_VAR) {
name = s->stmtExpr.expr->exprVar.thing->data.var.name;
} else {
name = s->stmtExpr.expr->exprVar.thing->data.symbol.name;
}
return malp("%s; /* loop guard */", name);
} else if(s->nodeKind == AST_STMT_EXPR) {
return ast_dumpe(tlc, s->stmtExpr.expr);
} else if(s->nodeKind == AST_STMT_RETURN) {
if(s->stmtReturn.val) {
char *e = ast_dumpe(tlc, s->stmtReturn.val);
char *c = malp("return %s;", e);
free(e);
return c;
} else {
return malp("return;");
}
}
return malp("@unimp:%s;", AST_KIND_STR[s->nodeKind]);
}
static char *stmt_live_range_dbgs(AST *tlc, AST *stmt) {
char *ret = malp("");
for(size_t v = 0; v < tlc->chunk.varCount; v++) {
ScopeItem *si = tlc->chunk.vars[v];
if(si->data.var.liveRangeStart == stmt) {
char *ret2 = malp("%s (%s start)", ret, si->data.var.name);
free(ret);
ret = ret2;
}
if(si->data.var.liveRangeEnd == stmt) {
char *ret2 = malp("%s (%s end)", ret, si->data.var.name);
free(ret);
ret = ret2;
}
}
return ret;
}
char *ast_dumpc(AST *tlc, AST *chu) {
AST *stmt = chu->chunk.statementFirst;
char *ret = malp("");
while(stmt) {
char *new = ast_dumps(tlc, stmt);
char *users = stmt_live_range_dbgs(tlc, stmt);
char *ret2 = malp("%s%s%s\n", ret, new, users);
free(ret);
free(new);
free(users);
ret = ret2;
stmt = stmt->statement.next;
}
return ret;
}
char *ast_dump(AST *tlc) {
return ast_dumpc(tlc, tlc);
}

5
src/ast/dump.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
union AST;
char *ast_dump(union AST *chu);
char *ast_dumpc(union AST *tlc, union AST *chu);

161
src/ast/linearize.c Normal file
View File

@ -0,0 +1,161 @@
#include"linearize.h"
#include"ast.h"
#include"ntc.h"
#include"utils.h"
#include<stdlib.h>
static void ast_patch_in_chunk(AST *chunkOuter, AST *stmtBefore, AST *chunkInner, AST *stmtAfter) {
if(chunkInner->chunk.statementFirst) {
stmtBefore->statement.next = chunkInner->chunk.statementFirst;
for(AST *z = chunkInner->chunk.statementFirst; z; z = z->statement.next) {
if(!z->statement.next) {
z->statement.next = stmtAfter;
break;
}
}
} else {
stmtBefore->statement.next = stmtAfter;
}
}
#define LOOPSTACKSIZE 64
struct LinearizeState {
size_t currentDepth;
size_t loopStackStart[LOOPSTACKSIZE];
size_t loopStackEnd[LOOPSTACKSIZE];
AST *loopAfters[LOOPSTACKSIZE];
};
static void ast_linearize_visitor_pre(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
static size_t nextLabelIdx = 0;
struct LinearizeState *state = ud;
AST *a = *aptr;
if(a->nodeKind == AST_STMT_IF) {
if(a->stmtIf.elss == NULL) {
ASTExprUnaryOp *notcond = calloc(1, sizeof(*notcond));
notcond->nodeKind = AST_EXPR_UNARY_OP;
notcond->operator = UNOP_NOT;
notcond->operand = a->stmtIf.expression;
notcond->type = a->stmtIf.expression->expression.type;
ASTStmtJump *jump = calloc(1, sizeof(ASTStmtJump));
jump->nodeKind = AST_STMT_JUMP;
jump->condition = (AST*) notcond;
jump->label = malp("$Lin%lu", nextLabelIdx++);
ASTStmtLabel *label = calloc(1, sizeof(ASTStmtLabel));
label->nodeKind = AST_STMT_LABEL;
label->name = strdup(jump->label);
if(stmtPrev) {
stmtPrev->statement.next = (AST*) jump;
} else {
chunk->chunk.statementFirst = (AST*) jump;
}
ast_patch_in_chunk(chunk, (AST*) jump, a->stmtIf.then, (AST*) label);
label->next = a->statement.next;
} else {
ASTExprUnaryOp *notcond = calloc(1, sizeof(*notcond));
notcond->nodeKind = AST_EXPR_UNARY_OP;
notcond->operator = UNOP_NOT;
notcond->operand = a->stmtIf.expression;
notcond->type = a->stmtIf.expression->expression.type;
ASTStmtJump *jump2Else = calloc(1, sizeof(ASTStmtJump));
jump2Else->nodeKind = AST_STMT_JUMP;
jump2Else->condition = (AST*) notcond;
jump2Else->label = malp("$Lin%lu", nextLabelIdx++);
ASTStmtJump *jump2End = calloc(1, sizeof(ASTStmtJump));
jump2End->nodeKind = AST_STMT_JUMP;
jump2End->label = malp("$Lin%lu", nextLabelIdx++);
ASTStmtLabel *labelElse = calloc(1, sizeof(ASTStmtLabel));
labelElse->nodeKind = AST_STMT_LABEL;
labelElse->name = strdup(jump2Else->label);
ASTStmtLabel *labelEnd = calloc(1, sizeof(ASTStmtLabel));
labelEnd->nodeKind = AST_STMT_LABEL;
labelEnd->name = strdup(jump2End->label);
if(stmtPrev) {
stmtPrev->statement.next = (AST*) jump2Else;
} else {
chunk->chunk.statementFirst = (AST*) jump2Else;
}
ast_patch_in_chunk(chunk, (AST*) jump2Else, a->stmtIf.then, (AST*) jump2End);
jump2End->next = (AST*) labelElse;
ast_patch_in_chunk(chunk, (AST*) labelElse, a->stmtIf.elss, (AST*) labelEnd);
labelEnd->next = a->statement.next;
}
} else if(a->nodeKind == AST_STMT_LOOP) {
size_t startIdx = nextLabelIdx++;
size_t endIdx = nextLabelIdx++;
ASTStmtJump *jump = calloc(1, sizeof(ASTStmtJump));
jump->nodeKind = AST_STMT_JUMP;
jump->condition = NULL;
jump->label = malp("$Lin%lu", startIdx);
ASTStmtLabel *startLabel = calloc(1, sizeof(ASTStmtLabel));
startLabel->nodeKind = AST_STMT_LABEL;
startLabel->name = strdup(jump->label);
ASTStmtLabel *endLabel = calloc(1, sizeof(ASTStmtLabel));
endLabel->nodeKind = AST_STMT_LABEL;
endLabel->name = malp("$Lin%lu", endIdx);
if(stmtPrev) {
stmtPrev->statement.next = (AST*) startLabel;
} else {
chunk->chunk.statementFirst = (AST*) startLabel;
}
ast_patch_in_chunk(chunk, (AST*) startLabel, a->stmtLoop.body, (AST*) jump);
jump->next = (AST*) endLabel;
endLabel->next = a->statement.next;
state->currentDepth++;
state->loopStackStart[state->currentDepth - 1] = startIdx;
state->loopStackEnd[state->currentDepth - 1] = endIdx;
state->loopAfters[state->currentDepth - 1] = (AST*) endLabel;
} else if(a->nodeKind == AST_STMT_BREAK) {
ASTStmtJump *jump = calloc(1, sizeof(ASTStmtJump));
jump->nodeKind = AST_STMT_JUMP;
jump->condition = NULL;
jump->label = malp("$Lin%lu", state->loopStackEnd[state->currentDepth - 1]);
jump->next = a->statement.next;
*aptr = (AST*) jump;
} else if(a->nodeKind == AST_STMT_CONTINUE) {
ASTStmtJump *jump = calloc(1, sizeof(ASTStmtJump));
jump->nodeKind = AST_STMT_JUMP;
jump->condition = NULL;
jump->label = malp("$Lin%lu", state->loopStackStart[state->currentDepth - 1]);
jump->next = a->statement.next;
*aptr = (AST*) jump;
}
}
static void ast_linearize_visitor_post(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
struct LinearizeState *state = ud;
AST *a = *aptr;
if(state->currentDepth && state->loopAfters[state->currentDepth - 1] == a) {
state->currentDepth--;
}
}
void ast_linearize(AST *tlc) {
struct LinearizeState state = {};
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, ast_linearize_visitor_pre, ast_linearize_visitor_post);
}

4
src/ast/linearize.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
union AST;
void ast_linearize(union AST *tlc);

104
src/ast/sroa.c Normal file
View File

@ -0,0 +1,104 @@
#include"sroa.h"
#include"ast.h"
#include"ntc.h"
#include"utils.h"
#include<stdlib.h>
#include<assert.h>
static bool is_sroa_candidate(ScopeItem *si) {
return si->type->type == TYPE_TYPE_RECORD && type_size(si->type) <= ntc_get_int_default("sroa-threshold", 32);
}
struct IsScopeItemReferenced {
bool yes;
ScopeItem *si;
};
static void is_scopeitem_referenced_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
struct IsScopeItemReferenced *state = ud;
AST *n = *aptr;
if(n->nodeKind == AST_EXPR_UNARY_OP) {
if(n->exprUnOp.operand->nodeKind == AST_EXPR_VAR && n->exprUnOp.operator == UNOP_REF && n->exprUnOp.operand->exprVar.thing == state->si) {
state->yes = true;
}
}
}
static bool is_scopeitem_referenced(AST *tlc, ScopeItem *si) {
struct IsScopeItemReferenced state = {.si = si};
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, NULL, is_scopeitem_referenced_visitor);
return state.yes;
}
struct DecomposeAutomaticRecordState {
AST *tlc;
ScopeItem *target;
ScopeItem **replacements;
};
static void ast_decompose_automatic_record_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
AST *n = *aptr;
struct DecomposeAutomaticRecordState *state = ud;
if(state->tlc != tlc) return;
if(n->nodeKind == AST_EXPR_DOT && n->exprDot.a->nodeKind == AST_EXPR_VAR && n->exprDot.a->exprVar.thing == state->target) {
size_t idx;
for(idx = 0; strcmp(state->target->type->record.fieldNames[idx], n->exprDot.b); idx++);
AST *ev = calloc(1, sizeof(ASTExprVar));
ev->nodeKind = AST_EXPR_VAR;
ev->expression.type = state->target->type->record.fieldTypes[idx];
ev->exprVar.thing = state->replacements[idx];
*aptr = (AST*) ev;
}
}
static void ast_decompose_automatic_record(AST *tlc, ScopeItem *target) {
assert(target->kind == SCOPEITEM_VAR);
assert(target->type->type == TYPE_TYPE_RECORD);
struct DecomposeAutomaticRecordState state = {
.tlc = tlc,
.target = target,
.replacements = calloc(target->type->record.fieldCount, sizeof(ScopeItem)),
};
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (tlc->chunk.varCount + target->type->record.fieldCount));
for(size_t f = 0; f < target->type->record.fieldCount; f++) {
ScopeItem *si = calloc(1, sizeof(*si));
si->kind = SCOPEITEM_VAR;
si->type = target->type->record.fieldTypes[f];
si->data.var.name = malp("%s_sroa_%s", target->data.var.name, target->type->record.fieldNames[f]);
state.replacements[f] = si;
tlc->chunk.vars[tlc->chunk.varCount++] = si;
}
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, ast_decompose_automatic_record_visitor, NULL);
free(state.replacements);
}
void ast_sroa(AST *tlc) {
for(int i = 0; i < tlc->chunk.varCount; i++) {
ScopeItem *si = tlc->chunk.vars[i];
if(!is_sroa_candidate(si)) {
continue;
}
if(is_scopeitem_referenced(tlc, si)) {
continue;
}
ast_decompose_automatic_record(tlc, si);
memmove(tlc->chunk.vars + i, tlc->chunk.vars + i + 1, sizeof(*tlc->chunk.vars) * (tlc->chunk.varCount - i - 1));
tlc->chunk.varCount--;
/* Restart */
i = -1;
}
}

4
src/ast/sroa.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
union AST;
void ast_sroa(union AST *tlc);

101
src/ast/stack.c Normal file
View File

@ -0,0 +1,101 @@
#include"stack.h"
#include"ast.h"
#include"ntc.h"
#include"scope.h"
#include<assert.h>
#include<stdlib.h>
struct Spill2StackState {
AST *targetTLC;
ScopeItem *target; // can be NULL
size_t stackGrowth;
};
static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
struct Spill2StackState *this = ud;
if(tlc != this->targetTLC) {
// Don't do anything.
return;
}
AST *a = *aptr;
if(a == tlc) {
a->chunk.stackReservation += this->stackGrowth;
} else if(a->nodeKind == AST_EXPR_VAR) {
if(a->exprVar.thing == this->target) {
// DO THE SPILL
ASTExprStackPointer *rsp = calloc(1, sizeof(*rsp));
rsp->nodeKind = AST_EXPR_STACK_POINTER;
rsp->type = primitive_parse("u32");
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
offset->nodeKind = AST_EXPR_PRIMITIVE;
offset->type = rsp->type;
offset->val = -this->stackGrowth; // This will be affected by the other part of this pass, so we must reverse
offset->stackGrowth = true;
ASTExprBinaryOp *bop = calloc(1, sizeof(*bop));
bop->nodeKind = AST_EXPR_BINARY_OP;
bop->type = rsp->type;
bop->operator = BINOP_ADD;
bop->operands[0] = (AST*) rsp;
bop->operands[1] = (AST*) offset;
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
deref->nodeKind = AST_EXPR_UNARY_OP;
deref->type = a->expression.type;
deref->operator = UNOP_DEREF;
deref->operand = (AST*) bop;
*aptr = (AST*) deref;
}
} else if(a->nodeKind == AST_EXPR_PRIMITIVE && a->exprPrim.stackGrowth) {
// Guaranteed to not require more dumbification
a->exprPrim.val += this->stackGrowth;
}
}
void ast_spill_to_stack(AST *tlc, ScopeItem *vte) {
assert(tlc->nodeKind == AST_CHUNK);
assert(vte != NULL);
assert(vte->kind == SCOPEITEM_VAR);
if(ntc_get_int("pdbg")) {
fprintf(stderr, "### SPILLING %s ###\n", vte->data.var.name);
}
struct Spill2StackState state;
memset(&state, 0, sizeof(state));
state.target = vte;
state.targetTLC = tlc;
state.stackGrowth = (type_size(vte->type) + 7) & ~7;
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor, NULL);
size_t vteIndex = 0;
while(tlc->chunk.vars[vteIndex] != vte) vteIndex++;
memmove(&tlc->chunk.vars[vteIndex], &tlc->chunk.vars[vteIndex + 1], sizeof(*tlc->chunk.vars) * (tlc->chunk.varCount - vteIndex - 1));
tlc->chunk.varCount--;
}
void ast_grow_stack_frame(AST *tlc, size_t bytes) {
if(bytes == 0) {
return;
}
struct Spill2StackState state;
memset(&state, 0, sizeof(state));
state.target = NULL; // spill nothing
state.targetTLC = tlc;
state.stackGrowth = bytes;
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor, NULL);
}

9
src/ast/stack.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include<stddef.h>
union AST;
struct ScopeItem;
void ast_spill_to_stack(union AST *tlc, struct ScopeItem *vte);
void ast_grow_stack_frame(union AST *tlc, size_t bytes);

215
src/ast/usedef.c Normal file
View File

@ -0,0 +1,215 @@
#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;
}
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);
}
}

4
src/ast/usedef.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
union AST;
void ast_usedef_reset(union AST *chu);

View File

@ -1,7 +1,7 @@
#ifndef NCTREF_PARSE_H #ifndef NCTREF_PARSE_H
#define NCTREF_PARSE_H #define NCTREF_PARSE_H
#include"ast.h" #include"ast/ast.h"
AST *nct_parse(Token*); AST *nct_parse(Token*);

View File

@ -3,7 +3,7 @@
#include<stdarg.h> #include<stdarg.h>
#include<stdio.h> #include<stdio.h>
#include<stdlib.h> #include<stdlib.h>
#include"ast.h" #include"ast/ast.h"
#include"lexer.h" #include"lexer.h"
static void stahp_va(int row, int column, const char *error, va_list l) { static void stahp_va(int row, int column, const char *error, va_list l) {

View File

@ -6,31 +6,6 @@
#include<assert.h> #include<assert.h>
#include<stdio.h> #include<stdio.h>
/*struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) {
struct ReachingDefs *ret = calloc(1, sizeof(*ret));
ret->parent = this;
return ret;
}
struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs *this) {
struct ReachingDefs *parent = this->parent;
if(parent) {
parent->defs = realloc(parent->defs, sizeof(*parent->defs) * (parent->defCount + this->defCount));
memcpy(&parent->defs[parent->defCount], this->defs, sizeof(*this->defs) * this->defCount);
parent->defCount += this->defCount;
}
free(this->defs);
free(this);
return parent;
}
void reachingdefs_set(struct ReachingDefs *this, union AST *def) {
this->defCount = 1;
this->defs = realloc(this->defs, sizeof(*this->defs) * this->defCount);
this->defs[0] = def;
this->excludeParent = 1;
}*/
Scope *scope_new(Scope *parent) { Scope *scope_new(Scope *parent) {
Scope *ret = calloc(1, sizeof(*ret)); Scope *ret = calloc(1, sizeof(*ret));
ret->parent = parent; ret->parent = parent;

View File

@ -4,7 +4,7 @@
#include<stdlib.h> #include<stdlib.h>
#include<string.h> #include<string.h>
#include<stdint.h> #include<stdint.h>
#include"ast.h" #include"ast/ast.h"
#include"reporting.h" #include"reporting.h"
#include<assert.h> #include<assert.h>

View File

@ -5,7 +5,7 @@
#include<assert.h> #include<assert.h>
#include<stdbool.h> #include<stdbool.h>
#include<stdlib.h> #include<stdlib.h>
#include"ast.h" #include"ast/ast.h"
#define HWR_AL 1 #define HWR_AL 1
#define HWR_AH 2 #define HWR_AH 2

View File

@ -4,7 +4,7 @@
#include<assert.h> #include<assert.h>
#include"ntc.h" #include"ntc.h"
#include"reporting.h" #include"reporting.h"
#include"ast.h" #include"ast/ast.h"
#include"arch.h" #include"arch.h"
#include"utils.h" #include"utils.h"