518 lines
18 KiB
C
518 lines
18 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 file along with CG is strictly for IA-32 and will fail for other
|
|
// architectures.
|
|
|
|
#include"x86.h"
|
|
#include<string.h>
|
|
|
|
static VarTableEntry *create_dumbtemp(AST *tlc, Type *itstype) {
|
|
static size_t vidx = 0;
|
|
|
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
|
vte->kind = VARTABLEENTRY_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.reachingDefs = NULL;
|
|
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;
|
|
}
|
|
|
|
/* Split away complex expression into a new local variable */
|
|
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
|
VarTableEntry *vte = create_dumbtemp(tlc, e->expression.type);
|
|
|
|
// Alter AST
|
|
|
|
ASTExprVar *ev[2];
|
|
for(int i = 0; i < 2; i++) {
|
|
ev[i] = calloc(1, sizeof(ASTExprVar));
|
|
ev[i]->nodeKind = AST_EXPR_VAR;
|
|
ev[i]->type = e->expression.type;
|
|
ev[i]->thing = vte;
|
|
}
|
|
|
|
ASTStmtAssign *assign = calloc(1, 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;
|
|
|
|
// Reset ud-chain
|
|
|
|
vte->data.var.usedefFirst = NULL;
|
|
vte->data.var.usedefLast = NULL;
|
|
|
|
return (AST*) ev[1];
|
|
}
|
|
|
|
static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
|
return varify(tlc, chunk, stmtPrev, stmt, e);
|
|
}
|
|
|
|
struct DumbenState {
|
|
int effective;
|
|
};
|
|
|
|
static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud) {
|
|
struct DumbenState *this = ud;
|
|
|
|
AST *s = *nptr;
|
|
|
|
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, stmtPrev, s, e->exprBinOp.operands[0]);
|
|
this->effective = 1;
|
|
}
|
|
|
|
if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) {
|
|
e->exprBinOp.operands[1] = xopify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]);
|
|
this->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, stmtPrev, s, e->exprBinOp.operands[1]);
|
|
this->effective = 1;
|
|
}
|
|
|
|
} else {
|
|
|
|
s->stmtIf.expression = varify(tlc, chu, stmtPrev, s, e);
|
|
this->effective = 1;
|
|
|
|
}
|
|
|
|
} else if(s->nodeKind == AST_STMT_LOOP) {
|
|
|
|
} else if(s->nodeKind == AST_STMT_RETURN) {
|
|
|
|
// ret specifically returns in eax always, so it needs to be in a precolored var
|
|
AST *retval = s->stmtReturn.val;
|
|
|
|
if(retval && (!is_xop(retval) || retval->nodeKind == AST_EXPR_PRIMITIVE || (retval->nodeKind == AST_EXPR_VAR && retval->exprVar.thing->kind == VARTABLEENTRY_VAR && retval->exprVar.thing->data.var.color != COLOR_EAX))) {
|
|
|
|
retval = s->stmtReturn.val = varify(tlc, chu, stmtPrev, s, retval);
|
|
this->effective = 1;
|
|
|
|
vte_precolor(retval->exprVar.thing, COLOR_EAX);
|
|
|
|
}
|
|
|
|
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) {
|
|
|
|
// Turn this:
|
|
// f(x);
|
|
// into:
|
|
// a = f(x);
|
|
|
|
s->stmtExpr.expr = varify(tlc, chu, stmtPrev, s, s->stmtExpr.expr);
|
|
|
|
vte_precolor(s->stmtExpr.expr->exprVar.thing, COLOR_EAX);
|
|
|
|
// Purge this statement entirely, otherwise we'd have
|
|
// a = f(x);
|
|
// a;
|
|
|
|
if(stmtPrev) {
|
|
assert(stmtPrev->statement.next->statement.next == s);
|
|
stmtPrev->statement.next->statement.next = s->statement.next;
|
|
} else {
|
|
assert(chu->chunk.statementFirst->statement.next == s);
|
|
chu->chunk.statementFirst->statement.next = s->statement.next;
|
|
}
|
|
|
|
this->effective = 1;
|
|
|
|
} else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.to) {
|
|
|
|
if(ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to) && stmtPrev) {
|
|
// This is a NOP, remove it from the AST
|
|
stmtPrev->statement.next = s->statement.next;
|
|
this->effective = 1;
|
|
} else {
|
|
|
|
if(s->stmtAssign.to->nodeKind == AST_EXPR_CALL && (s->stmtAssign.what->nodeKind != AST_EXPR_VAR || s->stmtAssign.what->exprVar.thing->kind != VARTABLEENTRY_VAR)) {
|
|
|
|
VarTableEntry *tmp = create_dumbtemp(tlc, s->stmtAssign.what->expression.type);
|
|
|
|
ASTExprVar *ev[2] = {calloc(1, sizeof(**ev)), calloc(1, sizeof(**ev))};
|
|
ev[0]->nodeKind = AST_EXPR_VAR;
|
|
ev[0]->type = tmp->type;
|
|
ev[0]->thing = tmp;
|
|
memcpy(ev[1], ev[0], sizeof(**ev));
|
|
|
|
ASTStmtAssign *assign2 = calloc(1, sizeof(*assign2));
|
|
assign2->nodeKind = AST_STMT_ASSIGN;
|
|
assign2->what = (AST*) s->stmtAssign.what;
|
|
assign2->to = (AST*) ev[0];
|
|
|
|
s->stmtAssign.what = (AST*) ev[1];
|
|
|
|
assign2->next = s->stmtAssign.next;
|
|
s->stmtAssign.next = (AST*) assign2;
|
|
|
|
this->effective = 1;
|
|
|
|
} else 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, stmtPrev, s, s->stmtAssign.to);
|
|
this->effective = 1;
|
|
|
|
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF && !is_xop(s->stmtAssign.what)) {
|
|
|
|
s->stmtAssign.what->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what->exprUnOp.operand);
|
|
this->effective = 1;
|
|
|
|
} else if(s->stmtAssign.what && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
|
ASTExprCall *call = &s->stmtAssign.to->exprCall;
|
|
|
|
int argCount = call->what->expression.type->function.argCount;
|
|
|
|
for(int i = 0; i < argCount; i++) {
|
|
if(is_xop(call->args[i]) == XOP_NOT_XOP) {
|
|
call->args[i] = xopify(tlc, chu, stmtPrev, s, call->args[i]);
|
|
this->effective = 1;
|
|
}
|
|
}
|
|
} else if(s->stmtAssign.to && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && !ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprUnOp.operand)) {
|
|
// Turn this:
|
|
// a = -b
|
|
// into
|
|
// a = b
|
|
// a = -a
|
|
|
|
AST *ev[2] = {
|
|
ast_deep_copy(s->stmtAssign.what),
|
|
ast_deep_copy(s->stmtAssign.what)
|
|
};
|
|
|
|
AST *negation = s->stmtAssign.to;
|
|
|
|
s->stmtAssign.to = negation->exprUnOp.operand;
|
|
negation->exprUnOp.operand = ev[0];
|
|
|
|
AST *assign2 = calloc(1, sizeof(ASTStmtAssign));
|
|
assign2->nodeKind = AST_STMT_ASSIGN;
|
|
assign2->stmtAssign.what = ev[1];
|
|
assign2->stmtAssign.to = negation;
|
|
|
|
assign2->statement.next = s->statement.next;
|
|
s->statement.next = assign2;
|
|
|
|
this->effective = 1;
|
|
} else if(is_xop(s->stmtAssign.to) == XOP_NOT_XOP) {
|
|
if(s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) {
|
|
s->stmtAssign.to->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprUnOp.operand);
|
|
|
|
this->effective = 1;
|
|
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) {
|
|
|
|
WhysItBad_Huh because = x86_test_mul(stmtPrev, s);
|
|
|
|
if(because == SRC0_IS_BAD_XOP) {
|
|
s->stmtAssign.to->exprBinOp.operands[0] = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[0]);
|
|
|
|
this->effective = 1;
|
|
} else if(because == SRC1_IS_BAD_XOP) {
|
|
s->stmtAssign.to->exprBinOp.operands[1] = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[1]);
|
|
|
|
this->effective = 1;
|
|
} else if(because == MISSING_MULHI_FOR_MUL || because == DEST_NOT_SRC0) {// !stmtPrev || stmtPrev->nodeKind != AST_STMT_ASSIGN || stmtPrev->stmtAssign.to->nodeKind != AST_EXPR_BINARY_OP || stmtPrev->stmtAssign.to->exprBinOp.operator != BINOP_MULHI) {
|
|
// Turn this:
|
|
// a = b * c
|
|
// Into this:
|
|
// d = b
|
|
// e = d *^ c
|
|
// d = d * c
|
|
// a = d
|
|
|
|
ASTExprVar *originalDestination = s->stmtAssign.what;
|
|
|
|
s->stmtAssign.to->exprBinOp.operands[0] = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[0]);
|
|
|
|
assert(stmtPrev->statement.next->nodeKind == AST_STMT_ASSIGN && stmtPrev->statement.next->stmtAssign.what->nodeKind == AST_EXPR_VAR && ast_expression_equal(stmtPrev->statement.next->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]));
|
|
|
|
if(!x86_imul_supported()) {
|
|
ASTExprBinaryOp *mulhi = calloc(1, sizeof(*mulhi));
|
|
mulhi->nodeKind = AST_EXPR_BINARY_OP;
|
|
mulhi->type = s->stmtAssign.to->expression.type;
|
|
mulhi->operator = BINOP_MULHI;
|
|
mulhi->operands[0] = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[0]);
|
|
mulhi->operands[1] = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[1]);
|
|
|
|
AST *hihalf = varify(tlc, chu, stmtPrev->statement.next, s, mulhi);
|
|
|
|
vte_precolor(hihalf->exprVar.thing, COLOR_EDX);
|
|
}
|
|
|
|
s->stmtAssign.what = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[0]);
|
|
|
|
ASTStmtAssign *redest = calloc(1, sizeof(*redest));
|
|
redest->nodeKind = AST_STMT_ASSIGN;
|
|
redest->what = originalDestination;
|
|
redest->to = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[0]);
|
|
redest->next = s->stmtAssign.next;
|
|
|
|
s->stmtAssign.next = (AST*) redest;
|
|
|
|
vte_precolor(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, COLOR_EAX);
|
|
|
|
this->effective = 1;
|
|
} else assert(because == NOT_AT_ALL_IT || because == GUCCI);
|
|
|
|
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator < BINOP_SIMPLES && !ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0])) {
|
|
// Turn this:
|
|
// a = b op c
|
|
// into
|
|
// a = b
|
|
// a = a op c
|
|
|
|
AST *assign2 = calloc(1, sizeof(ASTStmtAssign));
|
|
assign2->nodeKind = AST_STMT_ASSIGN;
|
|
assign2->stmtAssign.what = ast_deep_copy(s->stmtAssign.what);
|
|
assign2->stmtAssign.to = s->stmtAssign.to->exprBinOp.operands[0];
|
|
|
|
if(stmtPrev) {
|
|
stmtPrev->statement.next = assign2;
|
|
} else {
|
|
chu->chunk.statementFirst = assign2;
|
|
}
|
|
assign2->statement.next = s;
|
|
|
|
s->stmtAssign.to->exprBinOp.operands[0] = ast_deep_copy(s->stmtAssign.what);
|
|
|
|
this->effective = 1;
|
|
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && !is_xop(s->stmtAssign.to->exprBinOp.operands[0])) {
|
|
s->stmtAssign.to->exprBinOp.operands[0] = xopify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[0]);
|
|
this->effective = 1;
|
|
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && !is_xop(s->stmtAssign.to->exprBinOp.operands[1])) {
|
|
s->stmtAssign.to->exprBinOp.operands[1] = xopify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[1]);
|
|
this->effective = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
|
AST *n = *nptr;
|
|
|
|
if(n == tlc) {
|
|
if(tlc->chunk.functionType) {
|
|
size_t argCount = n->chunk.functionType->function.argCount;
|
|
|
|
// First argCount vtes in list are the arguments
|
|
for(size_t i = 0; i < argCount; i++) {
|
|
VarTableEntry *vte = n->chunk.vars[i];
|
|
|
|
ASTExprStackPointer *stck = calloc(1, sizeof(*stck));
|
|
stck->nodeKind = AST_EXPR_STACK_POINTER;
|
|
stck->type = type_pointer_wrap(vte->type);
|
|
|
|
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
|
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
|
offset->type = primitive_parse("u32");
|
|
offset->val = 4 + i * 4;
|
|
|
|
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
|
sum->nodeKind = AST_EXPR_BINARY_OP;
|
|
sum->type = stck->type;
|
|
sum->operands[0] = (AST*) stck;
|
|
sum->operands[1] = (AST*) offset;
|
|
sum->operator = BINOP_ADD;
|
|
|
|
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
|
deref->nodeKind = AST_EXPR_UNARY_OP;
|
|
deref->type = vte->type;
|
|
deref->operand = (AST*) sum;
|
|
deref->operator = UNOP_DEREF;
|
|
|
|
ASTExprVar *evar = calloc(1, sizeof(*evar));
|
|
evar->nodeKind = AST_EXPR_VAR;
|
|
evar->type = vte->type;
|
|
evar->thing = vte;
|
|
|
|
ASTStmtAssign *ass = calloc(1, sizeof(*ass));
|
|
ass->nodeKind = AST_STMT_ASSIGN;
|
|
ass->next = NULL;
|
|
ass->what = (AST*) evar;
|
|
ass->to = (AST*) deref;
|
|
ass->next = n->chunk.statementFirst;
|
|
|
|
if(n->chunk.statementFirst) {
|
|
n->chunk.statementFirst = ass;
|
|
} else {
|
|
assert(!n->chunk.statementLast);
|
|
n->chunk.statementFirst = n->chunk.statementLast = ass;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void decompose_symbol_record_field_access(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
|
AST *n = *nptr;
|
|
|
|
if(n->nodeKind == AST_EXPR_DOT) {
|
|
ASTExprUnaryOp *ref = calloc(1, sizeof(*ref));
|
|
ref->nodeKind = AST_EXPR_UNARY_OP;
|
|
ref->type = type_pointer_wrap(n->exprDot.a->expression.type);
|
|
ref->operator = UNOP_REF;
|
|
ref->operand = n->exprDot.a;
|
|
|
|
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
|
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
|
offset->type = primitive_parse("u32");
|
|
|
|
size_t f;
|
|
for(f = 0; f < n->exprDot.a->expression.type->record.fieldCount; f++) {
|
|
if(!strcmp(n->exprDot.a->expression.type->record.fieldNames[f], n->exprDot.b)) {
|
|
break;
|
|
}
|
|
}
|
|
assert(f < n->exprDot.a->expression.type->record.fieldCount);
|
|
|
|
offset->val = n->exprDot.a->expression.type->record.fieldOffsets[f];
|
|
|
|
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
|
sum->nodeKind = AST_EXPR_BINARY_OP;
|
|
sum->type = ref->type;
|
|
sum->operator = BINOP_ADD;
|
|
sum->operands[0] = (AST*) ref;
|
|
sum->operands[1] = (AST*) offset;
|
|
|
|
AST *cast = ast_cast_expr((AST*) sum, type_pointer_wrap(n->exprDot.a->expression.type->record.fieldTypes[f]));
|
|
|
|
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
|
deref->nodeKind = AST_EXPR_UNARY_OP;
|
|
deref->type = cast->expression.type->pointer.of;
|
|
deref->operator = UNOP_DEREF;
|
|
deref->operand = cast;
|
|
|
|
*nptr = (AST*) deref;
|
|
}
|
|
}
|
|
|
|
static bool is_pointer2pointer_cast(AST *e) {
|
|
return e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER;
|
|
}
|
|
|
|
static bool is_double_field_access(AST *e) {
|
|
return e->nodeKind == AST_EXPR_BINARY_OP && is_pointer2pointer_cast(e->exprBinOp.operands[0]) && e->exprBinOp.operands[0]->exprCast.what->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operands[0]->exprCast.what->exprBinOp.operator == e->exprBinOp.operator && e->exprBinOp.operator == BINOP_ADD && e->exprBinOp.operands[0]->exprCast.what->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && e->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE;
|
|
}
|
|
|
|
static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
|
AST *n = *nptr;
|
|
|
|
bool *success = ud;
|
|
|
|
if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_REF && n->exprUnOp.operand->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operand->exprUnOp.operator == UNOP_DEREF) {
|
|
// Turn `&*a` into `a`
|
|
|
|
*nptr = n->exprUnOp.operand->exprUnOp.operand;
|
|
|
|
*success = true;
|
|
} else if(is_double_field_access(n)) {
|
|
// Turn `(p + x) as C + y` into `(p + (x + y)) as C`
|
|
|
|
n->exprBinOp.operands[0]->exprCast.what->exprBinOp.operands[1]->exprPrim.val += n->exprBinOp.operands[1]->exprPrim.val;
|
|
|
|
*nptr = n->exprBinOp.operands[0];
|
|
|
|
*success = true;
|
|
} else if(n->nodeKind == AST_EXPR_CAST && n->exprCast.what->nodeKind == AST_EXPR_CAST) {
|
|
// Turn `(p as A) as B` to `p as B`
|
|
|
|
n->exprCast.what = n->exprCast.what->exprCast.what;
|
|
|
|
*success = true;
|
|
} else if(n->nodeKind == AST_EXPR_BINARY_OP && n->exprBinOp.operands[0]->nodeKind == AST_EXPR_BINARY_OP && n->exprBinOp.operator == BINOP_ADD && n->exprBinOp.operands[0]->exprBinOp.operator == BINOP_ADD && n->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && n->exprBinOp.operands[0]->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
|
|
// Turn `(x + a) + b` into `x + (a + b)`
|
|
|
|
n->exprBinOp.operands[0]->exprBinOp.operands[1]->exprPrim.val += n->exprBinOp.operands[1]->exprPrim.val;
|
|
|
|
*nptr = n->exprBinOp.operands[0];
|
|
|
|
*success = true;
|
|
} else if(n->nodeKind == AST_EXPR_CAST && n->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && n->exprCast.to->type == TYPE_TYPE_POINTER) {
|
|
// Turn (x as A*) into x, since all pointer types are identical in Nectar's AST
|
|
|
|
*nptr = n->exprCast.what;
|
|
|
|
*success = true;
|
|
}
|
|
}
|
|
|
|
void dumben_pre(AST *tlc) {
|
|
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor, NULL);
|
|
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, decompose_symbol_record_field_access, NULL);
|
|
|
|
for(size_t t = 0; t < tlc->chunk.varCount; t++) {
|
|
if(tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) {
|
|
ast_spill_to_stack(tlc, tlc->chunk.vars[t]);
|
|
}
|
|
}
|
|
|
|
bool success;
|
|
do {
|
|
success = false;
|
|
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor, NULL);
|
|
} while(success);
|
|
}
|
|
|
|
void dumben_go(AST* tlc) {
|
|
size_t i = 0;
|
|
while(1) {
|
|
if(i == 20000) {
|
|
puts("TOO MANY DUMBS");
|
|
abort();
|
|
}
|
|
|
|
fprintf(stderr, "; Dumbing down %lu...\n", i++);
|
|
|
|
struct DumbenState state;
|
|
memset(&state, 0, sizeof(state));
|
|
|
|
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, dumben_visitor, NULL);
|
|
|
|
int successful = state.effective;
|
|
|
|
if(!successful) {
|
|
break;
|
|
}
|
|
|
|
fputs(ast_dump(tlc), stderr);
|
|
}
|
|
}
|