From d0262c586e2afb95350a30c2606c258316043739 Mon Sep 17 00:00:00 2001 From: Mid <> Date: Sat, 13 Sep 2025 11:19:49 +0300 Subject: [PATCH] So many bug fixes like omg why didn't u use bp for stacc idiot --- src/ast/stack.c | 3 +- src/ast/usedef.c | 4 ++ src/ntc.c | 2 + src/parse.c | 53 ++++---------------- src/scope.h | 1 - src/types.h | 7 +++ src/x86/arch.c | 16 ++++-- src/x86/arch.h | 109 +++++++++++++++++++++++++---------------- src/x86/cg.c | 69 ++++++++++++++++++++------ src/x86/dumberdowner.c | 27 ++++++++-- 10 files changed, 184 insertions(+), 107 deletions(-) diff --git a/src/ast/stack.c b/src/ast/stack.c index d0a8eea..e3ba48c 100644 --- a/src/ast/stack.c +++ b/src/ast/stack.c @@ -5,6 +5,7 @@ #include"scope.h" #include #include +#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; diff --git a/src/ast/usedef.c b/src/ast/usedef.c index a69ae17..4f28dd4 100644 --- a/src/ast/usedef.c +++ b/src/ast/usedef.c @@ -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++) { diff --git a/src/ntc.c b/src/ntc.c index 9b5fb4d..aa75780 100644 --- a/src/ntc.c +++ b/src/ntc.c @@ -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); diff --git a/src/parse.c b/src/parse.c index 20aa7d1..b415fce 100644 --- a/src/parse.c +++ b/src/parse.c @@ -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)) { diff --git a/src/scope.h b/src/scope.h index be142b5..5345674 100644 --- a/src/scope.h +++ b/src/scope.h @@ -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; diff --git a/src/types.h b/src/types.h index a7ba157..ee8f8f4 100644 --- a/src/types.h +++ b/src/types.h @@ -5,6 +5,7 @@ #include #include #include +#include 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 diff --git a/src/x86/arch.c b/src/x86/arch.c index 091f854..b4d4766 100644 --- a/src/x86/arch.c +++ b/src/x86/arch.c @@ -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() { + +} diff --git a/src/x86/arch.h b/src/x86/arch.h index 6ffddea..111038b 100644 --- a/src/x86/arch.h +++ b/src/x86/arch.h @@ -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(); \ No newline at end of file diff --git a/src/x86/cg.c b/src/x86/cg.c index 609177c..298af66 100644 --- a/src/x86/cg.c +++ b/src/x86/cg.c @@ -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, ®); + if(sz == x86_max_gpr_size()) { + reg_cast_to_gpr(&cls, ®); } 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; } } } diff --git a/src/x86/dumberdowner.c b/src/x86/dumberdowner.c index 5557b5d..4de043f 100644 --- a/src/x86/dumberdowner.c +++ b/src/x86/dumberdowner.c @@ -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; + } } }