2023-08-27 19:48:06 +03:00
|
|
|
#include"cg.h"
|
|
|
|
|
|
|
|
#include<stdlib.h>
|
|
|
|
#include<signal.h>
|
|
|
|
#include<string.h>
|
|
|
|
#include<assert.h>
|
2025-06-10 22:07:22 +03:00
|
|
|
#include"dumberdowner.h"
|
|
|
|
#include"reporting.h"
|
|
|
|
#include"ast.h"
|
2023-08-27 19:48:06 +03:00
|
|
|
|
2024-06-12 11:17:09 +03:00
|
|
|
#include"x86.h"
|
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
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;
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
typedef struct {
|
2024-02-13 21:33:49 +02:00
|
|
|
#define LOOPSTACKSIZE 96
|
2024-11-26 18:42:20 +02:00
|
|
|
size_t loopStackStart[LOOPSTACKSIZE];
|
|
|
|
size_t loopStackEnd[LOOPSTACKSIZE];
|
|
|
|
size_t loopStackIdx;
|
2024-12-14 18:13:33 +02:00
|
|
|
|
|
|
|
int isFunction;
|
|
|
|
|
|
|
|
AST *tlc;
|
2024-11-26 18:42:20 +02:00
|
|
|
} CGState;
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
static const char *direct(int size) {
|
|
|
|
switch(size) {
|
2024-11-25 17:36:03 +02:00
|
|
|
case 0:
|
2023-08-27 19:48:06 +03:00
|
|
|
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) {
|
2024-11-25 17:36:03 +02:00
|
|
|
case 0:
|
2023-08-27 19:48:06 +03:00
|
|
|
case 1: return "byte";
|
|
|
|
case 2: return "word";
|
|
|
|
case 4: return "dword";
|
|
|
|
case 8: return "qword";
|
|
|
|
}
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
/*static int log_size(int size) {
|
2024-02-13 21:33:49 +02:00
|
|
|
switch(size) {
|
2024-11-25 17:36:03 +02:00
|
|
|
case 0:
|
2024-02-13 21:33:49 +02:00
|
|
|
case 1: return 0;
|
|
|
|
case 2: return 1;
|
|
|
|
case 4: return 2;
|
|
|
|
case 8: return 3;
|
|
|
|
}
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
static const char *specexpr(AST *e) {
|
|
|
|
return spec(type_size(e->expression.type));
|
2025-06-10 22:07:22 +03:00
|
|
|
}*/
|
2023-08-27 19:48:06 +03:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
static const char *xv_sz(ScopeItem *v, int sz) {
|
|
|
|
assert(v->kind == SCOPEITEM_VAR);
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
#define XVBUFS 8
|
2025-06-10 22:07:22 +03:00
|
|
|
#define XVBUFSZ 16
|
2023-08-27 19:48:06 +03:00
|
|
|
static char bufs[XVBUFS][XVBUFSZ];
|
|
|
|
static int bufidx = 0;
|
|
|
|
|
|
|
|
char *ret = bufs[bufidx];
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
if(ntc_get_int("rcd")) {
|
|
|
|
snprintf(ret, XVBUFSZ, "%i@%i", v->data.var.registerClass, v->data.var.color);
|
|
|
|
} else {
|
|
|
|
int cls = v->data.var.registerClass, reg = v->data.var.color;
|
|
|
|
|
|
|
|
if(type_size(v->type) != sz) {
|
|
|
|
if(sz == 4) {
|
|
|
|
reg_cast_up(&cls, ®);
|
|
|
|
} else abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(ret, XVBUFSZ, "%s", REG_CLASSES[cls].rsN[reg]);
|
|
|
|
}
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
bufidx = (bufidx + 1) % XVBUFS;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
static const char *xv(ScopeItem *v) {
|
2024-06-12 11:17:09 +03:00
|
|
|
return xv_sz(v, type_size(v->type));
|
|
|
|
}
|
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
static const char *xj(BinaryOp op) {
|
|
|
|
switch(op) {
|
|
|
|
case BINOP_EQUAL: return "e";
|
|
|
|
case BINOP_NEQUAL: return "ne";
|
2024-12-14 18:13:33 +02:00
|
|
|
case BINOP_LESS: return "b";
|
|
|
|
case BINOP_GREATER: return "a";
|
|
|
|
case BINOP_LEQUAL: return "be";
|
|
|
|
case BINOP_GEQUAL: return "ae";
|
2025-02-27 20:10:02 +02:00
|
|
|
default: abort(); return NULL;
|
2023-08-27 19:48:06 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-27 20:10:02 +02:00
|
|
|
static AST *is_field_access(AST *e) {
|
|
|
|
if(e->nodeKind != AST_EXPR_UNARY_OP || e->exprUnOp.operator != UNOP_DEREF) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
e = e->exprUnOp.operand;
|
|
|
|
|
|
|
|
if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) {
|
|
|
|
e = e->exprCast.what;
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_ADD && e->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && e->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == SCOPEITEM_SYMBOL) {
|
2025-02-27 20:10:02 +02:00
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_ADD && e->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && e->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && e->exprBinOp.operands[0]->exprVar.thing->kind == SCOPEITEM_VAR) {
|
2025-05-03 09:59:30 +03:00
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2025-02-27 20:10:02 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
static const char *xop_sz(AST *tlc, AST *e, int sz) {
|
2023-08-27 19:48:06 +03:00
|
|
|
#define XOPBUFS 16
|
|
|
|
#define XOPBUFSZ 24
|
|
|
|
static char bufs[XOPBUFS][XOPBUFSZ];
|
|
|
|
static int bufidx = 0;
|
|
|
|
|
|
|
|
char *ret = bufs[bufidx];
|
|
|
|
|
2025-05-03 09:59:30 +03:00
|
|
|
//if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) {
|
2025-06-10 22:07:22 +03:00
|
|
|
/*if(e->nodeKind == AST_EXPR_CAST) {
|
2025-02-27 20:10:02 +02:00
|
|
|
e = e->exprCast.what;
|
2025-06-10 22:07:22 +03:00
|
|
|
}*/
|
2025-02-27 20:10:02 +02:00
|
|
|
|
|
|
|
if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
|
|
|
|
AST *p = e->exprUnOp.operand;
|
|
|
|
|
|
|
|
if(p->nodeKind == AST_EXPR_CAST && p->exprCast.to->type == TYPE_TYPE_POINTER) {
|
|
|
|
p = p->exprCast.what;
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprVar.thing->kind == SCOPEITEM_VAR && p->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_VAR) {
|
2025-02-27 20:10:02 +02:00
|
|
|
snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
|
|
|
|
spec(sz),
|
|
|
|
xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 4),
|
|
|
|
xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 4));
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && p->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == SCOPEITEM_SYMBOL && p->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_VAR) {
|
2025-02-27 20:10:02 +02:00
|
|
|
snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
|
|
|
|
spec(sz),
|
|
|
|
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
|
|
|
xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 4));
|
|
|
|
} else if(is_field_access(e)) {
|
|
|
|
e = is_field_access(e);
|
2025-05-03 09:59:30 +03:00
|
|
|
|
|
|
|
if(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP) {
|
|
|
|
assert(e->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF);
|
|
|
|
|
|
|
|
snprintf(ret, XOPBUFSZ, "%s [%s + %i]",
|
|
|
|
spec(sz),
|
|
|
|
e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
|
|
|
e->exprBinOp.operands[1]->exprPrim.val);
|
|
|
|
} else {
|
|
|
|
assert(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR);
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *vte = e->exprBinOp.operands[0]->exprVar.thing;
|
|
|
|
|
2025-05-03 09:59:30 +03:00
|
|
|
snprintf(ret, XOPBUFSZ, "%s [%s + %i]",
|
|
|
|
spec(sz),
|
2025-06-10 22:07:22 +03:00
|
|
|
REG_CLASSES[vte->data.var.registerClass].rsN[vte->data.var.color],
|
2025-05-03 09:59:30 +03:00
|
|
|
e->exprBinOp.operands[1]->exprPrim.val);
|
|
|
|
}
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && p->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == SCOPEITEM_SYMBOL && p->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && p->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_VAR) {
|
2025-02-27 20:10:02 +02:00
|
|
|
snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]",
|
|
|
|
spec(sz),
|
|
|
|
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
|
|
|
p->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val,
|
|
|
|
xv_sz(p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 4));
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(p->nodeKind == AST_EXPR_VAR && p->exprVar.thing->kind == SCOPEITEM_VAR) {
|
2025-02-27 20:10:02 +02:00
|
|
|
snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(p->exprVar.thing, 4));
|
|
|
|
} else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
|
|
|
|
snprintf(ret, XOPBUFSZ, "[esp + %i]", p->exprBinOp.operands[1]->exprPrim.val);
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if(e->nodeKind == AST_EXPR_STACK_POINTER) {
|
2025-06-10 22:07:22 +03:00
|
|
|
snprintf(ret, XOPBUFSZ, "esp");
|
2024-11-20 16:36:17 +02:00
|
|
|
} else if(e->nodeKind == AST_EXPR_VAR) {
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *v = e->exprVar.thing;
|
2023-08-27 19:48:06 +03:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
if(v->kind == SCOPEITEM_VAR) {
|
2024-06-12 11:17:09 +03:00
|
|
|
return xv_sz(v, sz);
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(v->kind == SCOPEITEM_SYMBOL) {
|
2024-11-25 18:35:11 +02:00
|
|
|
snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), v->data.symbol.name);
|
2023-08-27 19:48:06 +03:00
|
|
|
} else abort();
|
|
|
|
} else if(e->nodeKind == AST_EXPR_PRIMITIVE) {
|
2025-02-27 20:10:02 +02:00
|
|
|
snprintf(ret, XOPBUFSZ, "%s %i", spec(type_size(e->exprPrim.type)), e->exprPrim.val);
|
2025-06-10 22:07:22 +03:00
|
|
|
} 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 == SCOPEITEM_SYMBOL) {
|
2023-08-27 19:48:06 +03:00
|
|
|
snprintf(ret, XOPBUFSZ, "%s", e->exprUnOp.operand->exprVar.thing->data.symbol.name);
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bufidx = (bufidx + 1) % XOPBUFS;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
static const char *xop(AST *tlc, AST *e) {
|
|
|
|
return xop_sz(tlc, e, type_size(e->expression.type));
|
2024-06-12 11:17:09 +03:00
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
static int ud_empty(ScopeItem *a) {
|
|
|
|
assert(a->kind == SCOPEITEM_VAR);
|
2025-01-02 18:04:57 +02:00
|
|
|
assert(!a->data.var.usedefFirst == !a->data.var.usedefLast);
|
|
|
|
|
|
|
|
return !a->data.var.usedefFirst;
|
|
|
|
}
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
void cg_chunk(CGState *cg, AST *a) {
|
2023-08-27 19:48:06 +03:00
|
|
|
AST *s = a->chunk.statementFirst;
|
|
|
|
|
2024-11-25 17:36:03 +02:00
|
|
|
if(a->chunk.stackReservation) {
|
|
|
|
printf("sub esp, %lu\n", a->chunk.stackReservation);
|
|
|
|
}
|
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
// 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);
|
|
|
|
|
2024-02-13 21:33:49 +02:00
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == SCOPEITEM_SYMBOL) {
|
|
|
|
ScopeItem *v = s->stmtDecl.thing;
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
if(v->data.symbol.isExternal) {
|
2025-05-03 09:59:30 +03:00
|
|
|
// Do nothing.
|
|
|
|
// All external symbols are handled at once in the top-level chunk.
|
|
|
|
//printf("extern %s\n", v->data.symbol.name);
|
2023-08-27 19:48:06 +03:00
|
|
|
} else {
|
|
|
|
if(!v->data.symbol.isLocal) {
|
|
|
|
printf("global %s\n", v->data.symbol.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(s->stmtDecl.expression) {
|
2024-02-13 21:33:49 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
} else if(v->type->type == TYPE_TYPE_FUNCTION) {
|
|
|
|
|
|
|
|
putchar('\n');
|
|
|
|
|
|
|
|
assert(s->stmtDecl.expression->nodeKind == AST_EXPR_FUNC);
|
|
|
|
|
2025-05-03 09:59:30 +03:00
|
|
|
// Generic functions have non-NULL code blocks
|
|
|
|
if(!type_is_generic(s->stmtDecl.expression->expression.type)) {
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
dumben_pre(s->stmtDecl.expression->exprFunc.chunk);
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
dumben_go(s->stmtDecl.expression->exprFunc.chunk);
|
2025-05-03 09:59:30 +03:00
|
|
|
while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) {
|
|
|
|
dumben_go(s->stmtDecl.expression->exprFunc.chunk);
|
|
|
|
}
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
}
|
2024-11-26 18:42:20 +02:00
|
|
|
|
|
|
|
} else abort();
|
2024-02-13 21:33:49 +02:00
|
|
|
putchar('\n');
|
2023-08-27 19:48:06 +03:00
|
|
|
} else {
|
2024-02-13 21:33:49 +02:00
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
printf("%s resb %lu\n", v->data.symbol.name, type_size(s->stmtDecl.thing->type));
|
2024-02-13 21:33:49 +02:00
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
}
|
|
|
|
}
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.to && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
2024-11-25 17:36:03 +02:00
|
|
|
|
|
|
|
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--) {
|
2024-12-14 18:13:33 +02:00
|
|
|
printf("push %s\n", xop_sz(cg->tlc, e->exprCall.args[i], 4));
|
2024-11-25 17:36:03 +02:00
|
|
|
|
|
|
|
argSize += (type_size(e->exprCall.args[i]->expression.type) + 3) & ~3;
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
assert(e->exprCall.what->nodeKind == AST_EXPR_VAR && e->exprCall.what->exprVar.thing->kind == SCOPEITEM_SYMBOL);
|
2024-11-25 17:36:03 +02:00
|
|
|
|
|
|
|
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");
|
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
if(s->stmtAssign.to && is_xop(s->stmtAssign.what) == XOP_NOT_MEM && is_xop(s->stmtAssign.to) == XOP_NOT_MEM && !strcmp(xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to))) {
|
2024-11-25 17:36:03 +02:00
|
|
|
// It's a noop
|
|
|
|
} else if(s->stmtAssign.to) {
|
2025-02-27 20:10:02 +02:00
|
|
|
if(x86_imul_supported() && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) {
|
|
|
|
assert(s->stmtAssign.what->nodeKind == AST_EXPR_VAR);
|
2025-06-10 22:07:22 +03:00
|
|
|
assert(s->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR);
|
2025-02-27 20:10:02 +02:00
|
|
|
|
|
|
|
if(!strcmp(xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[0]))) {
|
2025-06-10 22:07:22 +03:00
|
|
|
printf("imul %s, %s, %s\n", xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[1]));
|
2025-02-27 20:10:02 +02:00
|
|
|
} else {
|
|
|
|
printf("imul %s, %s, %s\n", xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[0]), xop(a, s->stmtAssign.to->exprBinOp.operands[1]));
|
|
|
|
}
|
|
|
|
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MULHI) {
|
|
|
|
assert(s->stmtAssign.what->nodeKind == AST_EXPR_VAR);
|
2025-06-10 22:07:22 +03:00
|
|
|
assert(s->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR);
|
|
|
|
//assert(s->stmtAssign.what->exprVar.thing->data.var.color == COLOR_EDX);
|
2025-02-27 20:10:02 +02:00
|
|
|
|
|
|
|
assert(s->statement.next->nodeKind == AST_STMT_ASSIGN);
|
|
|
|
assert(s->statement.next->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP);
|
|
|
|
assert(s->statement.next->stmtAssign.to->exprBinOp.operator == BINOP_MUL);
|
|
|
|
|
|
|
|
AST *otherop = NULL;
|
|
|
|
if(ast_expression_equal(s->statement.next->stmtAssign.to->exprBinOp.operands[0], s->statement.next->stmtAssign.what)) {
|
|
|
|
otherop = s->statement.next->stmtAssign.to->exprBinOp.operands[1];
|
|
|
|
} else if(ast_expression_equal(s->statement.next->stmtAssign.to->exprBinOp.operands[1], s->statement.next->stmtAssign.what)) {
|
|
|
|
otherop = s->statement.next->stmtAssign.to->exprBinOp.operands[0];
|
|
|
|
} else abort();
|
|
|
|
|
|
|
|
printf("mul %s\n", xop(a, otherop));
|
|
|
|
|
|
|
|
// Skip next statement, because they come in a pair
|
|
|
|
s = s->statement.next;
|
|
|
|
|
|
|
|
} 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_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) {
|
2023-08-27 19:48:06 +03:00
|
|
|
|
2024-02-15 22:33:06 +02:00
|
|
|
// inc or dec
|
|
|
|
|
|
|
|
static const char *instrs[] = {"inc", "dec"};
|
2024-12-14 18:13:33 +02:00
|
|
|
printf("%s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], xop(cg->tlc, s->stmtAssign.what));
|
2024-02-15 22:33:06 +02:00
|
|
|
|
2024-11-20 16:36:17 +02:00
|
|
|
} 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) {
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
printf("%s %s, %s\n", BINOP_SIMPLE_INSTRS[s->stmtAssign.to->exprBinOp.operator], xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to->exprBinOp.operands[1]));
|
2024-11-20 16:36:17 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
} 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 == SCOPEITEM_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_VAR) {
|
2024-02-15 22:33:06 +02:00
|
|
|
|
|
|
|
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));
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
} 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 == SCOPEITEM_SYMBOL && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_VAR) {
|
2024-02-15 22:33:06 +02:00
|
|
|
|
|
|
|
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));
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
} 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 == SCOPEITEM_VAR) {
|
2024-06-12 11:17:09 +03:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(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)) {
|
2024-06-12 11:17:09 +03:00
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
printf("neg %s\n", xop(cg->tlc, s->stmtAssign.what));
|
2024-11-20 16:36:17 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST) {
|
2024-06-12 11:17:09 +03:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
if(type_size(s->stmtAssign.what->expression.type) > type_size(s->stmtAssign.to->expression.type)) {
|
|
|
|
|
|
|
|
printf("movzx %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to->exprCast.what));
|
|
|
|
|
2024-06-12 11:17:09 +03:00
|
|
|
} else {
|
2025-06-10 22:07:22 +03:00
|
|
|
|
|
|
|
const char *dest = xop_sz(cg->tlc, s->stmtAssign.what, 4);
|
|
|
|
const char *src = xop_sz(cg->tlc, s->stmtAssign.to->exprCast.what, 4);
|
|
|
|
|
|
|
|
if(strcmp(dest, src)) {
|
|
|
|
printf("mov %s, %s\n", dest, src);
|
|
|
|
}
|
|
|
|
|
2024-06-12 11:17:09 +03:00
|
|
|
}
|
2024-02-15 22:33:06 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
} else {
|
|
|
|
|
|
|
|
printf("mov %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to));
|
|
|
|
|
2024-02-15 22:33:06 +02:00
|
|
|
}
|
2023-08-27 19:48:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} else if(s->nodeKind == AST_STMT_LOOP) {
|
|
|
|
|
|
|
|
size_t lbl0 = nextLocalLabel++;
|
|
|
|
size_t lbl1 = nextLocalLabel++;
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
cg->loopStackStart[cg->loopStackIdx] = lbl0;
|
|
|
|
cg->loopStackEnd[cg->loopStackIdx] = lbl1;
|
|
|
|
cg->loopStackIdx++;
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
printf(".L%lu:\n", lbl0);
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
cg_chunk(cg, s->stmtLoop.body);
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
printf("jmp .L%lu\n", lbl0);
|
|
|
|
|
|
|
|
printf(".L%lu:\n", lbl1);
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
cg->loopStackIdx--;
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
} else if(s->nodeKind == AST_STMT_BREAK) {
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
printf("jmp .L%lu\n", cg->loopStackEnd[cg->loopStackIdx - 1]);
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
} else if(s->nodeKind == AST_STMT_CONTINUE) {
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
printf("jmp .L%lu\n", cg->loopStackStart[cg->loopStackIdx - 1]);
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
} 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++;
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
printf("cmp %s, %s\n", xop(cg->tlc, s->stmtIf.expression->exprBinOp.operands[0]), xop(cg->tlc, s->stmtIf.expression->exprBinOp.operands[1]));
|
2023-08-27 19:48:06 +03:00
|
|
|
printf("j%s .L%lu\n", xj(binop_comp_opposite(s->stmtIf.expression->exprBinOp.operator)), lbl);
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
cg_chunk(cg, s->stmtIf.then);
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
printf(".L%lu:\n", lbl);
|
|
|
|
|
2024-11-28 21:40:03 +02:00
|
|
|
} else if(s->nodeKind == AST_STMT_RETURN) {
|
|
|
|
|
|
|
|
if(s->stmtReturn.val) {
|
|
|
|
assert(s->stmtReturn.val->nodeKind == AST_EXPR_VAR);
|
2025-06-10 22:07:22 +03:00
|
|
|
assert(s->stmtReturn.val->exprVar.thing->kind == SCOPEITEM_VAR);
|
|
|
|
//assert(s->stmtReturn.val->exprVar.thing->data.var.color == COLOR_EAX);
|
2024-11-28 21:40:03 +02:00
|
|
|
}
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
if(a->chunk.stackReservation) {
|
|
|
|
printf("add esp, %lu\n", a->chunk.stackReservation);
|
|
|
|
}
|
|
|
|
|
2024-11-28 21:40:03 +02:00
|
|
|
printf("ret\n");
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_VAR) {
|
|
|
|
|
|
|
|
/* Loop guard, probably. */
|
|
|
|
|
2025-05-03 09:59:30 +03:00
|
|
|
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_UNARY_OP && s->stmtExpr.expr->exprUnOp.operator == UNOP_DEREF && s->stmtExpr.expr->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
|
|
|
|
|
|
|
|
/* Loop guard for a spilled variable, probably. */
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
stahp_node(s, "Unknown statement caught by code generator.");
|
|
|
|
|
|
|
|
}
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
s = s->statement.next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
struct Spill2VarState {
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *target;
|
2024-12-14 18:13:33 +02:00
|
|
|
};
|
|
|
|
static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
|
|
|
static size_t vidx = 0;
|
|
|
|
|
|
|
|
struct Spill2VarState *this = ud;
|
|
|
|
|
2024-11-25 17:36:03 +02:00
|
|
|
AST *a = *aptr;
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
if(a->nodeKind == AST_STMT_ASSIGN && a->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
2025-06-10 22:07:22 +03:00
|
|
|
assert(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR);
|
2024-12-14 18:13:33 +02:00
|
|
|
|
|
|
|
if(a->stmtAssign.what->exprVar.thing == this->target) {
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *new = calloc(1, sizeof(*new));
|
|
|
|
new->kind = SCOPEITEM_VAR;
|
2024-12-14 18:13:33 +02:00
|
|
|
new->type = a->stmtAssign.what->exprVar.thing->type;
|
|
|
|
new->data.var.name = malp("$s2v_%lu", vidx++);
|
|
|
|
|
|
|
|
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
|
|
|
|
tlc->chunk.vars[tlc->chunk.varCount - 1] = new;
|
|
|
|
|
|
|
|
ASTExprVar *ev0 = calloc(1, sizeof(*ev0));
|
|
|
|
ev0->nodeKind = AST_EXPR_VAR;
|
|
|
|
ev0->type = new->type;
|
|
|
|
ev0->thing = a->stmtAssign.what->exprVar.thing;
|
|
|
|
|
|
|
|
ASTExprVar *ev1 = calloc(1, sizeof(*ev1));
|
|
|
|
ev1->nodeKind = AST_EXPR_VAR;
|
|
|
|
ev1->type = new->type;
|
|
|
|
ev1->thing = new;
|
|
|
|
|
|
|
|
ASTStmtAssign *ass = calloc(1, sizeof(*ass));
|
|
|
|
ass->nodeKind = AST_STMT_ASSIGN;
|
|
|
|
ass->what = (AST*) ev0;
|
|
|
|
ass->to = (AST*) ev1;
|
|
|
|
|
|
|
|
a->stmtAssign.what->exprVar.thing = new;
|
|
|
|
|
|
|
|
ass->next = a->statement.next;
|
|
|
|
a->statement.next = (AST*) ass;
|
|
|
|
|
|
|
|
if(!ass->next) {
|
|
|
|
chunk->chunk.statementLast = (AST*) ass;
|
|
|
|
}
|
|
|
|
|
2024-11-20 16:36:17 +02:00
|
|
|
}
|
2024-12-14 18:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(a->nodeKind == AST_STMT_RETURN && a->stmtReturn.val && a->stmtReturn.val->nodeKind == AST_EXPR_VAR && a->stmtReturn.val->exprVar.thing == this->target) {
|
2024-11-20 16:36:17 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *new = calloc(1, sizeof(*new));
|
|
|
|
new->kind = SCOPEITEM_VAR;
|
2024-12-14 18:13:33 +02:00
|
|
|
new->type = a->stmtReturn.val->exprVar.thing->type;
|
|
|
|
new->data.var.name = malp("$s2v_%lu", vidx++);
|
|
|
|
|
|
|
|
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
|
|
|
|
tlc->chunk.vars[tlc->chunk.varCount - 1] = new;
|
|
|
|
|
|
|
|
ASTExprVar *ev0 = calloc(1, sizeof(*ev0));
|
|
|
|
ev0->nodeKind = AST_EXPR_VAR;
|
|
|
|
ev0->type = new->type;
|
|
|
|
ev0->thing = a->stmtReturn.val->exprVar.thing;
|
|
|
|
|
|
|
|
ASTExprVar *ev1 = calloc(1, sizeof(*ev1));
|
|
|
|
ev1->nodeKind = AST_EXPR_VAR;
|
|
|
|
ev1->type = new->type;
|
|
|
|
ev1->thing = new;
|
|
|
|
|
|
|
|
ASTStmtAssign *ass = calloc(1, sizeof(*ass));
|
|
|
|
ass->nodeKind = AST_STMT_ASSIGN;
|
|
|
|
ass->what = (AST*) ev1;
|
|
|
|
ass->to = (AST*) ev0;
|
|
|
|
|
|
|
|
stmt->stmtReturn.val->exprVar.thing = new;
|
|
|
|
|
|
|
|
ass->next = stmt;
|
|
|
|
|
|
|
|
if(stmtPrev) {
|
|
|
|
stmtPrev->statement.next = (AST*) ass;
|
|
|
|
} else {
|
|
|
|
chunk->chunk.statementFirst = (AST*) ass;
|
2024-11-20 16:36:17 +02:00
|
|
|
}
|
2024-12-14 18:13:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
/*struct PrecolorState {
|
|
|
|
ScopeItem *mustBeSpilled;
|
2025-01-02 18:04:57 +02:00
|
|
|
};
|
2024-12-14 18:13:33 +02:00
|
|
|
static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
2025-01-02 18:04:57 +02:00
|
|
|
struct PrecolorState *this = ud;
|
|
|
|
|
|
|
|
if(this->mustBeSpilled) {
|
2025-06-10 22:07:22 +03:00
|
|
|
// Since something must be spilled first, we can't do anything else. Quit ASAP.
|
2025-01-02 18:04:57 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
AST *n = *nptr;
|
|
|
|
|
|
|
|
if(n == tlc) {
|
|
|
|
for(size_t i = 0; i < n->chunk.varCount; i++) {
|
|
|
|
n->chunk.vars[i]->data.var.color = -1;
|
|
|
|
n->chunk.vars[i]->data.var.precolored = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-27 20:10:02 +02:00
|
|
|
if(n->nodeKind == AST_STMT_RETURN && n->stmtReturn.val) {
|
2025-06-10 22:07:22 +03:00
|
|
|
assert(n->stmtReturn.val->nodeKind == AST_EXPR_VAR && n->stmtReturn.val->exprVar.thing->kind == SCOPEITEM_VAR);
|
2025-02-27 20:10:02 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *vte = n->stmtReturn.val->exprVar.thing;
|
2025-02-27 20:10:02 +02:00
|
|
|
|
|
|
|
const int requiredColor = COLOR_EAX;
|
|
|
|
|
|
|
|
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
|
|
|
// Precoloring collision!
|
|
|
|
this->mustBeSpilled = vte;
|
|
|
|
return;
|
2024-12-14 18:13:33 +02:00
|
|
|
}
|
2025-02-27 20:10:02 +02:00
|
|
|
|
|
|
|
vte->data.var.color = requiredColor;
|
|
|
|
vte->data.var.precolored = true;
|
2024-12-14 18:13:33 +02:00
|
|
|
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
2025-06-10 22:07:22 +03:00
|
|
|
assert(n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR);
|
2024-12-14 18:13:33 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *vte = n->stmtAssign.what->exprVar.thing;
|
2024-12-14 18:13:33 +02:00
|
|
|
|
2025-01-02 18:04:57 +02:00
|
|
|
const int requiredColor = COLOR_EAX;
|
2024-12-14 18:13:33 +02:00
|
|
|
|
2025-01-02 18:04:57 +02:00
|
|
|
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
|
|
|
// Precoloring collision!
|
|
|
|
this->mustBeSpilled = vte;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-02-27 20:10:02 +02:00
|
|
|
vte->data.var.color = requiredColor;
|
|
|
|
vte->data.var.precolored = true;
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MUL) {
|
2025-02-27 20:10:02 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *vte = n->stmtAssign.what->exprVar.thing;
|
2025-02-27 20:10:02 +02:00
|
|
|
|
|
|
|
const int requiredColor = COLOR_EAX;
|
|
|
|
|
|
|
|
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
|
|
|
// Precoloring collision!
|
|
|
|
this->mustBeSpilled = vte;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vte->data.var.color = requiredColor;
|
|
|
|
vte->data.var.precolored = true;
|
2025-06-10 22:07:22 +03:00
|
|
|
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MULHI) {
|
2025-02-27 20:10:02 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *vte = n->stmtAssign.what->exprVar.thing;
|
2025-02-27 20:10:02 +02:00
|
|
|
|
|
|
|
const int requiredColor = COLOR_EDX;
|
|
|
|
|
|
|
|
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
|
|
|
// Precoloring collision!
|
|
|
|
this->mustBeSpilled = vte;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-01-02 18:04:57 +02:00
|
|
|
vte->data.var.color = requiredColor;
|
2024-12-14 18:13:33 +02:00
|
|
|
vte->data.var.precolored = true;
|
|
|
|
}
|
2025-06-10 22:07:22 +03:00
|
|
|
}*/
|
2024-12-14 18:13:33 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
typedef ScopeItem *Adjacency[2];
|
2024-12-14 18:13:33 +02:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) {
|
2024-12-14 18:13:33 +02:00
|
|
|
/* 1D intersection test */
|
2025-06-10 22:07:22 +03:00
|
|
|
bool liveRangeIntersection = !ud_empty(v1) && !ud_empty(v2) && (
|
2024-12-14 18:13:33 +02:00
|
|
|
(ast_stmt_is_after(tlc, v1->data.var.usedefFirst->stmt, v2->data.var.usedefFirst->stmt) == 1
|
|
|
|
&& ast_stmt_is_after(tlc, v2->data.var.usedefLast->stmt, v1->data.var.usedefFirst->stmt) == 1)
|
|
|
|
||
|
|
|
|
(ast_stmt_is_after(tlc, v1->data.var.usedefLast->stmt, v2->data.var.usedefFirst->stmt) == 1
|
|
|
|
&& ast_stmt_is_after(tlc, v2->data.var.usedefLast->stmt, v1->data.var.usedefLast->stmt) == 1)
|
|
|
|
);
|
2025-06-10 22:07:22 +03:00
|
|
|
|
|
|
|
bool resourceIntersection = (REG_CLASSES[v1->data.var.registerClass].rMask & REG_CLASSES[v2->data.var.registerClass].rMask) != 0;
|
|
|
|
|
|
|
|
return liveRangeIntersection && resourceIntersection;
|
2024-12-14 18:13:33 +02:00
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
/*static ScopeItem *get_precolor_spill_candidate(AST *tlc) {
|
2024-12-14 18:13:33 +02:00
|
|
|
Adjacency *adjs = NULL;
|
|
|
|
size_t adjCount = 0;
|
|
|
|
|
|
|
|
for(size_t i = 0; i < tlc->chunk.varCount; i++) {
|
|
|
|
tlc->chunk.vars[i]->data.var.degree = 0;
|
|
|
|
|
|
|
|
for(size_t j = 0; j < tlc->chunk.varCount; j++) {
|
|
|
|
|
|
|
|
if( tlc->chunk.vars[i]->data.var.precolored
|
|
|
|
&& tlc->chunk.vars[j]->data.var.precolored
|
|
|
|
&& tlc->chunk.vars[i]->data.var.color == tlc->chunk.vars[j]->data.var.color
|
|
|
|
&& var_collision(tlc, tlc->chunk.vars[i], tlc->chunk.vars[j])) {
|
|
|
|
|
|
|
|
adjs = realloc(adjs, sizeof(*adjs) * ++adjCount);
|
|
|
|
|
|
|
|
adjs[adjCount - 1][0] = tlc->chunk.vars[i];
|
|
|
|
adjs[adjCount - 1][1] = tlc->chunk.vars[j];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(adjCount == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(size_t a = 0; a < adjCount; a++) {
|
|
|
|
adjs[a][0]->data.var.degree++;
|
|
|
|
adjs[a][1]->data.var.degree++;
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *maxdeg = tlc->chunk.vars[0];
|
2024-12-14 18:13:33 +02:00
|
|
|
|
|
|
|
for(size_t v = 1; v < tlc->chunk.varCount; v++) {
|
|
|
|
if(maxdeg->data.var.degree < tlc->chunk.vars[v]->data.var.degree) {
|
|
|
|
maxdeg = tlc->chunk.vars[v];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(adjs);
|
|
|
|
|
|
|
|
return maxdeg;
|
2025-06-10 22:07:22 +03:00
|
|
|
}*/
|
2024-12-14 18:13:33 +02:00
|
|
|
|
|
|
|
struct CalleeSavedState {
|
|
|
|
AST *targetTLC;
|
2025-06-10 22:07:22 +03:00
|
|
|
|
|
|
|
ScopeItem *calleeUsers[MAX_REGS_PER_CLASS];
|
|
|
|
size_t calleeOffsets[MAX_REGS_PER_CLASS];
|
2024-12-14 18:13:33 +02:00
|
|
|
|
|
|
|
// To make sure we don't process the same return statement to infinity
|
|
|
|
AST *lastProcessedReturn;
|
|
|
|
};
|
|
|
|
static void callee_saved_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
|
|
|
struct CalleeSavedState *this = ud;
|
|
|
|
|
|
|
|
AST *n = *nptr;
|
|
|
|
|
|
|
|
if(tlc != this->targetTLC) {
|
|
|
|
// Don't do anything.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(n == tlc) {
|
|
|
|
// Function entry
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
for(int i = 0; i < MAX_REGS_PER_CLASS; i++) {
|
|
|
|
ScopeItem *vte = this->calleeUsers[i];
|
|
|
|
|
|
|
|
if(!vte) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
|
|
|
|
stk->nodeKind = AST_EXPR_STACK_POINTER;
|
|
|
|
stk->type = primitive_parse("u32");
|
|
|
|
|
|
|
|
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
|
|
|
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
|
|
|
offset->type = primitive_parse("u32");
|
|
|
|
offset->val = this->calleeOffsets[i];
|
|
|
|
|
|
|
|
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
|
|
|
sum->nodeKind = AST_EXPR_BINARY_OP;
|
|
|
|
sum->type = offset->type;
|
|
|
|
sum->operator = BINOP_ADD;
|
|
|
|
sum->operands[0] = (AST*) stk;
|
|
|
|
sum->operands[1] = (AST*) offset;
|
|
|
|
|
|
|
|
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
|
|
|
deref->nodeKind = AST_EXPR_UNARY_OP;
|
|
|
|
deref->type = offset->type;
|
|
|
|
deref->operator = UNOP_DEREF;
|
|
|
|
deref->operand = (AST*) sum;
|
|
|
|
|
|
|
|
ASTExprVar *ev = calloc(1, sizeof(*ev));
|
|
|
|
ev->nodeKind = AST_EXPR_VAR;
|
|
|
|
ev->type = vte->type;
|
|
|
|
ev->thing = vte;
|
|
|
|
|
|
|
|
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
|
|
|
|
assign->nodeKind = AST_STMT_ASSIGN;
|
|
|
|
assign->what = (AST*) deref;
|
|
|
|
assign->to = (AST*) ev;
|
|
|
|
|
|
|
|
assign->next = tlc->chunk.statementFirst;
|
|
|
|
tlc->chunk.statementFirst = (AST*) assign;
|
|
|
|
|
|
|
|
assert(tlc->chunk.statementLast != NULL);
|
|
|
|
}
|
2024-12-14 18:13:33 +02:00
|
|
|
|
|
|
|
} else if(n->nodeKind == AST_STMT_RETURN && n != this->lastProcessedReturn) {
|
|
|
|
// Function exit
|
|
|
|
|
|
|
|
this->lastProcessedReturn = n;
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
for(int i = 0; i < MAX_REGS_PER_CLASS; i++) {
|
|
|
|
ScopeItem *vte = this->calleeUsers[i];
|
|
|
|
|
|
|
|
if(!vte) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
|
|
|
|
stk->nodeKind = AST_EXPR_STACK_POINTER;
|
|
|
|
stk->type = primitive_parse("u32");
|
|
|
|
|
|
|
|
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
|
|
|
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
|
|
|
offset->type = primitive_parse("u32");
|
|
|
|
offset->val = this->calleeOffsets[i];
|
|
|
|
|
|
|
|
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
|
|
|
sum->nodeKind = AST_EXPR_BINARY_OP;
|
|
|
|
sum->type = offset->type;
|
|
|
|
sum->operator = BINOP_ADD;
|
|
|
|
sum->operands[0] = (AST*) stk;
|
|
|
|
sum->operands[1] = (AST*) offset;
|
|
|
|
|
|
|
|
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
|
|
|
deref->nodeKind = AST_EXPR_UNARY_OP;
|
|
|
|
deref->type = offset->type;
|
|
|
|
deref->operator = UNOP_DEREF;
|
|
|
|
deref->operand = (AST*) sum;
|
|
|
|
|
|
|
|
ASTExprVar *ev = calloc(1, sizeof(*ev));
|
|
|
|
ev->nodeKind = AST_EXPR_VAR;
|
|
|
|
ev->type = vte->type;
|
|
|
|
ev->thing = vte;
|
|
|
|
|
|
|
|
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
|
|
|
|
assign->nodeKind = AST_STMT_ASSIGN;
|
|
|
|
assign->what = (AST*) ev;
|
|
|
|
assign->to = (AST*) deref;
|
|
|
|
assign->next = stmt;
|
|
|
|
|
|
|
|
if(stmtPrev) {
|
|
|
|
stmtPrev->statement.next = (AST*) assign;
|
|
|
|
} else {
|
|
|
|
tlc->chunk.statementFirst = (AST*) assign;
|
|
|
|
}
|
|
|
|
stmtPrev = (AST*) assign;
|
2024-12-14 18:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void callee_saved(AST *tlc) {
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *ebxuser = NULL, *ediuser = NULL, *esiuser = NULL;
|
2024-12-14 18:13:33 +02:00
|
|
|
|
|
|
|
for(size_t v = 0; v < tlc->chunk.varCount; v++) {
|
2025-06-10 22:07:22 +03:00
|
|
|
if(is_reg_b(tlc->chunk.vars[v]->data.var.registerClass, tlc->chunk.vars[v]->data.var.color)) {
|
2024-12-14 18:13:33 +02:00
|
|
|
ebxuser = tlc->chunk.vars[v];
|
2025-06-10 22:07:22 +03:00
|
|
|
}
|
|
|
|
if(is_reg_di(tlc->chunk.vars[v]->data.var.registerClass, tlc->chunk.vars[v]->data.var.color)) {
|
|
|
|
ediuser = tlc->chunk.vars[v];
|
|
|
|
}
|
|
|
|
if(is_reg_si(tlc->chunk.vars[v]->data.var.registerClass, tlc->chunk.vars[v]->data.var.color)) {
|
|
|
|
esiuser = tlc->chunk.vars[v];
|
2024-12-14 18:13:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
struct CalleeSavedState state = {};
|
|
|
|
state.targetTLC = tlc;
|
|
|
|
|
|
|
|
size_t nextUser = 0;
|
2024-12-14 18:13:33 +02:00
|
|
|
if(ebxuser) {
|
2025-06-10 22:07:22 +03:00
|
|
|
state.calleeOffsets[nextUser] = nextUser * 4;
|
|
|
|
state.calleeUsers[nextUser] = ebxuser;
|
|
|
|
nextUser++;
|
|
|
|
}
|
|
|
|
if(esiuser) {
|
|
|
|
state.calleeOffsets[nextUser] = nextUser * 4;
|
|
|
|
state.calleeUsers[nextUser] = esiuser;
|
|
|
|
nextUser++;
|
|
|
|
}
|
|
|
|
if(ediuser) {
|
|
|
|
state.calleeOffsets[nextUser] = nextUser * 4;
|
|
|
|
state.calleeUsers[nextUser] = ediuser;
|
|
|
|
nextUser++;
|
|
|
|
}
|
|
|
|
ast_grow_stack_frame(tlc, nextUser * 4);
|
|
|
|
|
|
|
|
if(nextUser) {
|
2025-05-03 09:59:30 +03:00
|
|
|
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, callee_saved_visitor, NULL);
|
2024-12-14 18:13:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
/*struct DetermineRegisterClassesState {
|
|
|
|
int isInDereference;
|
|
|
|
};
|
|
|
|
static void determine_register_classes_visitor_pre(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
|
|
|
struct DetermineRegisterClassesState *this = ud;
|
|
|
|
|
|
|
|
AST *n = *nptr;
|
|
|
|
if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_DEREF) {
|
|
|
|
this->isInDereference++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void determine_register_classes_visitor_post(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
|
|
|
struct DetermineRegisterClassesState *this = ud;
|
|
|
|
|
|
|
|
AST *n = *nptr;
|
|
|
|
if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_DEREF) {
|
|
|
|
this->isInDereference--;
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
static void determine_register_classes(AST *tlc) {
|
|
|
|
for(size_t v = 0; v < tlc->chunk.varCount; v++) {
|
|
|
|
if(type_size(tlc->chunk.vars[v]->type) == 1) {
|
|
|
|
tlc->chunk.vars[v]->data.var.registerClass = REG_CLASS_8;
|
|
|
|
} else {
|
|
|
|
tlc->chunk.vars[v]->data.var.registerClass = REG_CLASS_NOT_8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//struct DetermineRegisterClassesState state = {};
|
|
|
|
//generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, determine_register_classes_visitor_pre, determine_register_classes_visitor_post);
|
|
|
|
}
|
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
/* Welsh-Powell graph coloring */
|
|
|
|
static int comparator(const void *A, const void *B) {
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *const *a = A;
|
|
|
|
ScopeItem *const *b = B;
|
2023-08-27 19:48:06 +03:00
|
|
|
return ((*a)->data.var.degree * (*a)->data.var.priority) - ((*b)->data.var.degree * (*b)->data.var.priority);
|
|
|
|
}
|
2024-11-20 16:36:17 +02:00
|
|
|
int cg_go(AST *a) {
|
2025-05-03 09:59:30 +03:00
|
|
|
assert(a->nodeKind == AST_CHUNK);
|
|
|
|
|
|
|
|
for(size_t e = 0; e < a->chunk.externCount; e++) {
|
2025-06-10 22:07:22 +03:00
|
|
|
assert(a->chunk.externs[e]->kind == SCOPEITEM_SYMBOL);
|
2025-05-03 09:59:30 +03:00
|
|
|
assert(a->chunk.externs[e]->data.symbol.isExternal);
|
|
|
|
|
|
|
|
printf("extern %s\n", a->chunk.externs[e]->data.symbol.name);
|
|
|
|
}
|
|
|
|
|
2025-02-27 20:10:02 +02:00
|
|
|
ast_usedef_reset(a);
|
2024-11-20 16:36:17 +02:00
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
size_t adjCount = 0;
|
2024-11-25 17:36:03 +02:00
|
|
|
Adjacency *adjs = calloc(adjCount, sizeof(*adjs));
|
2023-08-27 19:48:06 +03:00
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem **vars = a->chunk.vars;
|
2023-08-27 19:48:06 +03:00
|
|
|
|
2024-11-20 16:36:17 +02:00
|
|
|
for(size_t vi = 0; vi < a->chunk.varCount; vi++) {
|
|
|
|
vars[vi]->data.var.priority = 1;
|
|
|
|
vars[vi]->data.var.degree = 0;
|
2025-06-10 22:07:22 +03:00
|
|
|
vars[vi]->data.var.registerClass = -1;
|
2024-12-14 18:13:33 +02:00
|
|
|
|
|
|
|
if(!vars[vi]->data.var.precolored) {
|
|
|
|
vars[vi]->data.var.color = -1;
|
|
|
|
}
|
2024-11-20 16:36:17 +02:00
|
|
|
}
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
determine_register_classes(a);
|
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
for(size_t v1i = 0; v1i < a->chunk.varCount; v1i++) {
|
|
|
|
for(size_t v2i = 0; v2i < a->chunk.varCount; v2i++) {
|
|
|
|
if(v1i == v2i) continue;
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *v1 = vars[v1i];
|
|
|
|
ScopeItem *v2 = vars[v2i];
|
2023-08-27 19:48:06 +03:00
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
if(var_collision(a, v1, v2)) {
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *min = v1 < v2 ? v1 : v2;
|
|
|
|
ScopeItem *max = v1 < v2 ? v2 : v1;
|
2023-08-27 19:48:06 +03:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
int mustSpillRegisterClass = -1;
|
2024-11-20 16:36:17 +02:00
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
/* Welsh plow my ass */
|
|
|
|
for(int v = 0; v < a->chunk.varCount; v++) {
|
2024-11-25 17:36:03 +02:00
|
|
|
if(vars[v]->data.var.color != -1) {
|
|
|
|
// Already assigned.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
for(int c = 0;; c++) {
|
2025-06-10 22:07:22 +03:00
|
|
|
if(c >= MAX_REGS_PER_CLASS || REG_CLASSES[vars[v]->data.var.registerClass].rs[c] == 0) {
|
|
|
|
// Ran out of resources
|
|
|
|
mustSpillRegisterClass = vars[v]->data.var.registerClass;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
int resource = REG_CLASSES[vars[v]->data.var.registerClass].rs[c];
|
|
|
|
|
|
|
|
if(REG_CLASSES[vars[v]->data.var.registerClass].rsS[c] != type_size(vars[v]->type)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
for(int a = 0; a < adjCount; a++) {
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *me = NULL, *they = NULL;
|
|
|
|
|
|
|
|
if(adjs[a][0] == vars[v]) {
|
|
|
|
me = adjs[a][0];
|
|
|
|
they = adjs[a][1];
|
|
|
|
} else if(adjs[a][1] == vars[v]) {
|
|
|
|
me = adjs[a][1];
|
|
|
|
they = adjs[a][0];
|
|
|
|
} else continue;
|
|
|
|
|
|
|
|
if(they->data.var.color == -1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int theyRes = REG_CLASSES[they->data.var.registerClass].rs[they->data.var.color];
|
|
|
|
|
|
|
|
if((resource & theyRes) != 0) {
|
2023-08-27 19:48:06 +03:00
|
|
|
goto nextColor;
|
|
|
|
}
|
|
|
|
}
|
2025-06-10 22:07:22 +03:00
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
vars[v]->data.var.color = c;
|
2024-11-20 16:36:17 +02:00
|
|
|
|
2023-08-27 19:48:06 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
nextColor:;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(adjs);
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
if(mustSpillRegisterClass != -1) {
|
2024-11-20 16:36:17 +02:00
|
|
|
// Spill node with highest degree
|
|
|
|
|
2025-06-10 22:07:22 +03:00
|
|
|
ScopeItem *chosen = NULL;
|
2025-02-27 20:10:02 +02:00
|
|
|
for(ssize_t i = a->chunk.varCount - 1; i >= 0; i--) {
|
2025-06-10 22:07:22 +03:00
|
|
|
if(!vars[i]->data.var.precolored && vars[i]->data.var.registerClass == mustSpillRegisterClass) {
|
2025-02-27 20:10:02 +02:00
|
|
|
chosen = vars[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(chosen != NULL);
|
2024-12-14 18:13:33 +02:00
|
|
|
|
2025-02-27 20:10:02 +02:00
|
|
|
ast_spill_to_stack(a, chosen);
|
2024-11-20 16:36:17 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-12-14 18:13:33 +02:00
|
|
|
if(a->chunk.functionType) {
|
|
|
|
callee_saved(a);
|
|
|
|
}
|
|
|
|
|
2024-11-26 18:42:20 +02:00
|
|
|
CGState cg;
|
|
|
|
memset(&cg, 0, sizeof(cg));
|
2024-12-14 18:13:33 +02:00
|
|
|
cg.tlc = a;
|
|
|
|
cg.isFunction = !!a->chunk.functionType;
|
2024-11-26 18:42:20 +02:00
|
|
|
|
|
|
|
cg_chunk(&cg, a);
|
2023-08-27 19:48:06 +03:00
|
|
|
|
2024-11-20 16:36:17 +02:00
|
|
|
return 1;
|
2024-06-12 11:17:09 +03:00
|
|
|
}
|
2024-11-20 16:36:17 +02:00
|
|
|
|