Handle certain precoloring collisions
This commit is contained in:
parent
17a0c9d902
commit
5b3991e81c
@ -100,6 +100,7 @@ int ast_expression_equal(AST *a, AST *b) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function may return three values: YES (1), NO (0) or UNKNOWN (-1).
|
||||||
// ... Ew
|
// ... Ew
|
||||||
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) {
|
||||||
const AST *s = chunk->chunk.statementFirst;
|
const AST *s = chunk->chunk.statementFirst;
|
||||||
|
66
src/cg.c
66
src/cg.c
@ -165,6 +165,13 @@ static const char *xop(AST *tlc, AST *e) {
|
|||||||
return xop_sz(tlc, e, type_size(e->expression.type));
|
return xop_sz(tlc, e, type_size(e->expression.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ud_empty(VarTableEntry *a) {
|
||||||
|
assert(a->kind == VARTABLEENTRY_VAR);
|
||||||
|
assert(!a->data.var.usedefFirst == !a->data.var.usedefLast);
|
||||||
|
|
||||||
|
return !a->data.var.usedefFirst;
|
||||||
|
}
|
||||||
|
|
||||||
void cg_chunk(CGState *cg, AST *a) {
|
void cg_chunk(CGState *cg, AST *a) {
|
||||||
AST *s = a->chunk.statementFirst;
|
AST *s = a->chunk.statementFirst;
|
||||||
|
|
||||||
@ -383,15 +390,9 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Spill2StackState {
|
|
||||||
AST *targetTLC;
|
|
||||||
VarTableEntry *target;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Spill2VarState {
|
struct Spill2VarState {
|
||||||
VarTableEntry *target;
|
VarTableEntry *target;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
static size_t vidx = 0;
|
static size_t vidx = 0;
|
||||||
|
|
||||||
@ -476,6 +477,10 @@ static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Spill2StackState {
|
||||||
|
AST *targetTLC;
|
||||||
|
VarTableEntry *target;
|
||||||
|
};
|
||||||
static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
struct Spill2StackState *this = ud;
|
struct Spill2StackState *this = ud;
|
||||||
|
|
||||||
@ -521,14 +526,17 @@ static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ud_empty(VarTableEntry *a) {
|
struct PrecolorState {
|
||||||
assert(a->kind == VARTABLEENTRY_VAR);
|
ASTExprVar *mustBeSpilled;
|
||||||
assert(!a->data.var.usedefFirst == !a->data.var.usedefLast);
|
};
|
||||||
|
|
||||||
return !a->data.var.usedefFirst;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
|
struct PrecolorState *this = ud;
|
||||||
|
|
||||||
|
if(this->mustBeSpilled) {
|
||||||
|
/* Since something must be spilled first, we can't do anything else. Quit ASAP. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AST *n = *nptr;
|
AST *n = *nptr;
|
||||||
|
|
||||||
if(n == tlc) {
|
if(n == tlc) {
|
||||||
@ -544,9 +552,15 @@ static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A
|
|||||||
|
|
||||||
VarTableEntry *vte = n->stmtReturn.val->exprVar.thing;
|
VarTableEntry *vte = n->stmtReturn.val->exprVar.thing;
|
||||||
|
|
||||||
assert(!vte->data.var.precolored);
|
const int requiredColor = COLOR_EAX;
|
||||||
|
|
||||||
vte->data.var.color = COLOR_EAX;
|
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
||||||
|
// Precoloring collision!
|
||||||
|
this->mustBeSpilled = vte;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vte->data.var.color = requiredColor;
|
||||||
vte->data.var.precolored = true;
|
vte->data.var.precolored = true;
|
||||||
}
|
}
|
||||||
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
||||||
@ -554,9 +568,15 @@ static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A
|
|||||||
|
|
||||||
VarTableEntry *vte = n->stmtAssign.what->exprVar.thing;
|
VarTableEntry *vte = n->stmtAssign.what->exprVar.thing;
|
||||||
|
|
||||||
assert(!vte->data.var.precolored);
|
const int requiredColor = COLOR_EAX;
|
||||||
|
|
||||||
vte->data.var.color = COLOR_EAX;
|
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
||||||
|
// Precoloring collision!
|
||||||
|
this->mustBeSpilled = vte;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vte->data.var.color = requiredColor;
|
||||||
vte->data.var.precolored = true;
|
vte->data.var.precolored = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -626,7 +646,6 @@ struct CalleeSavedState {
|
|||||||
// To make sure we don't process the same return statement to infinity
|
// To make sure we don't process the same return statement to infinity
|
||||||
AST *lastProcessedReturn;
|
AST *lastProcessedReturn;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void callee_saved_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
static void callee_saved_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
struct CalleeSavedState *this = ud;
|
struct CalleeSavedState *this = ud;
|
||||||
|
|
||||||
@ -753,11 +772,18 @@ static int comparator(const void *A, const void *B) {
|
|||||||
}
|
}
|
||||||
int cg_go(AST *a) {
|
int cg_go(AST *a) {
|
||||||
do {
|
do {
|
||||||
generic_visitor(&a, NULL, NULL, a, a, NULL, precolor_visitor);
|
struct PrecolorState state = {};
|
||||||
|
generic_visitor(&a, NULL, NULL, a, a, &state, precolor_visitor);
|
||||||
|
|
||||||
ast_usedef_reset(a);
|
ast_usedef_reset(a);
|
||||||
|
|
||||||
VarTableEntry *vte = get_precolor_spill_candidate(a);
|
// Spill?
|
||||||
|
VarTableEntry *vte = state.mustBeSpilled; // set if precoloring demands DIFFERENT colors for the same variable
|
||||||
|
if(!vte) {
|
||||||
|
// Find variables with the same color
|
||||||
|
vte = get_precolor_spill_candidate(a);
|
||||||
|
}
|
||||||
|
|
||||||
if(vte) {
|
if(vte) {
|
||||||
struct Spill2VarState state;
|
struct Spill2VarState state;
|
||||||
memset(&state, 0, sizeof(state));
|
memset(&state, 0, sizeof(state));
|
||||||
|
Loading…
Reference in New Issue
Block a user