Despaghettify source
This commit is contained in:
parent
5196026ed1
commit
7f855f3931
269
src/ast/ast.c
Normal file
269
src/ast/ast.c
Normal 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));
|
||||||
|
}
|
@ -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
21
src/ast/commutativity.c
Normal 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
8
src/ast/commutativity.h
Normal 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
117
src/ast/desegment.c
Normal 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
7
src/ast/desegment.h
Normal 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
327
src/ast/dump.c
Normal 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
5
src/ast/dump.h
Normal 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
161
src/ast/linearize.c
Normal 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
4
src/ast/linearize.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
union AST;
|
||||||
|
void ast_linearize(union AST *tlc);
|
104
src/ast/sroa.c
Normal file
104
src/ast/sroa.c
Normal 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
4
src/ast/sroa.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
union AST;
|
||||||
|
void ast_sroa(union AST *tlc);
|
101
src/ast/stack.c
Normal file
101
src/ast/stack.c
Normal 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
9
src/ast/stack.h
Normal 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
215
src/ast/usedef.c
Normal 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
4
src/ast/usedef.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
union AST;
|
||||||
|
void ast_usedef_reset(union AST *chu);
|
@ -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*);
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
25
src/scope.c
25
src/scope.c
@ -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;
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user