Loop guards

This commit is contained in:
Mid 2024-02-15 22:33:06 +02:00
parent 5ec2349336
commit 77a459ffd3
7 changed files with 101 additions and 30 deletions

View File

@ -29,6 +29,13 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) {
const AST *s = chunk->chunk.statementFirst;
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) {
return 0;
}
@ -41,11 +48,6 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) {
if(i != -1) {
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;

View File

@ -178,32 +178,34 @@ void cg_chunk(AST *a) {
}
}
} 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"};
printf("%s %s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], specexpr(s->stmtAssign.what), xop(s->stmtAssign.what));
} 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("lea %s, [%s + %s]\n",
xv(s->stmtAssign.what->exprVar.thing),
xv(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing),
xv(s->stmtAssign.to->exprBinOp.operands[1]->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) {
printf("lea %s, [%s + %s]\n",
xv(s->stmtAssign.what->exprVar.thing),
s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
} else {
printf("mov %s, %s\n", xop(s->stmtAssign.what), xop(s->stmtAssign.to));
// inc or dec
static const char *instrs[] = {"inc", "dec"};
printf("%s %s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], specexpr(s->stmtAssign.what), xop(s->stmtAssign.what));
} 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("lea %s, [%s + %s]\n",
xv(s->stmtAssign.what->exprVar.thing),
xv(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing),
xv(s->stmtAssign.to->exprBinOp.operands[1]->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) {
printf("lea %s, [%s + %s]\n",
xv(s->stmtAssign.what->exprVar.thing),
s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
} else {
printf("mov %s, %s\n", xop(s->stmtAssign.what), xop(s->stmtAssign.to));
}
}
} else if(s->nodeKind == AST_STMT_LOOP) {

View File

@ -158,14 +158,14 @@ static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
// Assemble ud-chain
UseDef *ud[2];
ud[0] = malloc(sizeof(UseDef));
ud[1] = malloc(sizeof(UseDef));
ud[0]->stmt = (AST*) assign;
ud[0]->use = assign->what;
ud[0]->def = (AST*) assign;
ud[0]->next = ud[1];
ud[1] = malloc(sizeof(UseDef));
ud[1]->stmt = stmt;
ud[1]->use = (AST*) ev[1];
ud[1]->def = (AST*) assign;

View File

@ -44,6 +44,11 @@ typedef struct {
// Used by pushstmt to assemble use-def chain
size_t udsToAddCount;
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;
static Token get(Parser *P) {
@ -167,6 +172,36 @@ static AST *exprvar(Parser *P, VarTableEntry *v) {
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;
}
@ -614,6 +649,7 @@ static AST *parse_declaration(Parser *P) {
ASTStmtAssign *assign = malloc(sizeof(*assign));
assign->nodeKind = AST_STMT_ASSIGN;
assign->next = NULL;
entry->data.var.reachingDefs = reachingdefs_push(NULL);
reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign);
@ -765,10 +801,29 @@ void nct_parse_statement(Parser *P) {
ret->nodeKind = AST_STMT_LOOP;
ret->next = NULL;
int isFirstLoop = P->loopScope == NULL;
if(isFirstLoop) {
P->loopScope = P->scope;
}
expect(P, TOKEN_SQUIGGLY_L);
ret->body = (AST*) nct_parse_chunk(P, 0, 1);
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);
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++) {
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
P->topLevel->vars[P->topLevel->varCount++] = P->scope->data[i];
P->scope->data[i]->owner = P->topLevel;
}
}

View File

@ -65,6 +65,7 @@ VarTableEntry *vartable_set(VarTable *this, const char *name, VarTableEntry *e)
this->data[this->count] = e;
this->count++;
if(e->kind == VARTABLEENTRY_VAR) e->data.var.name = name;
e->owner = this;
return e;
}

View File

@ -27,9 +27,12 @@ struct ReachingDefs *reachingdefs_push(struct ReachingDefs*);
struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*);
void reachingdefs_set(struct ReachingDefs*, union AST*);
struct VarTable;
typedef struct VarTableEntry {
Type *type;
struct VarTable *owner;
VarTableEntryKind kind;
struct {
union {

7
tests/loopregalloc.nct Normal file
View File

@ -0,0 +1,7 @@
u8 a;
loop {
a = 3;
u8 b = 1;
}