More AST functions (incl new second-class record pass)
This commit is contained in:
parent
b21ce51435
commit
dfbadfecb9
@ -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;
|
||||
}
|
@ -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
|
||||
|
61
src/ast/scr.c
Normal file
61
src/ast/scr.c
Normal file
@ -0,0 +1,61 @@
|
||||
#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 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);
|
||||
}
|
||||
}
|
12
src/ast/scr.h
Normal file
12
src/ast/scr.h
Normal file
@ -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);
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,7 @@ int main(int argc_, char **argv_) {
|
||||
}
|
||||
|
||||
ast_segmented_dereference(chunk);
|
||||
ast_secondclass_record(chunk);
|
||||
ast_sroa(chunk);
|
||||
|
||||
ast_linearize(chunk);
|
||||
|
@ -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++;
|
||||
|
Loading…
Reference in New Issue
Block a user