So many bug fixes like omg why didn't u use bp for stacc idiot

This commit is contained in:
Mid 2025-09-13 11:19:49 +03:00
parent 13333c971a
commit d0262c586e
10 changed files with 184 additions and 107 deletions

View File

@ -5,6 +5,7 @@
#include"scope.h"
#include<assert.h>
#include<stdlib.h>
#include"x86/arch.h"
struct Spill2StackState {
AST *targetTLC;
@ -30,7 +31,7 @@ static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk
ASTExprStackPointer *rsp = calloc(1, sizeof(*rsp));
rsp->nodeKind = AST_EXPR_STACK_POINTER;
rsp->type = primitive_parse("u32");
rsp->type = type_u(arch_gpr_size());
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
offset->nodeKind = AST_EXPR_PRIMITIVE;

View File

@ -153,6 +153,10 @@ void ast_usedef_reset(AST *chu) {
}
s->statement.dirty = true;
s->statement.rd.defCount = 0;
free(s->statement.rd.defs);
s->statement.rd.defs = NULL;
}
for(size_t rdsteps = 0;; rdsteps++) {

View File

@ -80,6 +80,8 @@ int main(int argc_, char **argv_) {
stahp(0, 0, "Failed to read input (%s)", strerror(errno));
}
arch_init();
Token *tokens = nct_lex(f);
if(in) fclose(f);

View File

@ -38,9 +38,6 @@ typedef struct {
// Used by pushstat to add statements
ASTChunk *currentChunk;
// Used to place guard variable uses after loops to stop reg allocation from fucking up
Scope *loopScope;
// Used for generating statements that load & store arguments
int isInFunction;
@ -143,36 +140,6 @@ static AST *exprvar(Parser *P, ScopeItem *v) {
a->exprVar.type = v->type;
a->exprVar.thing = v;
/*if(P->loopScope) {
// XXX: O(n)!!!!!!!!!
int inloop = 0;
for(Scope *vt = v->owner; vt; vt = vt->parent) {
if(vt->parent == P->loopScope) {
inloop = 1;
break;
}
}
if(!inloop) {
int alreadyAdded = 0;
for(size_t i = 0; i < P->guardedVarCount; i++) {
if(P->guardedVars[i]->thing == v) {
alreadyAdded = 1;
break;
}
}
if(!alreadyAdded) {
ASTExprVar *ev = alloc_node(P, sizeof(*ev));
memcpy(ev, a, sizeof(*ev));
P->guardedVars = realloc(P->guardedVars, sizeof(*P->guardedVars) * (P->guardedVarCount + 1));
P->guardedVars[P->guardedVarCount++] = ev;
}
}
}*/
return a;
}
@ -261,7 +228,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
ASTExprStackPointer *ret = alloc_node(P, sizeof(*ret));
ret->nodeKind = AST_EXPR_STACK_POINTER;
ret->type = primitive_parse("u32");
ret->type = type_u(arch_sp_size());
e = (AST*) ret;
} else if(!strcmp(peek(P, 0).content, "@salloc")) {
@ -288,7 +255,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
ret->ofExpr = nct_parse_expression(P, lOP - 1);
}
ret->type = primitive_parse("u32");
ret->type = type_u(arch_gpr_size());
e = (AST*) ret;
} else {
@ -494,7 +461,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
if(typesize != 1) {
ASTExprPrimitive *scale = alloc_node(P, sizeof(*scale));
scale->nodeKind = AST_EXPR_PRIMITIVE;
scale->type = primitive_parse("u32");
scale->type = type_u(arch_gpr_size());
scale->val = typesize;
ASTExprBinaryOp *mul = alloc_node(P, sizeof(*mul));
@ -1135,11 +1102,11 @@ static void nct_parse_statement(Parser *P) {
ret->nodeKind = AST_STMT_LOOP;
ret->next = NULL;
int isFirstLoop = P->loopScope == NULL;
//int isFirstLoop = P->loopScope == NULL;
if(isFirstLoop) {
P->loopScope = P->scope;
}
//if(isFirstLoop) {
//P->loopScope = P->scope;
//}
expect(P, TOKEN_SQUIGGLY_L);
ret->body = (AST*) nct_parse_chunk(P, 0, 1, NULL, NULL);
@ -1147,8 +1114,8 @@ static void nct_parse_statement(Parser *P) {
pushstat(P, ret);
if(isFirstLoop) {
P->loopScope = NULL;
//if(isFirstLoop) {
//P->loopScope = NULL;
/*for(size_t i = 0; i < P->guardedVarCount; i++) {
ASTExprVar *ev = P->guardedVars[i];
@ -1163,7 +1130,7 @@ static void nct_parse_statement(Parser *P) {
P->guardedVarCount = 0;
free(P->guardedVars);
P->guardedVars = NULL;*/
}
//}
return;
} else if(maybe(P, TOKEN_BREAK)) {

View File

@ -19,7 +19,6 @@ typedef struct UseDef {
struct UseDef *next;
} UseDef;
// Stack, necessary for "possible reaching defs" such as from if statements
typedef struct ReachingDefs {
size_t defCount;
union AST **defs;

View File

@ -5,6 +5,7 @@
#include<stdint.h>
#include<stdbool.h>
#include<string.h>
#include<stdio.h>
typedef enum {
TYPE_TYPE_PRIMITIVE, TYPE_TYPE_RECORD, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_GENERIC, TYPE_TYPE_ERROR
@ -114,4 +115,10 @@ static inline bool type_is_segmented_pointer(Type *type) {
return type->type == TYPE_TYPE_RECORD && !!strstr(type->record.name, " @far*");
}
static inline Type *type_u(size_t size) {
char buf[32];
snprintf(buf, sizeof(buf), "u%lu", size);
return primitive_parse(buf);
}
#endif

View File

@ -27,9 +27,15 @@ RegisterClass REG_CLASSES[] = {
},
[REG_CLASS_IA16_PTRS] = {
.rMask = HWR_IND | HWR_BX,
.rs = {HWR_DI, HWR_SI, HWR_BX, HWR_BP},
.rsN = {"di", "si", "bx", "bp"},
.rsS = {2, 2, 2, 2},
.rs = {HWR_DI, HWR_SI, HWR_BX},
.rsN = {"di", "si", "bx"},
.rsS = {2, 2, 2},
},
[REG_CLASS_IA16_USEABLE]= {
.rMask = HWR_IND | HWR_GPR,
.rs = {HWR_AX, HWR_CX, HWR_DX, HWR_DI, HWR_SI, HWR_BX},
.rsN = {"ax", "cx", "dx", "di", "si", "bx"},
.rsS = {2, 2, 2, 2, 2, 2},
},
[REG_CLASS_DATASEGS] = {
.rMask = HWR_SEGREGS,
@ -50,3 +56,7 @@ bool arch_verify_target() {
int arch_ptr_size() {
return x86_ia16() ? 2 : 4;
}
void arch_init() {
}

View File

@ -60,45 +60,10 @@ typedef struct RegisterClass {
#define REG_CLASS_16_32 2
#define REG_CLASS_IND 3
#define REG_CLASS_IA16_PTRS 4
#define REG_CLASS_DATASEGS 5
#define REG_CLASS_IA16_USEABLE 5
#define REG_CLASS_DATASEGS 6
extern RegisterClass REG_CLASSES[];
// lol
static inline bool is_reg_b(int cls, int res) {
const char *name = REG_CLASSES[cls].rsN[res];
return !strcmp(name, "bl") || !strcmp(name, "bh") || !!strstr(name, "bx");
}
static inline bool is_reg_di(int cls, int res) {
const char *name = REG_CLASSES[cls].rsN[res];
return !!strstr(name, "di");
}
static inline bool is_reg_si(int cls, int res) {
const char *name = REG_CLASSES[cls].rsN[res];
return !!strstr(name, "si");
}
static inline void reg_cast_up(int *cls, int *res) {
const char *name = REG_CLASSES[*cls].rsN[*res];
if(strstr(name, "a")) {
*cls = REG_CLASS_16_32;
*res = 1;
} else if(strstr(name, "b")) {
*cls = REG_CLASS_16_32;
*res = 3;
} else if(strstr(name, "c")) {
*cls = REG_CLASS_16_32;
*res = 5;
} else if(strstr(name, "dl") || strstr(name, "dh") || strstr(name, "dx")) {
*cls = REG_CLASS_16_32;
*res = 7;
} else if(strstr(name, "di")) {
*cls = REG_CLASS_16_32;
*res = 9;
} else if(strstr(name, "si")) {
*cls = REG_CLASS_16_32;
*res = 11;
}
}
typedef enum {
I086 = 0,
I186 = 1,
@ -151,6 +116,10 @@ static inline bool x86_imul_supported() {
return x86_target() >= I186;
}
static inline bool x86_is_marked_ptr(ScopeItem *si) {
return si->data.var.preclassed && si->data.var.registerClass == REG_CLASS_IA16_PTRS;
}
// Can expression be expressed as a single x86 operand?
#define XOP_NOT_XOP 0
#define XOP_NOT_MEM 1
@ -176,10 +145,9 @@ static inline int is_xop(AST *e) {
}
if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == SCOPEITEM_VAR) {
if(x86_ia16()) { // In IA-16, pointers MUST be preclassed to REG_CLASS_IA16_PTRS
if(!c->exprVar.thing->data.var.preclassed || c->exprVar.thing->data.var.registerClass != REG_CLASS_IA16_PTRS) {
return XOP_NOT_XOP;
}
if(x86_ia16() && !x86_is_marked_ptr(c->exprVar.thing)) {
// In IA-16, pointers MUST be preclassed to REG_CLASS_IA16_PTRS
return XOP_NOT_XOP;
}
return XOP_MEM;
@ -190,8 +158,18 @@ static inline int is_xop(AST *e) {
if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
return XOP_MEM;
} else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) {
if(x86_ia16() && !x86_is_marked_ptr(c->exprBinOp.operands[1]->exprVar.thing)) {
// In IA-16, pointers MUST be preclassed to REG_CLASS_IA16_PTRS
return XOP_NOT_XOP;
}
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) {
if(x86_ia16() && !x86_is_marked_ptr(c->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing)) {
// In IA-16, pointers MUST be preclassed to REG_CLASS_IA16_PTRS
return XOP_NOT_XOP;
}
int scale = c->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val;
if(scale == 1 || scale == 2 || scale == 4 || scale == 8) {
@ -307,3 +285,52 @@ static inline void arch_add_hidden_variables(Scope *scope) {
static inline bool x86_is_lea(AST *s) {
return !x86_ia16() && s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && is_xop(s->stmtAssign.what) == XOP_NOT_MEM && is_xop(s->stmtAssign.to->exprBinOp.operands[0]) == XOP_NOT_MEM && is_xop(s->stmtAssign.to->exprBinOp.operands[1]) == XOP_NOT_MEM;
}
static inline int arch_sp_size() {
return x86_max_gpr_size();
}
static inline int arch_gpr_size() {
return x86_max_gpr_size();
}
// lol
static inline bool is_reg_b(int cls, int res) {
const char *name = REG_CLASSES[cls].rsN[res];
return !strcmp(name, "bl") || !strcmp(name, "bh") || !!strstr(name, "bx");
}
static inline bool is_reg_di(int cls, int res) {
const char *name = REG_CLASSES[cls].rsN[res];
return !!strstr(name, "di");
}
static inline bool is_reg_si(int cls, int res) {
const char *name = REG_CLASSES[cls].rsN[res];
return !!strstr(name, "si");
}
static inline void reg_cast_to_gpr(int *cls, int *res) {
const char *name = REG_CLASSES[*cls].rsN[*res];
if(strstr(name, "a")) {
*cls = REG_CLASS_16_32;
*res = 1;
} else if(strstr(name, "b")) {
*cls = REG_CLASS_16_32;
*res = 3;
} else if(strstr(name, "c")) {
*cls = REG_CLASS_16_32;
*res = 5;
} else if(strstr(name, "dl") || strstr(name, "dh") || strstr(name, "dx")) {
*cls = REG_CLASS_16_32;
*res = 7;
} else if(strstr(name, "di")) {
*cls = REG_CLASS_16_32;
*res = 9;
} else if(strstr(name, "si")) {
*cls = REG_CLASS_16_32;
*res = 11;
}
if(x86_ia16()) {
(*res)--;
}
}
void arch_init();

View File

@ -78,8 +78,8 @@ static const char *xv_sz(ScopeItem *v, int sz) {
int cls = v->data.var.registerClass, reg = v->data.var.color;
if(type_size(v->type) != sz) {
if(sz == 4) {
reg_cast_up(&cls, &reg);
if(sz == x86_max_gpr_size()) {
reg_cast_to_gpr(&cls, &reg);
} else abort();
}
@ -185,13 +185,17 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
} else if(p->nodeKind == AST_EXPR_VAR && p->exprVar.thing->kind == SCOPEITEM_VAR) {
pr = snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(p->exprVar.thing, 0));
} 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) {
pr = snprintf(ret, XOPBUFSZ, "[esp + %i]", p->exprBinOp.operands[1]->exprPrim.val);
if(x86_ia16()) {
pr = snprintf(ret, XOPBUFSZ, "[bp + %li]", p->exprBinOp.operands[1]->exprPrim.val - tlc->chunk.stackReservation);
} else {
pr = snprintf(ret, XOPBUFSZ, "[esp + %i]", p->exprBinOp.operands[1]->exprPrim.val);
}
} else {
return NULL;
}
} else if(e->nodeKind == AST_EXPR_STACK_POINTER) {
pr = snprintf(ret, XOPBUFSZ, "esp");
pr = snprintf(ret, XOPBUFSZ, x86_ia16() ? "sp" : "esp");
} else if(e->nodeKind == AST_EXPR_VAR) {
ScopeItem *v = e->exprVar.thing;
@ -243,7 +247,13 @@ void cg_chunk(CGState *cg, AST *a) {
AST *s = a->chunk.statementFirst;
if(a->chunk.stackReservation) {
printf("sub esp, %lu\n", a->chunk.stackReservation);
if(x86_ia16()) {
printf("push bp\n");
printf("mov bp, sp\n");
printf("sub sp, %lu\n", a->chunk.stackReservation);
} else {
printf("sub esp, %lu\n", a->chunk.stackReservation);
}
}
// Potentially complex pattern matching
@ -352,15 +362,20 @@ void cg_chunk(CGState *cg, AST *a) {
AST *e = s->stmtAssign.to;
puts("push ecx");
puts("push edx");
if(x86_ia16()) {
puts("push cx");
puts("push dx");
} else {
puts("push ecx");
puts("push edx");
}
int argCount = e->exprCall.what->expression.type->pointer.of->function.argCount;
size_t argSize = 0;
for(int i = argCount - 1; i >= 0; i--) {
printf("push %s\n", xop_sz(cg->tlc, e->exprCall.args[i], 4));
printf("push %s\n", xop_sz(cg->tlc, e->exprCall.args[i], arch_gpr_size()));
argSize += (type_size(e->exprCall.args[i]->expression.type) + 3) & ~3;
}
@ -371,10 +386,21 @@ void cg_chunk(CGState *cg, AST *a) {
printf("call %s\n", xop(cg->tlc, e->exprCall.what));
}
if(argSize) printf("add esp, %lu\n", argSize);
if(argSize) {
if(x86_ia16()) {
printf("add sp, %lu\n", argSize);
} else {
printf("add esp, %lu\n", argSize);
}
}
puts("pop edx");
puts("pop ecx");
if(x86_ia16()) {
puts("pop dx");
puts("pop cx");
} else {
puts("pop edx");
puts("pop ecx");
}
} else if(s->nodeKind == AST_STMT_ASSIGN) {
@ -455,8 +481,8 @@ void cg_chunk(CGState *cg, AST *a) {
} else {
const char *dest = xop_sz(cg->tlc, s->stmtAssign.what, 4);
const char *src = xop_sz(cg->tlc, s->stmtAssign.to->exprCast.what, 4);
const char *dest = xop_sz(cg->tlc, s->stmtAssign.what, x86_max_gpr_size());
const char *src = xop_sz(cg->tlc, s->stmtAssign.to->exprCast.what, x86_max_gpr_size());
if(strcmp(dest, src)) {
printf("mov %s, %s\n", dest, src);
@ -520,7 +546,20 @@ void cg_chunk(CGState *cg, AST *a) {
}
if(a->chunk.stackReservation) {
printf("add esp, %lu\n", a->chunk.stackReservation);
if(x86_ia16()) {
printf("add sp, %lu\n", a->chunk.stackReservation);
} else {
printf("add esp, %lu\n", a->chunk.stackReservation);
}
}
if(x86_ia16()) {
if(x86_target() >= I186) {
printf("leave\n");
} else {
printf("mov sp, bp\n");
printf("pop bp\n");
}
}
printf("ret\n");
@ -735,7 +774,7 @@ static void determine_register_classes(AST *tlc) {
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;
tlc->chunk.vars[v]->data.var.registerClass = x86_ia16() ? REG_CLASS_IA16_USEABLE : REG_CLASS_NOT_8;
}
}
}

View File

@ -228,7 +228,7 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
// 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 == SCOPEITEM_VAR && !strchr(REG_CLASSES[retval->exprVar.thing->data.var.registerClass].rsN[retval->exprVar.thing->data.var.color], 'a')))) {
if(retval && (!is_xop(retval) || retval->nodeKind == AST_EXPR_PRIMITIVE || (retval->nodeKind == AST_EXPR_VAR && retval->exprVar.thing->kind == SCOPEITEM_VAR && (!retval->exprVar.thing->data.var.precolored || !strchr(REG_CLASSES[retval->exprVar.thing->data.var.registerClass].rsN[retval->exprVar.thing->data.var.color], 'a'))))) {
retval = s->stmtReturn.val = varify(tlc, chu, stmtPrev, s, retval);
this->effective = 1;
@ -474,8 +474,8 @@ static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
offset->nodeKind = AST_EXPR_PRIMITIVE;
offset->type = primitive_parse("u32");
offset->val = 4 + i * 4;
offset->type = type_u(x86_max_gpr_size());
offset->val = 4 + i * x86_max_gpr_size();
offset->stackGrowth = true;
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
@ -640,6 +640,27 @@ static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST
*nptr = (AST*) prim;
*success = true;
} else if(n->nodeKind == AST_EXPR_CAST) {
// TODO: Move all compile-time constant casting from ast_cast_expr to here.
AST *what = n->exprCast.what;
Type *to = n->exprCast.to;
if(what->nodeKind == AST_EXPR_PRIMITIVE && (to->type == TYPE_TYPE_PRIMITIVE || to->type == TYPE_TYPE_POINTER)) {
ASTExprPrimitive *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = to;
if(to->type == TYPE_TYPE_PRIMITIVE) {
ret->val = what->exprPrim.val & ((1UL << to->primitive.width) - 1);
} else {
ret->val = what->exprPrim.val & ((1UL << (8 * type_size(to))) - 1);
}
*nptr = ret;
*success = true;
}
}
}