#include"cg.h" #include #include #include #include #include"x86.h" #define REGS 4 static const char *regs[][3] = { [COLOR_EAX] = {"al", "ax", "eax"}, [COLOR_EBX] = {"bl", "bx", "ebx"}, [COLOR_ECX] = {"cl", "cx", "ecx"}, [COLOR_EDX] = {"dl", "dx", "edx"}, {"fu", "fk", "fck"} }; static const char *BINOP_SIMPLE_INSTRS[] = {[BINOP_ADD] = "add", [BINOP_SUB] = "sub", [BINOP_BITWISE_AND] = "and", [BINOP_BITWISE_OR] = "or", [BINOP_BITWISE_XOR] = "xor"}; static size_t nextLocalLabel = 0; typedef struct { #define LOOPSTACKSIZE 96 size_t loopStackStart[LOOPSTACKSIZE]; size_t loopStackEnd[LOOPSTACKSIZE]; size_t loopStackIdx; } CGState; static const char *direct(int size) { switch(size) { case 0: case 1: return "db"; case 2: return "dw"; case 4: return "dd"; case 8: return "dq"; } abort(); } static const char *spec(int size) { switch(size) { case 0: case 1: return "byte"; case 2: return "word"; case 4: return "dword"; case 8: return "qword"; } abort(); } static int log_size(int size) { switch(size) { case 0: case 1: return 0; case 2: return 1; case 4: return 2; case 8: return 3; } abort(); } static const char *specexpr(AST *e) { return spec(type_size(e->expression.type)); } static const char *xv_sz(VarTableEntry *v, int sz) { assert(v->kind == VARTABLEENTRY_VAR); #define XVBUFS 8 #define XVBUFSZ 8 static char bufs[XVBUFS][XVBUFSZ]; static int bufidx = 0; char *ret = bufs[bufidx]; #ifdef DEBUG snprintf(ret, XVBUFSZ, "@%i", v->data.var.color); #else snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(sz)]); #endif bufidx = (bufidx + 1) % XVBUFS; return ret; } static const char *xv(VarTableEntry *v) { return xv_sz(v, type_size(v->type)); } static const char *xj(BinaryOp op) { switch(op) { case BINOP_EQUAL: return "e"; case BINOP_NEQUAL: return "ne"; default: return "wtf"; } } static const char *xop_sz(AST *e, int sz) { #define XOPBUFS 16 #define XOPBUFSZ 24 static char bufs[XOPBUFS][XOPBUFSZ]; static int bufidx = 0; char *ret = bufs[bufidx]; if(e->nodeKind == AST_EXPR_STACK_POINTER) { snprintf(ret, XOPBUFSZ, "esp"); } else if(e->nodeKind == AST_EXPR_VAR) { VarTableEntry *v = e->exprVar.thing; if(v->kind == VARTABLEENTRY_VAR) { return xv_sz(v, sz); } else if(v->kind == VARTABLEENTRY_SYMBOL) { snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), v->data.symbol.name); } else abort(); } else if(e->nodeKind == AST_EXPR_PRIMITIVE) { snprintf(ret, XOPBUFSZ, "%i", e->exprPrim.val); } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { snprintf(ret, XOPBUFSZ, "%s [%s + %s]", spec(sz), xv_sz(e->exprUnOp.operand->exprBinOp.operands[0]->exprVar.thing, 4), xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing, 4)); } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { snprintf(ret, XOPBUFSZ, "%s [%s + %s]", spec(sz), e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing, 4)); } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]", spec(sz), e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val, xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 4)); } 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) { snprintf(ret, XOPBUFSZ, "%s", e->exprUnOp.operand->exprVar.thing->data.symbol.name); } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_VAR) { snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(e->exprUnOp.operand->exprVar.thing, 4)); } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == UNOP_DEREF && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) { snprintf(ret, XOPBUFSZ, "[esp + %i]", e->exprUnOp.operand->exprBinOp.operands[1]->exprPrim.val); } else { return NULL; } bufidx = (bufidx + 1) % XOPBUFS; return ret; } static const char *xop(AST *e) { return xop_sz(e, type_size(e->expression.type)); } void cg_chunk(CGState *cg, AST *a) { AST *s = a->chunk.statementFirst; if(a->chunk.stackReservation) { printf("sub esp, %lu\n", a->chunk.stackReservation); } // Potentially complex pattern matching while(s) { if(s->nodeKind == AST_STMT_EXT_SECTION) { Token t = s->stmtExtSection.name; printf("section %.*s\n", (int) t.length, t.content); } else if(s->nodeKind == AST_STMT_EXT_ORG) { printf("org %lu\n", s->stmtExtOrg.val); } else if(s->nodeKind == AST_STMT_EXT_ALIGN) { uint32_t val = s->stmtExtAlign.val; if((val & (val - 1))) { // nasm does not support non-PoT alignments, so pad manually printf("times ($ - $$ + %u) / %u * %u - ($ - $$) db 0\n", val - 1, val, val); } else { printf("align %u\n", val); } } else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == VARTABLEENTRY_SYMBOL) { VarTableEntry *v = s->stmtDecl.thing; if(v->data.symbol.isExternal) { printf("extern %s\n", v->data.symbol.name); } else { if(!v->data.symbol.isLocal) { printf("global %s\n", v->data.symbol.name); } if(s->stmtDecl.expression) { printf("%s:", v->data.symbol.name); if(v->type->type == TYPE_TYPE_PRIMITIVE) { assert(s->stmtDecl.expression->nodeKind == AST_EXPR_PRIMITIVE); printf("%s %i", direct(type_size(v->type)), s->stmtDecl.expression->exprPrim.val); } else if(v->type->type == TYPE_TYPE_ARRAY && v->type->array.of->type == TYPE_TYPE_PRIMITIVE) { printf("%s ", direct(type_size(v->type->array.of))); for(size_t i = 0; i < v->type->array.length; i++) { printf("%i,", s->stmtDecl.expression->exprArray.items[i]->exprPrim.val); } } else if(v->type->type == TYPE_TYPE_FUNCTION) { putchar('\n'); assert(s->stmtDecl.expression->nodeKind == AST_EXPR_FUNC); cg_go(s->stmtDecl.expression->exprFunc.chunk); } else abort(); putchar('\n'); } else { printf("%s resb %lu\n", v->data.symbol.name, type_size(s->stmtDecl.thing->type)); } } } else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { AST *e = s->stmtAssign.to; puts("push ecx"); puts("push edx"); int argCount = e->exprCall.what->expression.type->function.argCount; size_t argSize = 0; for(int i = argCount - 1; i >= 0; i--) { printf("push %s\n", xop_sz(e->exprCall.args[i], 4)); argSize += (type_size(e->exprCall.args[i]->expression.type) + 3) & ~3; } assert(e->exprCall.what->nodeKind == AST_EXPR_VAR && e->exprCall.what->exprVar.thing->kind == VARTABLEENTRY_SYMBOL); printf("call %s\n", e->exprCall.what->exprVar.thing->data.symbol.name); if(argSize) printf("add esp, %lu\n", argSize); puts("pop edx"); puts("pop ecx"); } else if(s->nodeKind == AST_STMT_ASSIGN) { if(is_xop(s->stmtAssign.what) == XOP_NOT_MEM && is_xop(s->stmtAssign.to) == XOP_NOT_MEM && !strcmp(xop(s->stmtAssign.what), xop(s->stmtAssign.to))) { // It's a noop } else 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) { // 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.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && s->stmtAssign.to->exprBinOp.operator < BINOP_SIMPLES) { printf("%s %s, %s\n", BINOP_SIMPLE_INSTRS[s->stmtAssign.to->exprBinOp.operator], xop(s->stmtAssign.what), xop(s->stmtAssign.to->exprBinOp.operands[1])); } 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 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_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR) { printf("lea %s, [%s + %i]\n", xv_sz(s->stmtAssign.what->exprVar.thing, 4), xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 4), s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val); } else if(is_xop(s->stmtAssign.what) != NULL && 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)) { printf("neg %s\n", xop(s->stmtAssign.what)); } else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST) { printf("movzx %s, %s\n", xop(s->stmtAssign.what), xop(s->stmtAssign.to->exprCast.what)); } else { if(is_xop(s->stmtAssign.to) == XOP_MEM && type_size(s->stmtAssign.what->expression.type) != type_size(s->stmtAssign.to->expression.type)) { printf("movzx %s, %s\n", xop_sz(s->stmtAssign.what, 4), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); } else { printf("mov %s, %s\n", xop(s->stmtAssign.what), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); } } } } else if(s->nodeKind == AST_STMT_LOOP) { size_t lbl0 = nextLocalLabel++; size_t lbl1 = nextLocalLabel++; cg->loopStackStart[cg->loopStackIdx] = lbl0; cg->loopStackEnd[cg->loopStackIdx] = lbl1; cg->loopStackIdx++; printf(".L%lu:\n", lbl0); cg_chunk(cg, s->stmtLoop.body); printf("jmp .L%lu\n", lbl0); printf(".L%lu:\n", lbl1); cg->loopStackIdx--; } else if(s->nodeKind == AST_STMT_BREAK) { printf("jmp .L%lu\n", cg->loopStackEnd[cg->loopStackIdx - 1]); } else if(s->nodeKind == AST_STMT_CONTINUE) { printf("jmp .L%lu\n", cg->loopStackStart[cg->loopStackIdx - 1]); } else if(s->nodeKind == AST_STMT_IF) { assert(s->stmtIf.expression->nodeKind == AST_EXPR_BINARY_OP && binop_is_comparison(s->stmtIf.expression->exprBinOp.operator)); size_t lbl = nextLocalLabel++; printf("cmp %s, %s\n", xop(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[1])); printf("j%s .L%lu\n", xj(binop_comp_opposite(s->stmtIf.expression->exprBinOp.operator)), lbl); cg_chunk(cg, s->stmtIf.then); printf(".L%lu:\n", lbl); } s = s->statement.next; } if(a->chunk.stackReservation) { printf("add esp, %lu\n", a->chunk.stackReservation); } } // MUST FIRST CALL with *aptr == tlc SO stackReservation IS UPDATED!! static void spill_pass(AST *tlc, AST **aptr, VarTableEntry *vte) { AST *a = *aptr; if(a->nodeKind == AST_CHUNK) { for(AST **s = &a->chunk.statementFirst; *s; s = &((*s)->statement.next)) { spill_pass(tlc, s, vte); } tlc->chunk.stackReservation += 4; } else if(a->nodeKind == AST_STMT_IF) { spill_pass(tlc, &a->stmtIf.expression, vte); spill_pass(tlc, &a->stmtIf.then, vte); } else if(a->nodeKind == AST_STMT_LOOP) { spill_pass(tlc, &a->stmtLoop.body, vte); } else if(a->nodeKind == AST_STMT_ASSIGN) { spill_pass(tlc, &a->stmtAssign.what, vte); if(a->stmtAssign.to) { spill_pass(tlc, &a->stmtAssign.to, vte); } } else if(a->nodeKind == AST_STMT_EXPR) { spill_pass(tlc, &a->stmtExpr.expr, vte); } else if(a->nodeKind == AST_EXPR_VAR) { if(a->exprVar.thing == vte) { // FINALLY SPILL ASTExprStackPointer *rsp = malloc(sizeof(*rsp)); rsp->nodeKind = AST_EXPR_STACK_POINTER; rsp->type = primitive_parse("u32"); ASTExprPrimitive *offset = malloc(sizeof(*offset)); offset->nodeKind = AST_EXPR_PRIMITIVE; offset->type = rsp->type; offset->val = -tlc->chunk.stackReservation; ASTExprBinaryOp *bop = malloc(sizeof(*bop)); bop->nodeKind = AST_EXPR_BINARY_OP; bop->type = rsp->type; bop->operator = BINOP_ADD; bop->operands[0] = (AST*) rsp; bop->operands[1] = (AST*) offset; ASTExprUnaryOp *deref = malloc(sizeof(*deref)); deref->nodeKind = AST_EXPR_UNARY_OP; deref->type = a->expression.type; deref->operator = UNOP_DEREF; deref->operand = (AST*) bop; *aptr = (AST*) deref; } } else if(a->nodeKind == AST_EXPR_BINARY_OP) { spill_pass(tlc, &a->exprBinOp.operands[0], vte); spill_pass(tlc, &a->exprBinOp.operands[1], vte); } else if(a->nodeKind == AST_EXPR_UNARY_OP) { spill_pass(tlc, &a->exprUnOp.operand, vte); } else if(a->nodeKind == AST_EXPR_CALL) { spill_pass(tlc, &a->exprCall.what, vte); for(size_t p = 0; p < a->exprCall.what->expression.type->function.argCount; p++) { spill_pass(tlc, &a->exprCall.args[p], vte); } } else if(a->nodeKind == AST_EXPR_PRIMITIVE) { } else if(a->nodeKind == AST_EXPR_STRING_LITERAL) { } else if(a->nodeKind == AST_EXPR_CAST) { spill_pass(tlc, &a->exprCast.what, vte); } else if(a->nodeKind == AST_EXPR_STACK_POINTER) { } else if(a->nodeKind == AST_STMT_BREAK) { } else if(a->nodeKind == AST_STMT_CONTINUE) { } else if(a->nodeKind == AST_STMT_EXT_ALIGN) { } else if(a->nodeKind == AST_STMT_EXT_ORG) { } else if(a->nodeKind == AST_STMT_EXT_SECTION) { } else if(a->nodeKind == AST_STMT_DECL) { assert(a->stmtDecl.thing->kind != VARTABLEENTRY_VAR || a->stmtDecl.expression); } else { abort(); } } 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; } /* Welsh-Powell graph coloring */ static int comparator(const void *A, const void *B) { VarTableEntry *const *a = A; VarTableEntry *const *b = B; return ((*a)->data.var.degree * (*a)->data.var.priority) - ((*b)->data.var.degree * (*b)->data.var.priority); } int cg_go(AST *a) { typedef VarTableEntry *Adjacency[2]; ast_usedef_reset(a); size_t adjCount = 0; Adjacency *adjs = calloc(adjCount, sizeof(*adjs)); VarTableEntry **vars = a->chunk.vars; for(size_t vi = 0; vi < a->chunk.varCount; vi++) { vars[vi]->data.var.priority = 1; //vars[vi]->data.var.color = 0; vars[vi]->data.var.degree = 0; } for(size_t v1i = 0; v1i < a->chunk.varCount; v1i++) { for(size_t v2i = 0; v2i < a->chunk.varCount; v2i++) { if(v1i == v2i) continue; VarTableEntry *v1 = vars[v1i]; VarTableEntry *v2 = vars[v2i]; /* 1D intersection test */ if(!ud_empty(v1) && !ud_empty(v2) && ( (ast_stmt_is_after(a, v1->data.var.usedefFirst->stmt, v2->data.var.usedefFirst->stmt) == 1 && ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefFirst->stmt) == 1) || (ast_stmt_is_after(a, v1->data.var.usedefLast->stmt, v2->data.var.usedefFirst->stmt) == 1 && ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefLast->stmt) == 1) )) { VarTableEntry *min = v1 < v2 ? v1 : v2; VarTableEntry *max = v1 < v2 ? v2 : v1; for(size_t a = 0; a < adjCount; a++) { if(adjs[a][0] == min && adjs[a][1] == max) { goto cont; } } adjs = realloc(adjs, sizeof(*adjs) * ++adjCount); adjs[adjCount - 1][0] = min; adjs[adjCount - 1][1] = max; cont:; } } } for(size_t a = 0; a < adjCount; a++) { adjs[a][0]->data.var.degree++; adjs[a][1]->data.var.degree++; } qsort(vars, a->chunk.varCount, sizeof(*vars), comparator); int lastColor = 0; /* Welsh plow my ass */ for(int v = 0; v < a->chunk.varCount; v++) { if(vars[v]->data.var.color != -1) { // Already assigned. continue; } for(int c = 0;; c++) { for(int a = 0; a < adjCount; a++) { if(adjs[a][0] == vars[v] && adjs[a][1]->data.var.color != -1 && adjs[a][1]->data.var.color == c) { goto nextColor; } else if(adjs[a][1] == vars[v] && adjs[a][0]->data.var.color != -1 && adjs[a][0]->data.var.color == c) { goto nextColor; } } vars[v]->data.var.color = c; lastColor = lastColor < c ? c : lastColor; break; nextColor:; } } free(adjs); if(lastColor >= 4) { // Spill node with highest degree spill_pass(a, &a, vars[a->chunk.varCount - 1]); return 0; } CGState cg; memset(&cg, 0, sizeof(cg)); cg_chunk(&cg, a); return 1; }