263 lines
7.8 KiB
C
263 lines
7.8 KiB
C
#include"dumberdowner.h"
|
|
|
|
#include<stdlib.h>
|
|
#include<assert.h>
|
|
|
|
// This is the dumbing down pass.
|
|
//
|
|
// Complex expressions are to be "broken down" into simpler ones until the AST
|
|
// can be trivially translated to the target architecture.
|
|
//
|
|
// This pass, along with CG is strictly dependent on x86 and will fail for
|
|
// any other architecture.
|
|
|
|
// Can expression be expressed as a single x86 operand?
|
|
#define XOP_NOT_XOP 0
|
|
#define XOP_NOT_MEM 1
|
|
#define XOP_MEM 2
|
|
static int is_xop(AST *e) {
|
|
if(e->nodeKind == AST_EXPR_PRIMITIVE) {
|
|
return XOP_NOT_MEM;
|
|
} else if(e->nodeKind == AST_EXPR_VAR) {
|
|
return e->exprVar.thing->kind == VARTABLEENTRY_VAR ? XOP_NOT_MEM : XOP_MEM;
|
|
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) {
|
|
return XOP_NOT_MEM;
|
|
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
|
|
AST *c = e->exprUnOp.operand;
|
|
|
|
if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
|
return XOP_MEM;
|
|
} else if(c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && c->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && c->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR) {
|
|
if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) {
|
|
return XOP_MEM;
|
|
} else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && c->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && c->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) {
|
|
int scale = c->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val;
|
|
|
|
if(scale == 1 || scale == 2 || scale == 4 || scale == 8) {
|
|
return XOP_MEM;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return XOP_NOT_XOP;
|
|
}
|
|
|
|
static void varify_change_usedefs(AST *e, AST *oldStmt, AST *newStmt) {
|
|
if(e->nodeKind == AST_EXPR_VAR) {
|
|
if(e->exprVar.thing->kind != VARTABLEENTRY_VAR) {
|
|
return;
|
|
}
|
|
|
|
UseDef *swapWithPrev = NULL;
|
|
UseDef *swapWith = NULL;
|
|
|
|
UseDef *udPrev = NULL;
|
|
UseDef *ud = e->exprVar.thing->data.var.usedefFirst;
|
|
while(ud && ud->use != e) {
|
|
if(ud->stmt == oldStmt && !swapWith) {
|
|
swapWithPrev = udPrev;
|
|
swapWith = ud;
|
|
}
|
|
|
|
udPrev = ud;
|
|
ud = ud->next;
|
|
}
|
|
|
|
if(ud) {
|
|
assert(ud->stmt == oldStmt);
|
|
ud->stmt = newStmt;
|
|
|
|
// We must make sure all newStmt usedefs are before the oldStmt ones, so swap
|
|
if(swapWith) {
|
|
assert(!!swapWithPrev + !!udPrev != 0);
|
|
|
|
if(swapWithPrev) {
|
|
swapWithPrev->next = ud;
|
|
} else {
|
|
e->exprVar.thing->data.var.usedefFirst = ud;
|
|
}
|
|
|
|
if(udPrev) {
|
|
udPrev->next = swapWith;
|
|
} else {
|
|
e->exprVar.thing->data.var.usedefFirst = swapWith;
|
|
}
|
|
|
|
UseDef *temp = ud->next;
|
|
ud->next = swapWith->next;
|
|
swapWith->next = temp;
|
|
|
|
assert(!!ud->next + !!swapWith->next != 0);
|
|
if(!swapWith->next) {
|
|
e->exprVar.thing->data.var.usedefLast = swapWith;
|
|
}
|
|
if(!ud->next) {
|
|
e->exprVar.thing->data.var.usedefLast = ud;
|
|
}
|
|
}
|
|
}
|
|
} else if(e->nodeKind == AST_EXPR_BINARY_OP) {
|
|
varify_change_usedefs(e->exprBinOp.operands[0], oldStmt, newStmt);
|
|
varify_change_usedefs(e->exprBinOp.operands[1], oldStmt, newStmt);
|
|
} else if(e->nodeKind == AST_EXPR_UNARY_OP) {
|
|
varify_change_usedefs(e->exprUnOp.operand, oldStmt, newStmt);
|
|
} else if(e->nodeKind == AST_EXPR_CALL) {
|
|
varify_change_usedefs(e->exprCall.what, oldStmt, newStmt);
|
|
|
|
int argCount = e->exprCall.what->expression.type->function.argCount;
|
|
for(int i = 0; i < argCount; i++) {
|
|
varify_change_usedefs(e->exprCall.args[i], oldStmt, newStmt);
|
|
}
|
|
} else if(e->nodeKind == AST_EXPR_ARRAY) {
|
|
int sz = e->exprArray.type->array.length;
|
|
for(int i = 0; i < sz; i++) {
|
|
varify_change_usedefs(e->exprArray.items[i], oldStmt, newStmt);
|
|
}
|
|
} else if(e->nodeKind == AST_EXPR_CAST) {
|
|
varify_change_usedefs(e->exprCast.what, oldStmt, newStmt);
|
|
}
|
|
}
|
|
|
|
/* Split away complex expression into a new local variable */
|
|
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
|
VarTableEntry *vte = malloc(sizeof(*vte));
|
|
vte->kind = VARTABLEENTRY_VAR;
|
|
vte->type = e->expression.type;
|
|
vte->data.var.color = 0;
|
|
vte->data.var.degree = 0;
|
|
vte->data.var.priority = 0;
|
|
vte->data.var.reachingDefs = NULL;
|
|
|
|
// 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;
|
|
|
|
// Alter AST
|
|
|
|
ASTExprVar *ev[2];
|
|
for(int i = 0; i < 2; i++) {
|
|
ev[i] = malloc(sizeof(ASTExprVar));
|
|
ev[i]->nodeKind = AST_EXPR_VAR;
|
|
ev[i]->type = e->expression.type;
|
|
ev[i]->thing = vte;
|
|
}
|
|
|
|
ASTStmtAssign *assign = malloc(sizeof(*assign));
|
|
assign->nodeKind = AST_STMT_ASSIGN;
|
|
assign->what = (AST*) ev[0];
|
|
assign->to = e;
|
|
|
|
if(stmtPrev) {
|
|
stmtPrev->statement.next = (AST*) assign;
|
|
} else {
|
|
chunk->chunk.statementFirst = (AST*) assign;
|
|
}
|
|
assign->next = stmt;
|
|
|
|
// 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]->stmt = stmt;
|
|
ud[1]->use = (AST*) ev[1];
|
|
ud[1]->def = (AST*) assign;
|
|
ud[1]->next = NULL;
|
|
|
|
vte->data.var.usedefFirst = ud[0];
|
|
vte->data.var.usedefLast = ud[1];
|
|
|
|
// Correct the ud-chain of variables used in varified expression `e`
|
|
|
|
varify_change_usedefs(e, stmt, (AST*) assign);
|
|
|
|
return (AST*) ev[1];
|
|
}
|
|
|
|
static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
|
return varify(tlc, chunk, stmtPrev, stmt, e);
|
|
}
|
|
|
|
static int dumben_chunk(AST *tlc, AST *chu) {
|
|
AST *sPrev = NULL;
|
|
AST *s = chu->chunk.statementFirst;
|
|
|
|
int effective = 0;
|
|
|
|
while(s) {
|
|
|
|
if(s->nodeKind == AST_STMT_IF) {
|
|
|
|
AST *e = s->stmtIf.expression;
|
|
|
|
if(e->nodeKind == AST_EXPR_BINARY_OP && binop_is_comparison(e->exprBinOp.operator)) {
|
|
|
|
if(is_xop(e->exprBinOp.operands[0]) == XOP_NOT_XOP) {
|
|
e->exprBinOp.operands[0] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[0]);
|
|
effective = 1;
|
|
}
|
|
|
|
if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) {
|
|
e->exprBinOp.operands[1] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]);
|
|
effective = 1;
|
|
}
|
|
|
|
if(is_xop(e->exprBinOp.operands[0]) == XOP_MEM && is_xop(e->exprBinOp.operands[1]) == XOP_MEM) {
|
|
// Can't have two mems; put one in var
|
|
|
|
e->exprBinOp.operands[1] = varify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]);
|
|
effective = 1;
|
|
}
|
|
|
|
} else {
|
|
|
|
s->stmtIf.expression = varify(tlc, chu, sPrev, s, e);
|
|
effective = 1;
|
|
|
|
}
|
|
|
|
effective |= dumben_chunk(tlc, s->stmtIf.then);
|
|
|
|
} else if(s->nodeKind == AST_STMT_LOOP) {
|
|
|
|
effective |= dumben_chunk(tlc, s->stmtLoop.body);
|
|
|
|
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
|
|
|
if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF
|
|
&& s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) {
|
|
|
|
s->stmtAssign.to = varify(tlc, chu, sPrev, s, s->stmtAssign.to);
|
|
effective = 1;
|
|
}
|
|
|
|
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) {
|
|
|
|
int argCount = s->stmtExpr.expr->exprCall.what->expression.type->function.argCount;
|
|
|
|
for(int i = 0; i < argCount; i++) {
|
|
if(is_xop(s->stmtExpr.expr->exprCall.args[i]) == XOP_NOT_XOP) {
|
|
s->stmtExpr.expr->exprCall.args[i] = xopify(tlc, chu, sPrev, s, s->stmtExpr.expr->exprCall.args[i]);
|
|
effective = 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
sPrev = s;
|
|
s = s->statement.next;
|
|
}
|
|
|
|
return effective;
|
|
}
|
|
|
|
void dumben_go(AST* tlc) {
|
|
while(dumben_chunk(tlc, tlc));
|
|
} |