diff --git a/src/ast/ast.c b/src/ast/ast.c index cbe1bd1..52a4f02 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -285,3 +285,55 @@ AST *ast_cast_expr(AST *what, Type *to) { fail: stahp_node(what, "Cannot cast type %s into %s", type_to_string(what->expression.type), type_to_string(to)); } + +struct ReferencesStackState { + bool yes; +}; +static void references_stack_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + AST *n = *nptr; + if(n->nodeKind == AST_EXPR_STACK_POINTER) { + ((struct ReferencesStackState*) ud)->yes = true; + } +} +bool ast_references_stack(AST *a) { + struct ReferencesStackState state = {}; + generic_visitor(&a, NULL, NULL, NULL, NULL, &state, references_stack_visitor, NULL); + return state.yes; +} + +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; + } + } +} +bool ast_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; +} + +ScopeItem *ast_tlc_new_var(AST *tlc, char *name, Type *itstype) { + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_VAR; + vte->type = itstype; + vte->data.var.color = -1; + vte->data.var.precolored = false; + vte->data.var.degree = 0; + vte->data.var.priority = 0; + vte->data.var.name = name; + + // Add to var array + tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount)); + tlc->chunk.vars[tlc->chunk.varCount - 1] = vte; + + return vte; +} \ No newline at end of file diff --git a/src/ast/ast.h b/src/ast/ast.h index 061d3dd..559a811 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -381,6 +381,13 @@ void ast_typecheck(AST *tlc); AST *ast_get_label_by_name(AST *tlc, const char *name); +bool ast_references_stack(AST *a); + +bool ast_is_scopeitem_referenced(AST *tlc, ScopeItem *si); + +// name becomes OWNED +ScopeItem *ast_tlc_new_var(AST *tlc, char *name, Type *itstype); + #include"dump.h" #include"stack.h" #include"desegment.h" @@ -388,5 +395,6 @@ AST *ast_get_label_by_name(AST *tlc, const char *name); #include"linearize.h" #include"usedef.h" #include"commutativity.h" +#include"scr.h" #endif diff --git a/src/ast/scr.c b/src/ast/scr.c new file mode 100644 index 0000000..ae971a2 --- /dev/null +++ b/src/ast/scr.c @@ -0,0 +1,61 @@ +#include"sroa.h" + +#include"ast.h" +#include"ntc.h" +#include"utils.h" +#include +#include + +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 SCRState { + AST *tlc; +}; +static void ast_scr_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + AST *n = *aptr; + + struct SCRState *state = ud; + + if(state->tlc != tlc) return; + + if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.what->expression.type->type == TYPE_TYPE_RECORD) { + Type *rectype = n->stmtAssign.what->expression.type; + + for(size_t f = 0; f < rectype->record.fieldCount; f++) { + ASTExprDot *dot1 = calloc(1, sizeof(*dot1)); + dot1->nodeKind = AST_EXPR_DOT; + dot1->type = rectype->record.fieldTypes[f]; + dot1->a = ast_deep_copy(n->stmtAssign.what); + dot1->b = strdup(rectype->record.fieldNames[f]); + + ASTExprDot *dot2 = calloc(1, sizeof(*dot2)); + dot2->nodeKind = AST_EXPR_DOT; + dot2->type = rectype->record.fieldTypes[f]; + dot2->a = ast_deep_copy(n->stmtAssign.to); + dot2->b = strdup(rectype->record.fieldNames[f]); + + ASTStmtAssign *assign = calloc(1, sizeof(*assign)); + assign->nodeKind = AST_STMT_ASSIGN; + assign->what = (AST*) dot1; + assign->to = (AST*) dot2; + + stmtPrev->statement.next = (AST*) assign; + stmtPrev = assign; + } + + stmtPrev->statement.next = stmt->statement.next; + } +} + +void ast_secondclass_record(AST *tlc) { + struct SCRState state = {.tlc = tlc}; + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, ast_scr_visitor, NULL); + + if(ntc_get_int("pdbg")) { + char *astdump = ast_dump(tlc); + fprintf(stderr, "### SCR ###\n%s\n", astdump); + free(astdump); + } +} diff --git a/src/ast/scr.h b/src/ast/scr.h new file mode 100644 index 0000000..07413d0 --- /dev/null +++ b/src/ast/scr.h @@ -0,0 +1,12 @@ +#pragma once + +// In machine code structs/records are second-class concepts. +// Either the record gets split into its separate fields (SRoA), +// or it must be spilled into memory. +// +// In any case, many QoL features programmers love (assigning structs to +// structs or passing structs as arguments to functions) don't exist in +// machine code and must be converted to a valid but equivalent form. + +union AST; +void ast_secondclass_record(union AST *tlc); diff --git a/src/ast/sroa.c b/src/ast/sroa.c index a599644..01cf1d7 100644 --- a/src/ast/sroa.c +++ b/src/ast/sroa.c @@ -10,26 +10,6 @@ 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; @@ -89,7 +69,7 @@ void ast_sroa(AST *tlc) { continue; } - if(is_scopeitem_referenced(tlc, si)) { + if(ast_is_scopeitem_referenced(tlc, si)) { continue; } @@ -101,4 +81,10 @@ void ast_sroa(AST *tlc) { /* Restart */ i = -1; } + + if(ntc_get_int("pdbg")) { + char *astdump = ast_dump(tlc); + fprintf(stderr, "### SROA ###\n%s\n", astdump); + free(astdump); + } } diff --git a/src/ntc.c b/src/ntc.c index aa75780..d1f94d0 100644 --- a/src/ntc.c +++ b/src/ntc.c @@ -97,6 +97,7 @@ int main(int argc_, char **argv_) { } ast_segmented_dereference(chunk); + ast_secondclass_record(chunk); ast_sroa(chunk); ast_linearize(chunk); diff --git a/src/x86/dumberdowner.c b/src/x86/dumberdowner.c index c2579a5..e158bba 100644 --- a/src/x86/dumberdowner.c +++ b/src/x86/dumberdowner.c @@ -16,21 +16,7 @@ static ScopeItem *create_dumbtemp(AST *tlc, Type *itstype) { static size_t vidx = 0; - - ScopeItem *vte = calloc(1, sizeof(*vte)); - vte->kind = SCOPEITEM_VAR; - vte->type = itstype; - vte->data.var.color = -1; - vte->data.var.precolored = false; - vte->data.var.degree = 0; - vte->data.var.priority = 0; - vte->data.var.name = malp("$dumb%lu", vidx++); - - // Add to var array - tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount)); - tlc->chunk.vars[tlc->chunk.varCount - 1] = vte; - - return vte; + return ast_tlc_new_var(tlc, malp("$dumb%lu", vidx++), itstype); } /* Split away complex expression into a new local variable */ @@ -781,7 +767,7 @@ void dumben_pre(AST *tlc) { generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, decompose_symbol_record_field_access, NULL); for(size_t t = 0; t < tlc->chunk.varCount;) { - if(tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) { + if(ast_is_scopeitem_referenced(tlc, tlc->chunk.vars[t]) || tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) { ast_spill_to_stack(tlc, tlc->chunk.vars[t]); } else { t++;