Loop guards
This commit is contained in:
parent
5ec2349336
commit
77a459ffd3
12
src/ast.c
12
src/ast.c
@ -29,6 +29,13 @@ 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;
|
||||||
|
|
||||||
while(s) {
|
while(s) {
|
||||||
|
if(s->nodeKind == AST_STMT_LOOP) {
|
||||||
|
int i = ast_stmt_is_after(s->stmtLoop.body, s1, s2);
|
||||||
|
if(i != -1) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(s == s1) {
|
if(s == s1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -41,11 +48,6 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) {
|
|||||||
if(i != -1) {
|
if(i != -1) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
} else if(s->nodeKind == AST_STMT_LOOP) {
|
|
||||||
int i = ast_stmt_is_after(s->stmtLoop.body, s1, s2);
|
|
||||||
if(i != -1) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s = s->statement.next;
|
s = s->statement.next;
|
||||||
|
48
src/cg.c
48
src/cg.c
@ -178,32 +178,34 @@ void cg_chunk(AST *a) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
||||||
|
|
||||||
if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && (s->stmtAssign.to->exprBinOp.operator == BINOP_ADD || s->stmtAssign.to->exprBinOp.operator == BINOP_SUB) && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val == 1) {
|
|
||||||
|
|
||||||
// inc or dec
|
if(s->stmtAssign.to) {
|
||||||
|
if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && (s->stmtAssign.to->exprBinOp.operator == BINOP_ADD || s->stmtAssign.to->exprBinOp.operator == BINOP_SUB) && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val == 1) {
|
||||||
|
|
||||||
static const char *instrs[] = {"inc", "dec"};
|
// inc or dec
|
||||||
printf("%s %s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], specexpr(s->stmtAssign.what), xop(s->stmtAssign.what));
|
|
||||||
|
static const char *instrs[] = {"inc", "dec"};
|
||||||
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
printf("%s %s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], specexpr(s->stmtAssign.what), xop(s->stmtAssign.what));
|
||||||
|
|
||||||
printf("lea %s, [%s + %s]\n",
|
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||||
xv(s->stmtAssign.what->exprVar.thing),
|
|
||||||
xv(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing),
|
printf("lea %s, [%s + %s]\n",
|
||||||
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
|
xv(s->stmtAssign.what->exprVar.thing),
|
||||||
|
xv(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing),
|
||||||
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
|
||||||
|
|
||||||
printf("lea %s, [%s + %s]\n",
|
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||||
xv(s->stmtAssign.what->exprVar.thing),
|
|
||||||
s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
printf("lea %s, [%s + %s]\n",
|
||||||
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
|
xv(s->stmtAssign.what->exprVar.thing),
|
||||||
|
s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||||
} else {
|
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
|
||||||
|
|
||||||
printf("mov %s, %s\n", xop(s->stmtAssign.what), xop(s->stmtAssign.to));
|
} else {
|
||||||
|
|
||||||
|
printf("mov %s, %s\n", xop(s->stmtAssign.what), xop(s->stmtAssign.to));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(s->nodeKind == AST_STMT_LOOP) {
|
} else if(s->nodeKind == AST_STMT_LOOP) {
|
||||||
|
@ -158,14 +158,14 @@ static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
|||||||
// Assemble ud-chain
|
// Assemble ud-chain
|
||||||
|
|
||||||
UseDef *ud[2];
|
UseDef *ud[2];
|
||||||
|
|
||||||
ud[0] = malloc(sizeof(UseDef));
|
ud[0] = malloc(sizeof(UseDef));
|
||||||
|
ud[1] = malloc(sizeof(UseDef));
|
||||||
|
|
||||||
ud[0]->stmt = (AST*) assign;
|
ud[0]->stmt = (AST*) assign;
|
||||||
ud[0]->use = assign->what;
|
ud[0]->use = assign->what;
|
||||||
ud[0]->def = (AST*) assign;
|
ud[0]->def = (AST*) assign;
|
||||||
ud[0]->next = ud[1];
|
ud[0]->next = ud[1];
|
||||||
|
|
||||||
ud[1] = malloc(sizeof(UseDef));
|
|
||||||
ud[1]->stmt = stmt;
|
ud[1]->stmt = stmt;
|
||||||
ud[1]->use = (AST*) ev[1];
|
ud[1]->use = (AST*) ev[1];
|
||||||
ud[1]->def = (AST*) assign;
|
ud[1]->def = (AST*) assign;
|
||||||
|
56
src/parse.c
56
src/parse.c
@ -44,6 +44,11 @@ typedef struct {
|
|||||||
// Used by pushstmt to assemble use-def chain
|
// Used by pushstmt to assemble use-def chain
|
||||||
size_t udsToAddCount;
|
size_t udsToAddCount;
|
||||||
UseDefToAdd *udsToAdd;
|
UseDefToAdd *udsToAdd;
|
||||||
|
|
||||||
|
// Used to place guard variable uses after loops to stop reg allocation from fucking up
|
||||||
|
VarTable *loopScope;
|
||||||
|
size_t guardedVarCount;
|
||||||
|
ASTExprVar **guardedVars;
|
||||||
} Parser;
|
} Parser;
|
||||||
|
|
||||||
static Token get(Parser *P) {
|
static Token get(Parser *P) {
|
||||||
@ -167,6 +172,36 @@ static AST *exprvar(Parser *P, VarTableEntry *v) {
|
|||||||
newusedef(P, v, a);
|
newusedef(P, v, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(P->loopScope) {
|
||||||
|
// XXX: O(n)!!!!!!!!!
|
||||||
|
|
||||||
|
int inloop = 0;
|
||||||
|
for(VarTable *vt = v->owner; vt; vt = vt->parent) {
|
||||||
|
if(vt->parent == P->loopScope) {
|
||||||
|
inloop = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!inloop) {
|
||||||
|
int alreadyAdded = 0;
|
||||||
|
for(size_t i = 0; i < P->guardedVarCount; i++) {
|
||||||
|
if(P->guardedVars[i]->thing == v) {
|
||||||
|
alreadyAdded = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!alreadyAdded) {
|
||||||
|
ASTExprVar *ev = malloc(sizeof(*ev));
|
||||||
|
memcpy(ev, a, sizeof(*ev));
|
||||||
|
|
||||||
|
P->guardedVars = realloc(P->guardedVars, sizeof(*P->guardedVars) * (P->guardedVarCount + 1));
|
||||||
|
P->guardedVars[P->guardedVarCount++] = ev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,6 +649,7 @@ static AST *parse_declaration(Parser *P) {
|
|||||||
|
|
||||||
ASTStmtAssign *assign = malloc(sizeof(*assign));
|
ASTStmtAssign *assign = malloc(sizeof(*assign));
|
||||||
assign->nodeKind = AST_STMT_ASSIGN;
|
assign->nodeKind = AST_STMT_ASSIGN;
|
||||||
|
assign->next = NULL;
|
||||||
|
|
||||||
entry->data.var.reachingDefs = reachingdefs_push(NULL);
|
entry->data.var.reachingDefs = reachingdefs_push(NULL);
|
||||||
reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign);
|
reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign);
|
||||||
@ -765,10 +801,29 @@ void nct_parse_statement(Parser *P) {
|
|||||||
ret->nodeKind = AST_STMT_LOOP;
|
ret->nodeKind = AST_STMT_LOOP;
|
||||||
ret->next = NULL;
|
ret->next = NULL;
|
||||||
|
|
||||||
|
int isFirstLoop = P->loopScope == NULL;
|
||||||
|
|
||||||
|
if(isFirstLoop) {
|
||||||
|
P->loopScope = P->scope;
|
||||||
|
}
|
||||||
|
|
||||||
expect(P, TOKEN_SQUIGGLY_L);
|
expect(P, TOKEN_SQUIGGLY_L);
|
||||||
ret->body = (AST*) nct_parse_chunk(P, 0, 1);
|
ret->body = (AST*) nct_parse_chunk(P, 0, 1);
|
||||||
expect(P, TOKEN_SQUIGGLY_R);
|
expect(P, TOKEN_SQUIGGLY_R);
|
||||||
|
|
||||||
|
if(isFirstLoop) {
|
||||||
|
P->loopScope = NULL;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < P->guardedVarCount; i++) {
|
||||||
|
ASTExprVar *ev = P->guardedVars[i];
|
||||||
|
|
||||||
|
newusedef(P, ev->thing, ev);
|
||||||
|
}
|
||||||
|
P->guardedVarCount = 0;
|
||||||
|
free(P->guardedVars);
|
||||||
|
P->guardedVars = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
loop_second_pass(ret->body);
|
loop_second_pass(ret->body);
|
||||||
|
|
||||||
pushstat(P, ret);
|
pushstat(P, ret);
|
||||||
@ -958,6 +1013,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
|
|||||||
for(size_t i = 0; i < P->scope->count; i++) {
|
for(size_t i = 0; i < P->scope->count; i++) {
|
||||||
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
|
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
|
||||||
P->topLevel->vars[P->topLevel->varCount++] = P->scope->data[i];
|
P->topLevel->vars[P->topLevel->varCount++] = P->scope->data[i];
|
||||||
|
P->scope->data[i]->owner = P->topLevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ VarTableEntry *vartable_set(VarTable *this, const char *name, VarTableEntry *e)
|
|||||||
this->data[this->count] = e;
|
this->data[this->count] = e;
|
||||||
this->count++;
|
this->count++;
|
||||||
if(e->kind == VARTABLEENTRY_VAR) e->data.var.name = name;
|
if(e->kind == VARTABLEENTRY_VAR) e->data.var.name = name;
|
||||||
|
e->owner = this;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,9 +27,12 @@ struct ReachingDefs *reachingdefs_push(struct ReachingDefs*);
|
|||||||
struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*);
|
struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*);
|
||||||
void reachingdefs_set(struct ReachingDefs*, union AST*);
|
void reachingdefs_set(struct ReachingDefs*, union AST*);
|
||||||
|
|
||||||
|
struct VarTable;
|
||||||
typedef struct VarTableEntry {
|
typedef struct VarTableEntry {
|
||||||
Type *type;
|
Type *type;
|
||||||
|
|
||||||
|
struct VarTable *owner;
|
||||||
|
|
||||||
VarTableEntryKind kind;
|
VarTableEntryKind kind;
|
||||||
struct {
|
struct {
|
||||||
union {
|
union {
|
||||||
|
7
tests/loopregalloc.nct
Normal file
7
tests/loopregalloc.nct
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
u8 a;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
a = 3;
|
||||||
|
|
||||||
|
u8 b = 1;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user