From 6ec68a766f5636b20b6979b477f9a47823e60d13 Mon Sep 17 00:00:00 2001 From: Mid <> Date: Tue, 10 Jun 2025 22:07:22 +0300 Subject: [PATCH] penis sex fuck penis cock, irregular register allocation and rename VarTable to Scope --- src/ast.c | 151 ++++++++----- src/ast.h | 34 ++- src/cg.c | 483 +++++++++++++++++++++++++--------------- src/dstr.c | 141 ------------ src/dstr.h | 15 -- src/dumberdowner.c | 77 +++++-- src/lexer.c | 4 + src/ntc.c | 73 ++++-- src/ntc.h | 9 +- src/optims.c | 75 ------- src/optims.h | 5 - src/parse.c | 375 +++++++++++++++++++------------ src/types.c | 79 +++---- src/types.h | 14 +- src/vartable.c | 59 ++--- src/vartable.h | 131 ++++++----- src/x86.h | 95 +++++++- tests/GenericStruct.nct | 44 ---- tests/Importer.nct | 3 +- 19 files changed, 985 insertions(+), 882 deletions(-) delete mode 100644 src/dstr.c delete mode 100644 src/dstr.h delete mode 100644 src/optims.c delete mode 100644 src/optims.h delete mode 100644 tests/GenericStruct.nct diff --git a/src/ast.c b/src/ast.c index 287749b..5859ecb 100644 --- a/src/ast.c +++ b/src/ast.c @@ -5,6 +5,8 @@ #include #include #include +#include"ntc.h" +#include"reporting.h" const char *AST_KIND_STR[] = { AST_KINDS(GEN_STRI) @@ -78,6 +80,10 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v } else if(n->nodeKind == AST_EXPR_EXT_SALLOC) { } else if(n->nodeKind == AST_EXPR_DOT) { generic_visitor(&n->exprDot.a, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); + } else if(n->nodeKind == AST_EXPR_EXT_SIZEOF) { + if(n->exprExtSizeOf.ofExpr) { + generic_visitor(&n->exprExtSizeOf.ofExpr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); + } } else { abort(); } @@ -145,7 +151,7 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) { * Because an AST may hold outdated UD-chains, this pass MUST be called * before using the UD-chains to make sure they are valid. * - * Each local var (VTE of kind VARTABLEENTRY_VAR) holds its own UD-chain + * Each local var (VTE of kind SCOPEITEM_VAR) holds its own UD-chain * that specifies the exact nodes in the AST where: * 1. It is used * 2. The whole statement in which it is used @@ -204,8 +210,8 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) { * Until dead code removal is implemented, this will not be a problem. */ -static void rawadduse(VarTableEntry *vte, UseDef *ud) { - assert(vte->kind == VARTABLEENTRY_VAR); +static void rawadduse(ScopeItem *vte, UseDef *ud) { + assert(vte->kind == SCOPEITEM_VAR); assert(ud->next == NULL); @@ -219,8 +225,8 @@ static void rawadduse(VarTableEntry *vte, UseDef *ud) { } } -static void adduse(VarTableEntry *vte, AST *use, AST *whole) { - assert(vte->kind == VARTABLEENTRY_VAR); +static void adduse(ScopeItem *vte, AST *use, AST *whole) { + assert(vte->kind == SCOPEITEM_VAR); assert(vte->data.var.reachingDefs != NULL); @@ -241,8 +247,8 @@ static void adduse(VarTableEntry *vte, AST *use, AST *whole) { } } -static void overwritedefs(VarTableEntry *vte, AST *def) { - assert(vte->kind == VARTABLEENTRY_VAR); +static void overwritedefs(ScopeItem *vte, AST *def) { + assert(vte->kind == SCOPEITEM_VAR); if(!vte->data.var.reachingDefs) { vte->data.var.reachingDefs = calloc(1, sizeof(*vte->data.var.reachingDefs)); @@ -250,15 +256,12 @@ static void overwritedefs(VarTableEntry *vte, AST *def) { vte->data.var.reachingDefs->defCount = 1; - if(!vte->data.var.reachingDefs->defs) { - vte->data.var.reachingDefs->defs = calloc(1, sizeof(*vte->data.var.reachingDefs->defs)); - } - + vte->data.var.reachingDefs->defs = realloc(vte->data.var.reachingDefs->defs, sizeof(*vte->data.var.reachingDefs->defs)); vte->data.var.reachingDefs->defs[0] = def; } -static void mergedefs(VarTableEntry *vte) { - assert(vte->kind == VARTABLEENTRY_VAR); +static void mergedefs(ScopeItem *vte) { + assert(vte->kind == SCOPEITEM_VAR); ReachingDefs *rdefs = vte->data.var.reachingDefs; @@ -274,8 +277,8 @@ static void mergedefs(VarTableEntry *vte) { free(rdefs); } -static void pushdefs(VarTableEntry *vte) { - assert(vte->kind == VARTABLEENTRY_VAR); +static void pushdefs(ScopeItem *vte) { + assert(vte->kind == SCOPEITEM_VAR); ReachingDefs *rdefs = calloc(1, sizeof(*rdefs)); rdefs->defCount = 0; @@ -298,8 +301,8 @@ static void mergedefsall(AST *tlc) { } } -static void mergedefsloop(AST *tlc, VarTableEntry *vte, AST *daLoopStmt) { - assert(vte->kind == VARTABLEENTRY_VAR); +static void mergedefsloop(AST *tlc, ScopeItem *vte, AST *daLoopStmt) { + assert(vte->kind == SCOPEITEM_VAR); for(size_t d = 0; d < vte->data.var.reachingDefs->defCount; d++) { UseDef *ud = vte->data.var.usedefFirst; @@ -351,7 +354,7 @@ static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) { mergedefsloopall(tlc, a); } else if(a->nodeKind == AST_STMT_ASSIGN) { - if(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR) { + if(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR) { overwritedefs(a->stmtAssign.what->exprVar.thing, a); } @@ -363,7 +366,7 @@ static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) { } else if(a->nodeKind == AST_STMT_EXPR) { ast_usedef_pass(tlc, a->stmtExpr.expr, wholestmt); } else if(a->nodeKind == AST_EXPR_VAR) { - if(a->exprVar.thing->kind == VARTABLEENTRY_VAR) { + if(a->exprVar.thing->kind == SCOPEITEM_VAR) { adduse(a->exprVar.thing, a, wholestmt); } } else if(a->nodeKind == AST_EXPR_BINARY_OP) { @@ -389,7 +392,7 @@ static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) { } 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); + assert(a->stmtDecl.thing->kind != SCOPEITEM_VAR || a->stmtDecl.expression); } else if(a->nodeKind == AST_STMT_RETURN) { if(a->stmtReturn.val) { ast_usedef_pass(tlc, a->stmtReturn.val, wholestmt); @@ -401,9 +404,9 @@ static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) { void ast_usedef_reset(AST *chu) { for(size_t i = 0; i < chu->chunk.varCount; i++) { - VarTableEntry *vte = chu->chunk.vars[i]; + ScopeItem *vte = chu->chunk.vars[i]; - assert(vte->kind == VARTABLEENTRY_VAR); + assert(vte->kind == SCOPEITEM_VAR); vte->data.var.reachingDefs = NULL; vte->data.var.usedefFirst = NULL; @@ -415,16 +418,6 @@ void ast_usedef_reset(AST *chu) { return ast_usedef_pass(chu, chu, NULL); } -static char *cat(char *a, const char *b) { - if(!a) { - return strdup(b); - } - - a = realloc(a, strlen(a) + strlen(b) + 1); - strcpy(a + strlen(a), b); - return a; -} - __attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...) { va_list v1, v2; va_start(v1, fmt); @@ -463,7 +456,7 @@ char *type_to_string(Type *t) { if(t->array.lengthIsGeneric) { len = malp(""); } else { - len = malp("%i", t->array.length); + len = malp("%li", t->array.length); } char *r = malp("%s[%s]", of, len); free(of); @@ -478,11 +471,11 @@ static char *ast_dumpe(AST *e) { if(e->nodeKind == AST_EXPR_PRIMITIVE) { return malp("%i", e->exprPrim.val); } else if(e->nodeKind == AST_EXPR_VAR) { - VarTableEntry *vte = e->exprVar.thing; + ScopeItem *vte = e->exprVar.thing; - if(vte->kind == VARTABLEENTRY_VAR) { + if(vte->kind == SCOPEITEM_VAR) { return strdup(vte->data.var.name); - } else if(vte->kind == VARTABLEENTRY_SYMBOL) { + } else if(vte->kind == SCOPEITEM_SYMBOL) { return strdup(vte->data.symbol.name); } else abort(); } else if(e->nodeKind == AST_EXPR_UNARY_OP) { @@ -633,9 +626,9 @@ char *ast_dump(AST *tlc); static char *ast_dumps(AST *s) { if(s->nodeKind == AST_STMT_DECL) { - VarTableEntry *vte = s->stmtDecl.thing; + ScopeItem *vte = s->stmtDecl.thing; - if(vte->kind == VARTABLEENTRY_SYMBOL) { + if(vte->kind == SCOPEITEM_SYMBOL) { char *t = type_to_string(vte->type); char *e = s->stmtDecl.expression ? ast_dumpe(s->stmtDecl.expression) : strdup(""); char *r = malp("%s%s %s: %s;\n", vte->data.symbol.isExternal ? "external " : "", t, vte->data.symbol.name, e); @@ -672,7 +665,7 @@ static char *ast_dumps(AST *s) { } else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_VAR) { const char *name; - if(s->stmtExpr.expr->exprVar.thing->kind == VARTABLEENTRY_VAR) { + if(s->stmtExpr.expr->exprVar.thing->kind == SCOPEITEM_VAR) { name = s->stmtExpr.expr->exprVar.thing->data.var.name; } else { name = s->stmtExpr.expr->exprVar.thing->data.symbol.name; @@ -698,12 +691,14 @@ static char *ast_dumps(AST *s) { char *ast_dump(AST *tlc) { AST *stmt = tlc->chunk.statementFirst; - char *ret = strdup(""); - - #define CAT(s) do { char *b = s; ret = cat(ret, (b)); free(b); } while(0) + char *ret = malp(""); while(stmt) { - CAT(ast_dumps(stmt)); + char *new = ast_dumps(stmt); + char *ret2 = malp("%s%s", ret, new); + free(ret); + free(new); + ret = ret2; stmt = stmt->statement.next; } @@ -732,13 +727,18 @@ AST *ast_cast_expr(AST *what, Type *to) { /* Only exists at parse-time, hence not part of type system and is handled separately */ if(what->nodeKind == AST_EXPR_STRING_LITERAL) { - if(to->type == TYPE_TYPE_ARRAY && type_equal(primitive_parse("u8"), to->array.of) && to->array.length == what->exprStrLit.length) { + if(to->type == TYPE_TYPE_ARRAY && type_equal(primitive_parse("u8"), to->array.of) && (to->array.length == what->exprStrLit.length || to->array.length == -1)) { ASTExprArray *ret = calloc(1, sizeof(*ret)); ret->nodeKind = AST_EXPR_ARRAY; - ret->items = calloc(to->array.length, sizeof(*ret->items)); + ret->items = calloc(what->exprStrLit.length, sizeof(*ret->items)); ret->type = to; - for(int i = 0; i < to->array.length; i++) { + // If this declaration is of an unknown-length array type (eg u8[?]) then update the length + if(to->array.length == -1) { + to->array.length = what->exprStrLit.length; + } + + for(int i = 0; i < what->exprStrLit.length; i++) { uint8_t bajt = what->exprStrLit.data[i]; ASTExprPrimitive *item = calloc(1, sizeof(*item)); @@ -764,10 +764,10 @@ AST *ast_cast_expr(AST *what, Type *to) { } // Make sure an unparametrized generic int parameter hasn't sneaked its way in - while(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == VARTABLEENTRY_CEXPR && what->exprVar.thing->data.cexpr.concrete) { + while(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR && what->exprVar.thing->data.cexpr.concrete) { what = what->exprVar.thing->data.cexpr.concrete; } - assert(!(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == VARTABLEENTRY_CEXPR)); + assert(!(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR)); if(type_equal(what->expression.type, to)) return what; @@ -802,7 +802,7 @@ fail: struct Spill2StackState { AST *targetTLC; - VarTableEntry *target; + ScopeItem *target; // can be NULL size_t stackGrowth; }; static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { @@ -855,12 +855,14 @@ static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk } } -void ast_spill_to_stack(AST *tlc, VarTableEntry *vte) { +void ast_spill_to_stack(AST *tlc, ScopeItem *vte) { assert(tlc->nodeKind == AST_CHUNK); assert(vte != NULL); - assert(vte->kind == VARTABLEENTRY_VAR); + assert(vte->kind == SCOPEITEM_VAR); - fprintf(stderr, "Spilling %s to stack...\n", vte->data.var.name); + if(ntc_get_int("pdbg")) { + fprintf(stderr, "### SPILLING %s ###\n", vte->data.var.name); + } struct Spill2StackState state; memset(&state, 0, sizeof(state)); @@ -869,17 +871,37 @@ void ast_spill_to_stack(AST *tlc, VarTableEntry *vte) { state.stackGrowth = (type_size(vte->type) + 7) & ~7; generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor, NULL); + + size_t vteIndex = 0; + while(tlc->chunk.vars[vteIndex] != vte) vteIndex++; + + memmove(&tlc->chunk.vars[vteIndex], &tlc->chunk.vars[vteIndex + 1], sizeof(*tlc->chunk.vars) * (tlc->chunk.varCount - vteIndex - 1)); + tlc->chunk.varCount--; +} + +void ast_grow_stack_frame(AST *tlc, size_t bytes) { + if(bytes == 0) { + return; + } + + struct Spill2StackState state; + memset(&state, 0, sizeof(state)); + state.target = NULL; // spill nothing + state.targetTLC = tlc; + state.stackGrowth = bytes; + + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor, NULL); } static void typecheck_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { AST *a = *aptr; if(a->nodeKind == AST_EXPR_CALL) { - if(a->exprCall.what->expression.type != TYPE_TYPE_FUNCTION) { + if(a->exprCall.what->expression.type->type != TYPE_TYPE_FUNCTION) { stahp_node(a, "Only function types may be called."); } } else if(a->nodeKind == AST_EXPR_BINARY_OP) { - if(!type_is_number(a->exprBinOp.operands[0]) || !type_is_number(a->exprBinOp.operands[1])) { + if(!type_is_number(a->exprBinOp.operands[0]->expression.type) || !type_is_number(a->exprBinOp.operands[1]->expression.type)) { stahp_node(a, "Operands must be numbers."); } @@ -898,6 +920,25 @@ static void typecheck_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, } } -void ast_type_check(AST *tlc, VarTableEntry *vte) { +void ast_type_check(AST *tlc, ScopeItem *vte) { generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, NULL, typecheck_visitor); } + +// The commutativity pass makes sure that integer literals are always operand 1 in a binary operation +// This simplifies passes further down +static void commutativity_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + AST *n = *nptr; + + if(n->nodeKind == AST_EXPR_BINARY_OP) { + if(binop_is_commutative(n->exprBinOp.operator)) { + if(n->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && n->exprBinOp.operands[1]->nodeKind != AST_EXPR_PRIMITIVE) { + AST *tmp = n->exprBinOp.operands[0]; + n->exprBinOp.operands[0] = n->exprBinOp.operands[1]; + n->exprBinOp.operands[1] = tmp; + } + } + } +} +void ast_commutativity_pass(AST *tlc) { + generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, NULL, commutativity_visitor); +} diff --git a/src/ast.h b/src/ast.h index da55f72..ae91588 100644 --- a/src/ast.h +++ b/src/ast.h @@ -5,11 +5,6 @@ #include"lexer.h" #include"vartable.h" -// VISITORS APPEAR IN varify_change_usedefs,ast_expr_is_equal,ast_stmt_is_after, -// dumben_chunk, cg_go, loop_second_pass AND OTHERS -// -// THEY ***MUST*** BE CHANGED ACCORDINGLY IF AST IS ALTERED - #pragma pack(push, 1) #ifdef __GNUC__ @@ -47,7 +42,8 @@ K(AST_STMT_EXT_SECTION) \ K(AST_STMT_RETURN) \ K(AST_EXPR_EXT_SALLOC) \ - K(AST_EXPR_DOT) + K(AST_EXPR_DOT) \ + K(AST_EXPR_EXT_SIZEOF) typedef enum ENUMPAK { AST_KINDS(GEN_ENUM) } ASTKind; extern const char *AST_KIND_STR[]; @@ -83,6 +79,10 @@ static inline int binop_is_comparison(BinaryOp op) { return op == BINOP_EQUAL || op == BINOP_NEQUAL || op == BINOP_LESS || op == BINOP_GREATER || op == BINOP_LEQUAL || op == BINOP_GEQUAL; } +static inline int binop_is_commutative(BinaryOp op) { + return op == BINOP_ADD || op == BINOP_MUL || op == BINOP_MULHI || op == BINOP_EQUAL || op == BINOP_NEQUAL || op == BINOP_BITWISE_AND || op == BINOP_BITWISE_OR || op == BINOP_BITWISE_XOR; +} + static inline BinaryOp binop_comp_opposite(BinaryOp op) { if(op == BINOP_EQUAL) { return BINOP_NEQUAL; @@ -143,7 +143,7 @@ typedef struct { typedef struct { ASTExpr; - VarTableEntry *thing; + ScopeItem *thing; } ASTExprVar; typedef struct { @@ -171,6 +171,7 @@ typedef struct { union AST *chunk; // Necessary for when the parser jumps to a generic function + Scope *scope; Token *rangeTokens; size_t startTokI; size_t endTokI; @@ -203,7 +204,7 @@ typedef struct { typedef struct { ASTStmt; - VarTableEntry *thing; + ScopeItem *thing; union AST *expression; } ASTStmtDecl; @@ -213,11 +214,11 @@ typedef struct { /* Flattened variable array for global register allocation */ size_t varCount; - VarTableEntry **vars; + ScopeItem **vars; /* extern symbol array */ size_t externCount; - VarTableEntry **externs; + ScopeItem **externs; union AST *statementFirst; union AST *statementLast; @@ -315,6 +316,14 @@ typedef struct { union AST *val; } ASTStmtReturn; +typedef struct { + ASTExpr; + + // One of these will be NULL + union AST *ofExpr; + Type *ofType; +} ASTExprExtSizeOf; + typedef union AST { ASTBase; @@ -343,6 +352,7 @@ typedef union AST { ASTExprExtSalloc exprExtSalloc; ASTStmtExtOrg stmtExtOrg; ASTStmtExtSection stmtExtSection; + ASTExprExtSizeOf exprExtSizeOf; } AST; #pragma pack(pop) @@ -362,10 +372,12 @@ AST *ast_deep_copy(AST*); AST *ast_cast_expr(AST *what, Type *to); -void ast_spill_to_stack(AST *tlc, VarTableEntry *vte); +void ast_spill_to_stack(AST *tlc, ScopeItem *vte); void ast_typecheck(AST *tlc); +void ast_grow_stack_frame(AST *tlc, size_t bytes); + __attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...); #endif diff --git a/src/cg.c b/src/cg.c index 4eaeafe..1f5cd53 100644 --- a/src/cg.c +++ b/src/cg.c @@ -4,18 +4,12 @@ #include #include #include +#include"dumberdowner.h" +#include"reporting.h" +#include"ast.h" #include"x86.h" -#define REGS 4 -static const char *regs[][3] = { - [COLOR_EAX] = {"al", "ax", "eax"}, - [COLOR_ECX] = {"cl", "cx", "ecx"}, - [COLOR_EDX] = {"dl", "dx", "edx"}, - [COLOR_EBX] = {"bl", "bx", "ebx"}, - {"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; @@ -53,7 +47,7 @@ static const char *spec(int size) { abort(); } -static int log_size(int size) { +/*static int log_size(int size) { switch(size) { case 0: case 1: return 0; @@ -66,30 +60,38 @@ static int log_size(int size) { 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); +static const char *xv_sz(ScopeItem *v, int sz) { + assert(v->kind == SCOPEITEM_VAR); #define XVBUFS 8 -#define XVBUFSZ 8 +#define XVBUFSZ 16 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 + 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]); + } bufidx = (bufidx + 1) % XVBUFS; return ret; } -static const char *xv(VarTableEntry *v) { +static const char *xv(ScopeItem *v) { return xv_sz(v, type_size(v->type)); } @@ -116,11 +118,11 @@ static AST *is_field_access(AST *e) { e = e->exprCast.what; } - 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 == VARTABLEENTRY_SYMBOL) { + 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) { return e; } - 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 == VARTABLEENTRY_VAR) { + 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) { return e; } @@ -136,9 +138,9 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) { char *ret = bufs[bufidx]; //if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) { - if(e->nodeKind == AST_EXPR_CAST) { + /*if(e->nodeKind == AST_EXPR_CAST) { e = e->exprCast.what; - } + }*/ if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { AST *p = e->exprUnOp.operand; @@ -147,12 +149,12 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) { p = p->exprCast.what; } - 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 == VARTABLEENTRY_VAR && p->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { + 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) { 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)); - } 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 == VARTABLEENTRY_SYMBOL && p->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { + } 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) { snprintf(ret, XOPBUFSZ, "%s [%s + %s]", spec(sz), p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, @@ -170,18 +172,20 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) { } else { assert(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR); + ScopeItem *vte = e->exprBinOp.operands[0]->exprVar.thing; + snprintf(ret, XOPBUFSZ, "%s [%s + %i]", spec(sz), - regs[e->exprBinOp.operands[0]->exprVar.thing->data.var.color][2], + REG_CLASSES[vte->data.var.registerClass].rsN[vte->data.var.color], e->exprBinOp.operands[1]->exprPrim.val); } - } 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 == VARTABLEENTRY_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 == VARTABLEENTRY_VAR) { + } 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) { 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)); - } else if(p->nodeKind == AST_EXPR_VAR && p->exprVar.thing->kind == VARTABLEENTRY_VAR) { + } else if(p->nodeKind == AST_EXPR_VAR && p->exprVar.thing->kind == SCOPEITEM_VAR) { 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); @@ -190,18 +194,18 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) { } } else if(e->nodeKind == AST_EXPR_STACK_POINTER) { - snprintf(ret, XOPBUFSZ, "esp", tlc->chunk.stackReservation); + snprintf(ret, XOPBUFSZ, "esp"); } else if(e->nodeKind == AST_EXPR_VAR) { - VarTableEntry *v = e->exprVar.thing; + ScopeItem *v = e->exprVar.thing; - if(v->kind == VARTABLEENTRY_VAR) { + if(v->kind == SCOPEITEM_VAR) { return xv_sz(v, sz); - } else if(v->kind == VARTABLEENTRY_SYMBOL) { + } else if(v->kind == SCOPEITEM_SYMBOL) { snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), v->data.symbol.name); } else abort(); } else if(e->nodeKind == AST_EXPR_PRIMITIVE) { snprintf(ret, XOPBUFSZ, "%s %i", spec(type_size(e->exprPrim.type)), e->exprPrim.val); - } 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) { + } 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) { snprintf(ret, XOPBUFSZ, "%s", e->exprUnOp.operand->exprVar.thing->data.symbol.name); } else { return NULL; @@ -216,8 +220,8 @@ static const char *xop(AST *tlc, AST *e) { return xop_sz(tlc, e, type_size(e->expression.type)); } -static int ud_empty(VarTableEntry *a) { - assert(a->kind == VARTABLEENTRY_VAR); +static int ud_empty(ScopeItem *a) { + assert(a->kind == SCOPEITEM_VAR); assert(!a->data.var.usedefFirst == !a->data.var.usedefLast); return !a->data.var.usedefFirst; @@ -251,8 +255,8 @@ void cg_chunk(CGState *cg, AST *a) { printf("align %u\n", val); } - } else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == VARTABLEENTRY_SYMBOL) { - VarTableEntry *v = s->stmtDecl.thing; + } else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == SCOPEITEM_SYMBOL) { + ScopeItem *v = s->stmtDecl.thing; if(v->data.symbol.isExternal) { // Do nothing. @@ -287,6 +291,8 @@ void cg_chunk(CGState *cg, AST *a) { // Generic functions have non-NULL code blocks if(!type_is_generic(s->stmtDecl.expression->expression.type)) { + dumben_pre(s->stmtDecl.expression->exprFunc.chunk); + dumben_go(s->stmtDecl.expression->exprFunc.chunk); while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) { dumben_go(s->stmtDecl.expression->exprFunc.chunk); @@ -302,7 +308,7 @@ void cg_chunk(CGState *cg, AST *a) { } } - } else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.to && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { + } 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) { AST *e = s->stmtAssign.to; @@ -319,7 +325,7 @@ void cg_chunk(CGState *cg, AST *a) { 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); + assert(e->exprCall.what->nodeKind == AST_EXPR_VAR && e->exprCall.what->exprVar.thing->kind == SCOPEITEM_SYMBOL); printf("call %s\n", e->exprCall.what->exprVar.thing->data.symbol.name); @@ -335,17 +341,17 @@ void cg_chunk(CGState *cg, AST *a) { } else if(s->stmtAssign.to) { 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); - assert(s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR); + assert(s->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR); if(!strcmp(xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[0]))) { - printf("imul %s, %s\n", xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[1])); + printf("imul %s, %s, %s\n", xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[1])); } 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); - assert(s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR); - assert(s->stmtAssign.what->exprVar.thing->data.var.color == COLOR_EDX); + assert(s->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR); + //assert(s->stmtAssign.what->exprVar.thing->data.var.color == COLOR_EDX); assert(s->statement.next->nodeKind == AST_STMT_ASSIGN); assert(s->statement.next->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP); @@ -374,42 +380,51 @@ void cg_chunk(CGState *cg, AST *a) { 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])); - } 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) { + } 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) { 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) { + } 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) { 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) { + } 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) { 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)) { + } 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)) { printf("neg %s\n", xop(cg->tlc, s->stmtAssign.what)); - - } else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST && 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)); + } else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST) { + + 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)); + + } 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); + + if(strcmp(dest, src)) { + printf("mov %s, %s\n", dest, src); + } + + } } 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(cg->tlc, s->stmtAssign.what, 4), xop_sz(cg->tlc, s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); - } else { - printf("mov %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop_sz(cg->tlc, s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); - } + printf("mov %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to)); } } @@ -458,8 +473,8 @@ void cg_chunk(CGState *cg, AST *a) { if(s->stmtReturn.val) { assert(s->stmtReturn.val->nodeKind == AST_EXPR_VAR); - assert(s->stmtReturn.val->exprVar.thing->kind == VARTABLEENTRY_VAR); - assert(s->stmtReturn.val->exprVar.thing->data.var.color == COLOR_EAX); + assert(s->stmtReturn.val->exprVar.thing->kind == SCOPEITEM_VAR); + //assert(s->stmtReturn.val->exprVar.thing->data.var.color == COLOR_EAX); } if(a->chunk.stackReservation) { @@ -487,7 +502,7 @@ void cg_chunk(CGState *cg, AST *a) { } struct Spill2VarState { - VarTableEntry *target; + ScopeItem *target; }; static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { static size_t vidx = 0; @@ -497,12 +512,12 @@ static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *a = *aptr; if(a->nodeKind == AST_STMT_ASSIGN && a->stmtAssign.to->nodeKind == AST_EXPR_CALL) { - assert(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR); + assert(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR); if(a->stmtAssign.what->exprVar.thing == this->target) { - VarTableEntry *new = calloc(1, sizeof(*new)); - new->kind = VARTABLEENTRY_VAR; + ScopeItem *new = calloc(1, sizeof(*new)); + new->kind = SCOPEITEM_VAR; new->type = a->stmtAssign.what->exprVar.thing->type; new->data.var.name = malp("$s2v_%lu", vidx++); @@ -538,8 +553,8 @@ static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, if(a->nodeKind == AST_STMT_RETURN && a->stmtReturn.val && a->stmtReturn.val->nodeKind == AST_EXPR_VAR && a->stmtReturn.val->exprVar.thing == this->target) { - VarTableEntry *new = calloc(1, sizeof(*new)); - new->kind = VARTABLEENTRY_VAR; + ScopeItem *new = calloc(1, sizeof(*new)); + new->kind = SCOPEITEM_VAR; new->type = a->stmtReturn.val->exprVar.thing->type; new->data.var.name = malp("$s2v_%lu", vidx++); @@ -573,14 +588,14 @@ static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, } } -struct PrecolorState { - VarTableEntry *mustBeSpilled; +/*struct PrecolorState { + ScopeItem *mustBeSpilled; }; static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { struct PrecolorState *this = ud; if(this->mustBeSpilled) { - /* Since something must be spilled first, we can't do anything else. Quit ASAP. */ + // Since something must be spilled first, we can't do anything else. Quit ASAP. return; } @@ -594,9 +609,9 @@ static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A } if(n->nodeKind == AST_STMT_RETURN && n->stmtReturn.val) { - assert(n->stmtReturn.val->nodeKind == AST_EXPR_VAR && n->stmtReturn.val->exprVar.thing->kind == VARTABLEENTRY_VAR); + assert(n->stmtReturn.val->nodeKind == AST_EXPR_VAR && n->stmtReturn.val->exprVar.thing->kind == SCOPEITEM_VAR); - VarTableEntry *vte = n->stmtReturn.val->exprVar.thing; + ScopeItem *vte = n->stmtReturn.val->exprVar.thing; const int requiredColor = COLOR_EAX; @@ -609,9 +624,9 @@ static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A vte->data.var.color = requiredColor; vte->data.var.precolored = true; } else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.to->nodeKind == AST_EXPR_CALL) { - assert(n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR); + assert(n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR); - VarTableEntry *vte = n->stmtAssign.what->exprVar.thing; + ScopeItem *vte = n->stmtAssign.what->exprVar.thing; const int requiredColor = COLOR_EAX; @@ -623,9 +638,9 @@ static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A vte->data.var.color = requiredColor; vte->data.var.precolored = true; - } else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MUL) { + } 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) { - VarTableEntry *vte = n->stmtAssign.what->exprVar.thing; + ScopeItem *vte = n->stmtAssign.what->exprVar.thing; const int requiredColor = COLOR_EAX; @@ -637,9 +652,9 @@ static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A vte->data.var.color = requiredColor; vte->data.var.precolored = true; - } else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MULHI) { + } 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) { - VarTableEntry *vte = n->stmtAssign.what->exprVar.thing; + ScopeItem *vte = n->stmtAssign.what->exprVar.thing; const int requiredColor = COLOR_EDX; @@ -652,22 +667,26 @@ static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A vte->data.var.color = requiredColor; vte->data.var.precolored = true; } -} +}*/ -typedef VarTableEntry *Adjacency[2]; +typedef ScopeItem *Adjacency[2]; -static bool var_collision(AST *tlc, VarTableEntry *v1, VarTableEntry *v2) { +static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) { /* 1D intersection test */ - return !ud_empty(v1) && !ud_empty(v2) && ( + bool liveRangeIntersection = !ud_empty(v1) && !ud_empty(v2) && ( (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) ); + + bool resourceIntersection = (REG_CLASSES[v1->data.var.registerClass].rMask & REG_CLASSES[v2->data.var.registerClass].rMask) != 0; + + return liveRangeIntersection && resourceIntersection; } -static VarTableEntry *get_precolor_spill_candidate(AST *tlc) { +/*static ScopeItem *get_precolor_spill_candidate(AST *tlc) { Adjacency *adjs = NULL; size_t adjCount = 0; @@ -699,7 +718,7 @@ static VarTableEntry *get_precolor_spill_candidate(AST *tlc) { adjs[a][1]->data.var.degree++; } - VarTableEntry *maxdeg = tlc->chunk.vars[0]; + ScopeItem *maxdeg = tlc->chunk.vars[0]; for(size_t v = 1; v < tlc->chunk.varCount; v++) { if(maxdeg->data.var.degree < tlc->chunk.vars[v]->data.var.degree) { @@ -710,11 +729,13 @@ static VarTableEntry *get_precolor_spill_candidate(AST *tlc) { free(adjs); return maxdeg; -} +}*/ struct CalleeSavedState { AST *targetTLC; - VarTableEntry *ebxuser; + + ScopeItem *calleeUsers[MAX_REGS_PER_CLASS]; + size_t calleeOffsets[MAX_REGS_PER_CLASS]; // To make sure we don't process the same return statement to infinity AST *lastProcessedReturn; @@ -732,122 +753,191 @@ static void callee_saved_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chun if(n == tlc) { // Function entry - 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 = tlc->chunk.stackReservation; - - 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 = this->ebxuser->type; - ev->thing = this->ebxuser; - - 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); - - tlc->chunk.stackReservation += 4; + 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); + } } else if(n->nodeKind == AST_STMT_RETURN && n != this->lastProcessedReturn) { // Function exit this->lastProcessedReturn = n; - 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 = tlc->chunk.stackReservation; - - 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 = this->ebxuser->type; - ev->thing = this->ebxuser; - - 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; + 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; } } } static void callee_saved(AST *tlc) { - VarTableEntry *ebxuser = NULL; + ScopeItem *ebxuser = NULL, *ediuser = NULL, *esiuser = NULL; for(size_t v = 0; v < tlc->chunk.varCount; v++) { - if(tlc->chunk.vars[v]->data.var.color == COLOR_EBX) { + if(is_reg_b(tlc->chunk.vars[v]->data.var.registerClass, tlc->chunk.vars[v]->data.var.color)) { ebxuser = tlc->chunk.vars[v]; - break; + } + 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]; } } + struct CalleeSavedState state = {}; + state.targetTLC = tlc; + + size_t nextUser = 0; if(ebxuser) { - struct CalleeSavedState state; - state.targetTLC = tlc; - state.ebxuser = ebxuser; - + 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) { generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, callee_saved_visitor, NULL); } } +/*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); +} + /* Welsh-Powell graph coloring */ static int comparator(const void *A, const void *B) { - VarTableEntry *const *a = A; - VarTableEntry *const *b = B; + ScopeItem *const *a = A; + ScopeItem *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) { assert(a->nodeKind == AST_CHUNK); for(size_t e = 0; e < a->chunk.externCount; e++) { - assert(a->chunk.externs[e]->kind == VARTABLEENTRY_SYMBOL); + assert(a->chunk.externs[e]->kind == SCOPEITEM_SYMBOL); assert(a->chunk.externs[e]->data.symbol.isExternal); printf("extern %s\n", a->chunk.externs[e]->data.symbol.name); @@ -858,27 +948,30 @@ int cg_go(AST *a) { size_t adjCount = 0; Adjacency *adjs = calloc(adjCount, sizeof(*adjs)); - VarTableEntry **vars = a->chunk.vars; + ScopeItem **vars = a->chunk.vars; for(size_t vi = 0; vi < a->chunk.varCount; vi++) { vars[vi]->data.var.priority = 1; vars[vi]->data.var.degree = 0; + vars[vi]->data.var.registerClass = -1; if(!vars[vi]->data.var.precolored) { vars[vi]->data.var.color = -1; } } + determine_register_classes(a); + 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]; + ScopeItem *v1 = vars[v1i]; + ScopeItem *v2 = vars[v2i]; if(var_collision(a, v1, v2)) { - VarTableEntry *min = v1 < v2 ? v1 : v2; - VarTableEntry *max = v1 < v2 ? v2 : v1; + ScopeItem *min = v1 < v2 ? v1 : v2; + ScopeItem *max = v1 < v2 ? v2 : v1; for(size_t a = 0; a < adjCount; a++) { if(adjs[a][0] == min && adjs[a][1] == max) { @@ -902,7 +995,7 @@ cont:; qsort(vars, a->chunk.varCount, sizeof(*vars), comparator); - int lastColor = 0; + int mustSpillRegisterClass = -1; /* Welsh plow my ass */ for(int v = 0; v < a->chunk.varCount; v++) { @@ -912,18 +1005,42 @@ cont:; } for(int c = 0;; c++) { + 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; + } + 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) { + 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) { goto nextColor; } } - + vars[v]->data.var.color = c; - lastColor = lastColor < c ? c : lastColor; - break; nextColor:; @@ -932,12 +1049,12 @@ nextColor:; free(adjs); - if(lastColor >= 4) { + if(mustSpillRegisterClass != -1) { // Spill node with highest degree - VarTableEntry *chosen = NULL; + ScopeItem *chosen = NULL; for(ssize_t i = a->chunk.varCount - 1; i >= 0; i--) { - if(!vars[i]->data.var.precolored) { + if(!vars[i]->data.var.precolored && vars[i]->data.var.registerClass == mustSpillRegisterClass) { chosen = vars[i]; break; } diff --git a/src/dstr.c b/src/dstr.c deleted file mode 100644 index e087341..0000000 --- a/src/dstr.c +++ /dev/null @@ -1,141 +0,0 @@ -#include"dstr.h" - -#include -#include -#include -#include - -static int ilen(int i) { - if(i == 0) return 1; - - int ret = 0; - if(i < 0) { - ret = 1; - i = -i; - } - while(i > 0) { - ret++; - i = i / 10; - } - return ret; -} - -static char *myitoa(int src) { - static char ret[12]; - snprintf(ret, 12, "%i", src); - return ret; -} - -typedef struct { - size_t length; - char data[]; -} dstrInternal; - -dstr dstrempty() { - dstrInternal *i = malloc(sizeof(dstrInternal) + 1); - i->length = 0; - i->data[0] = '\0'; - return (dstr) i + sizeof(dstrInternal); -} - -dstr dstrz(const char *src) { - size_t len = strlen(src); - dstrInternal *i = malloc(sizeof(dstrInternal) + len + 1); - i->length = len; - memcpy(i->data, src, len + 1); - return (dstr) i + sizeof(dstrInternal); -} - -dstr dstrfmt(dstr original, const char *fmt, ...) { - dstrInternal *originalInternal = (dstrInternal*) (original - sizeof(dstrInternal)); - - const char *start = fmt; - - va_list list; - va_start(list, fmt); - - size_t totalLength = 0; - - while(*fmt) { - if(*fmt == '%') { - switch(*++fmt) { - case 's': - totalLength += strlen(va_arg(list, char*)); - break; - case 'c': - if(va_arg(list, int)) totalLength++; - break; - case 'S': { - dstrInternal *i = (dstrInternal*) (va_arg(list, dstr) - sizeof(dstrInternal)); - totalLength += i->length; - break; - } - case 'i': - totalLength += ilen(va_arg(list, int)); - break; - default: { - totalLength++; - } - } - } else totalLength++; - - fmt++; - } - - va_end(list); - - fmt = start; - - originalInternal = realloc(originalInternal, sizeof(dstrInternal) + originalInternal->length + totalLength + 1); - - va_start(list, fmt); - - char *dst = originalInternal->data + originalInternal->length; - originalInternal->length += totalLength; - originalInternal->data[originalInternal->length] = 0; - - while(*fmt) { - if(*fmt == '%') { - switch(*++fmt) { - case 's': { - char *asdfasdf = va_arg(list, char*); - strcpy(dst, asdfasdf); - dst += strlen(asdfasdf); - break; - } - case 'c': { - int c = va_arg(list, int); - if(c) { - *(dst++) = c; - } - break; - } - case 'S': { - dstrInternal *i = (dstrInternal*) (va_arg(list, dstr) - sizeof(dstrInternal)); - memcpy(dst, i->data, i->length); - dst += i->length; - break; - } - case 'i': { - const char *asdf = myitoa(va_arg(list, int)); - strcpy(dst, asdf); - dst += strlen(asdf); - break; - } - default: { - *(dst++) = *fmt; - } - } - } else { - *(dst++) = *fmt; - } - fmt++; - } - va_end(list); - - return (dstr) originalInternal + sizeof(dstrInternal); -} - -void dstrfree(dstr s) { - free(s - sizeof(dstrInternal)); -} diff --git a/src/dstr.h b/src/dstr.h deleted file mode 100644 index 50bf4e0..0000000 --- a/src/dstr.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _DSTR_H -#define _DSTR_H - -#include - -/* Originally used sds, but it didn't support OpenWatcom. This isn't as optimized, but it's good enough. */ - -typedef char *dstr; - -dstr dstrempty(); -dstr dstrraw(const char*); -dstr dstrfmt(dstr, const char*, ...); -void dstrfree(dstr); - -#endif diff --git a/src/dumberdowner.c b/src/dumberdowner.c index dff0b15..80de349 100644 --- a/src/dumberdowner.c +++ b/src/dumberdowner.c @@ -2,6 +2,10 @@ #include #include +#include + +#include"x86.h" +#include"reporting.h" // This is the dumbing down pass. // @@ -11,14 +15,11 @@ // This file along with CG is strictly for IA-32 and will fail for other // architectures. -#include"x86.h" -#include - -static VarTableEntry *create_dumbtemp(AST *tlc, Type *itstype) { +static ScopeItem *create_dumbtemp(AST *tlc, Type *itstype) { static size_t vidx = 0; - VarTableEntry *vte = calloc(1, sizeof(*vte)); - vte->kind = VARTABLEENTRY_VAR; + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_VAR; vte->type = itstype; vte->data.var.color = -1; vte->data.var.precolored = false; @@ -36,7 +37,7 @@ static VarTableEntry *create_dumbtemp(AST *tlc, Type *itstype) { /* Split away complex expression into a new local variable */ static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) { - VarTableEntry *vte = create_dumbtemp(tlc, e->expression.type); + ScopeItem *vte = create_dumbtemp(tlc, e->expression.type); // Alter AST @@ -118,12 +119,12 @@ 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 == VARTABLEENTRY_VAR && retval->exprVar.thing->data.var.color != COLOR_EAX))) { + 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')))) { retval = s->stmtReturn.val = varify(tlc, chu, stmtPrev, s, retval); this->effective = 1; - vte_precolor(retval->exprVar.thing, COLOR_EAX); + vte_precolor(retval->exprVar.thing, REG_CLASS_16_32, 1); } @@ -136,7 +137,7 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * s->stmtExpr.expr = varify(tlc, chu, stmtPrev, s, s->stmtExpr.expr); - vte_precolor(s->stmtExpr.expr->exprVar.thing, COLOR_EAX); + vte_precolor(s->stmtExpr.expr->exprVar.thing, REG_CLASS_16_32, 1); // Purge this statement entirely, otherwise we'd have // a = f(x); @@ -160,9 +161,10 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * this->effective = 1; } else { - if(s->stmtAssign.to->nodeKind == AST_EXPR_CALL && (s->stmtAssign.what->nodeKind != AST_EXPR_VAR || s->stmtAssign.what->exprVar.thing->kind != VARTABLEENTRY_VAR)) { + if(s->stmtAssign.to->nodeKind == AST_EXPR_CALL && (s->stmtAssign.what->nodeKind != AST_EXPR_VAR || s->stmtAssign.what->exprVar.thing->kind != SCOPEITEM_VAR || !s->stmtAssign.what->exprVar.thing->data.var.precolored)) { - VarTableEntry *tmp = create_dumbtemp(tlc, s->stmtAssign.what->expression.type); + ScopeItem *tmp = create_dumbtemp(tlc, s->stmtAssign.what->expression.type); + vte_precolor(tmp, REG_CLASS_16_32, 1); ASTExprVar *ev[2] = {calloc(1, sizeof(**ev)), calloc(1, sizeof(**ev))}; ev[0]->nodeKind = AST_EXPR_VAR; @@ -193,7 +195,7 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * s->stmtAssign.what->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what->exprUnOp.operand); this->effective = 1; - } else if(s->stmtAssign.what && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { + } else if(s->stmtAssign.what && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { ASTExprCall *call = &s->stmtAssign.to->exprCall; int argCount = call->what->expression.type->function.argCount; @@ -272,7 +274,7 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * AST *hihalf = varify(tlc, chu, stmtPrev->statement.next, s, mulhi); - vte_precolor(hihalf->exprVar.thing, COLOR_EDX); + vte_precolor(hihalf->exprVar.thing, REG_CLASS_16_32, 7); } s->stmtAssign.what = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[0]); @@ -285,7 +287,7 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * s->stmtAssign.next = (AST*) redest; - vte_precolor(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, COLOR_EAX); + vte_precolor(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, REG_CLASS_16_32, 1); this->effective = 1; } else assert(because == NOT_AT_ALL_IT || because == GUCCI); @@ -318,6 +320,9 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && !is_xop(s->stmtAssign.to->exprBinOp.operands[1])) { s->stmtAssign.to->exprBinOp.operands[1] = xopify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[1]); this->effective = 1; + } else if(s->stmtAssign.to->nodeKind == AST_EXPR_CAST && s->stmtAssign.to->exprCast.what->nodeKind != AST_EXPR_VAR) { + s->stmtAssign.to->exprCast.what = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprCast.what); + this->effective = 1; } } } @@ -328,13 +333,13 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { AST *n = *nptr; - if(n == tlc) { + if(n == ud) { if(tlc->chunk.functionType) { size_t argCount = n->chunk.functionType->function.argCount; // First argCount vtes in list are the arguments for(size_t i = 0; i < argCount; i++) { - VarTableEntry *vte = n->chunk.vars[i]; + ScopeItem *vte = n->chunk.vars[i]; ASTExprStackPointer *stck = calloc(1, sizeof(*stck)); stck->nodeKind = AST_EXPR_STACK_POINTER; @@ -470,12 +475,28 @@ static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *nptr = n->exprCast.what; + *success = true; + } else if(n->nodeKind == AST_EXPR_EXT_SIZEOF) { + ASTExprPrimitive *prim = calloc(1, sizeof(*prim)); + prim->nodeKind = AST_EXPR_PRIMITIVE; + prim->type = n->expression.type; + + assert(!!n->exprExtSizeOf.ofExpr != !!n->exprExtSizeOf.ofType); + + if(n->exprExtSizeOf.ofType) { + prim->val = type_size(n->exprExtSizeOf.ofType); + } else { + prim->val = type_size(n->exprExtSizeOf.ofExpr->expression.type); + } + + *nptr = (AST*) prim; + *success = true; } } void dumben_pre(AST *tlc) { - generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor, NULL); + generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, pre_dumb_visitor, NULL); generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, decompose_symbol_record_field_access, NULL); for(size_t t = 0; t < tlc->chunk.varCount; t++) { @@ -484,23 +505,28 @@ void dumben_pre(AST *tlc) { } } + if(ntc_get_int("pdbg")) { + char *astdump = ast_dump(tlc); + fprintf(stderr, "### BEFORE DENOOP ###\n%s\n", astdump); + free(astdump); + } + bool success; do { success = false; generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor, NULL); } while(success); + + ast_commutativity_pass(tlc); } void dumben_go(AST* tlc) { size_t i = 0; while(1) { if(i == 20000) { - puts("TOO MANY DUMBS"); - abort(); + stahp(0, 0, "TOO MANY DUMBS. TOO MANY DUMBS."); } - fprintf(stderr, "; Dumbing down %lu...\n", i++); - struct DumbenState state; memset(&state, 0, sizeof(state)); @@ -512,6 +538,11 @@ void dumben_go(AST* tlc) { break; } - fputs(ast_dump(tlc), stderr); + if(ntc_get_int("pdbg")) { + fprintf(stderr, "### DUMBED DOWN %lu ###\n", i++); + char *astdump = ast_dump(tlc); + fputs(astdump, stderr); + free(astdump); + } } } diff --git a/src/lexer.c b/src/lexer.c index 6b4eb27..d3b2019 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -225,6 +225,7 @@ Token nct_tokenize(FILE *f) { if(c == '0') c = 0; else if(c == 'n') c = '\n'; + else if(c == 'r') c = '\r'; else if(c == 't') c = '\t'; } @@ -354,6 +355,9 @@ Token *nct_lex(FILE *f) { size_t length = 8, index = 0; Token *list = malloc(sizeof(*list) * length); + currentRow = 1; + currentColumn = 0; + while(1) { list[index] = nct_tokenize(f); diff --git a/src/ntc.c b/src/ntc.c index 76ffb68..0115adc 100644 --- a/src/ntc.c +++ b/src/ntc.c @@ -1,6 +1,7 @@ #include #include #include +#include #include"lexer.h" #include"parse.h" @@ -9,19 +10,45 @@ #include"cg.h" #include"dumberdowner.h" #include"x86.h" +#include"utils.h" static int argc; static char **argv; -const char* ntc_get_arg(const char *name) { - for(int i = 1; i < argc; i++) { - if(strstr(argv[i], name) == argv[i]) { - return argv[i] + strlen(name) + 1; +static char **includePaths; +const char **ntc_get_import_paths() { + return (const char**) includePaths; +} + +static const char *ntc_get_arg_from(size_t *i, const char *name) { + for(; *i < argc; (*i)++) { + if(strstr(argv[*i], name) == argv[*i]) { + return argv[*i] + strlen(name) + 1; } } return NULL; } +const char* ntc_get_arg(const char *name) { + size_t i = 1; + return ntc_get_arg_from(&i, name); +} + +intmax_t ntc_get_int(const char *name) { + const char *val = ntc_get_arg(name); + + if(!val) { + return 0; + } + + long result = 0; + if(!unstupid_strtol(val, (const char**) &val, 0, &result)) { + return 0; + } + + return result; +} + int main(int argc_, char **argv_) { argc = argc_; argv = argv_; @@ -32,8 +59,26 @@ int main(int argc_, char **argv_) { const char *in = ntc_get_arg("in"); + size_t includePathsCount = 1; + includePaths = malloc(sizeof(*includePaths)); + includePaths[0] = strdup(in ? dirname(strdup(in)) : "."); + for(size_t i = 1; i < argc; i++) { + const char *path = ntc_get_arg_from(&i, "inc"); + + if(!path) { + break; + } + + includePaths = realloc(includePaths, sizeof(*includePaths) * (++includePathsCount)); + includePaths[includePathsCount - 1] = path; + } + FILE *f = in ? fopen(in, "rb") : stdin; + if(!f) { + stahp(0, 0, "Failed to read input (%s)", strerror(errno)); + } + Token *tokens = nct_lex(f); if(in) fclose(f); @@ -42,23 +87,23 @@ int main(int argc_, char **argv_) { free(tokens); - fputs("; === Original AST ===\n", stderr); - fputs(ast_dump(chunk), stderr); - fputc('\n', stderr); + if(ntc_get_int("pdbg")) { + char *astdump = ast_dump(chunk); + fprintf(stderr, "### ORIGINAL ###\n%s\n", astdump); + free(astdump); + } dumben_pre(chunk); dumben_go(chunk); - fputs("\n; === Dumbified ===\n", stderr); - fputs(ast_dump(chunk), stderr); - fputc('\n', stderr); - while(!cg_go(chunk)) { dumben_go(chunk); - fputs("\n; === Spill ===\n", stderr); - fputs(ast_dump(chunk), stderr); - fputc('\n', stderr); + if(ntc_get_int("pdbg")) { + char *astdump = ast_dump(chunk); + fprintf(stderr, "### CG FAILURE ###\n%s\n", astdump); + free(astdump); + } } return 0; diff --git a/src/ntc.h b/src/ntc.h index a1fba8d..84bc5ef 100644 --- a/src/ntc.h +++ b/src/ntc.h @@ -1,6 +1,13 @@ #ifndef NTC_H #define NTC_H +#include +#include + +const char **ntc_get_import_paths(); + const char* ntc_get_arg(const char *name); -#endif \ No newline at end of file +intmax_t ntc_get_int(const char *name); + +#endif diff --git a/src/optims.c b/src/optims.c deleted file mode 100644 index fefbfc5..0000000 --- a/src/optims.c +++ /dev/null @@ -1,75 +0,0 @@ -#include"optims.h" - -#include - -// Currently performs only copy propagation. -// But CP is NECESSARY, otherwise it creates too many variables -// that are unable to be coalesced by the regallocator - -void optim_chunk(ASTChunk *chu) { - /*AST *s = chu->statementFirst, *sPrev = NULL; - while(s) { - if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_VAR) { - VarTableEntry *dst = ((AST*) s->stmtAssign.what)->exprVar.thing; - VarTableEntry *src = ((AST*) s->stmtAssign.to)->exprVar.thing; - - if(dst->kind == VARTABLEENTRY_VAR && src->kind == VARTABLEENTRY_VAR) { - // Find reaching source definition - - UseDef *srcUD = src->data.var.usedefFirst; - while(srcUD && srcUD->use != s->stmtAssign.to) { - srcUD = srcUD->next; - } - - if(!srcUD) { - goto copypropfail; - } - - // Find first use of this def - - UseDef *dstUDPrev = NULL; - UseDef *dstUD = dst->data.var.usedefFirst; - while(dstUD->def != s) { - dstUDPrev = dstUD; - dstUD = dstUD->next; - } - - // Update all definitions - - while(dstUD && dstUD->def == s) { - ((AST*) dstUD->use)->exprVar.thing = src; - - UseDef *next = dstUD->next; - - dstUD->def = srcUD->def; - dstUD->next = srcUD->next; - srcUD->next = dstUD; - - dstUD = next; - - if(dstUDPrev) { - dstUDPrev->next = dstUD; - } else { - dst->data.var.usedefFirst = dstUD; - } - } - - if(!dstUD) { - // dst was never used again -> DELETE ASSIGNMENT COMPLETELY - - if(sPrev) { - sPrev->statement.next = s->statement.next; - // TODO: free - } - } - - recalc_lifespan(dst); - recalc_lifespan(src); - } - } - -copypropfail: - sPrev = s; - s = s->statement.next; - }*/ -} \ No newline at end of file diff --git a/src/optims.h b/src/optims.h deleted file mode 100644 index c1247fe..0000000 --- a/src/optims.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include"ast.h" - -void optim_chunk(ASTChunk*); \ No newline at end of file diff --git a/src/parse.c b/src/parse.c index b2fa04a..bc60309 100644 --- a/src/parse.c +++ b/src/parse.c @@ -29,7 +29,7 @@ typedef struct { Token *tokens; intmax_t i; - VarTable *scope; + Scope *scope; // Used to coalesce all scopes into one after parsing, to perform global register allocation ASTChunk *topLevel; @@ -38,7 +38,7 @@ typedef struct { ASTChunk *currentChunk; // Used to place guard variable uses after loops to stop reg allocation from fucking up - VarTable *loopScope; + Scope *loopScope; size_t guardedVarCount; ASTExprVar **guardedVars; @@ -112,7 +112,7 @@ static ASTExprPrimitive *parse_prim(Parser *P) { Token tok = get(P); const char *str = tok.content; - int base = 10; + long base = 10; if(strchr(str, 'r')) { if(!unstupid_strtol(str, (char**) &str, 10, &base)) { return NULL; @@ -120,10 +120,13 @@ static ASTExprPrimitive *parse_prim(Parser *P) { str++; /* Go past the r. */ } - if(!unstupid_strtol(str, NULL, base, &ret->val)) { + long val; + if(!unstupid_strtol(str, NULL, base, &val)) { return NULL; } + ret->val = val; + // Smallest integer type to store number char buf[8]; snprintf(buf, sizeof(buf), "s%i", ret->val ? (64 - __builtin_clzl(ret->val - 1)) : 1); @@ -132,8 +135,8 @@ static ASTExprPrimitive *parse_prim(Parser *P) { return ret; } -static AST *exprvar(Parser *P, VarTableEntry *v) { - assert(v->kind != VARTABLEENTRY_TYPE); +static AST *exprvar(Parser *P, ScopeItem *v) { + assert(v->kind != SCOPEITEM_TYPE); AST *a = alloc_node(P, sizeof(ASTExprVar)); @@ -145,7 +148,7 @@ static AST *exprvar(Parser *P, VarTableEntry *v) { // XXX: O(n)!!!!!!!!! int inloop = 0; - for(VarTable *vt = v->owner; vt; vt = vt->parent) { + for(Scope *vt = v->owner; vt; vt = vt->parent) { if(vt->parent == P->loopScope) { inloop = 1; break; @@ -174,10 +177,10 @@ static AST *exprvar(Parser *P, VarTableEntry *v) { return a; } -ASTChunk *nct_parse_chunk(Parser*, int, int, VarTable*, Type *ft); +ASTChunk *nct_parse_chunk(Parser*, int, int, Scope*, Type *ft); Type *nct_parse_typename(Parser *P); -static bool parse_parametrization(Parser *P, Parametrizations *parametrizations); -static char *parametrize_function_name(Type *t, const char *original, Parametrization *types, Parametrization *ints); +static bool parse_parametrization(Parser *P); +static char *parametrize_function_name(Type *t, const char *original, Scope *scope); static void binop_implicit_cast(/*Parser *P, */ASTExprBinaryOp *binop) { if(type_size(binop->operands[0]->expression.type) < type_size(binop->operands[1]->expression.type)) { @@ -230,7 +233,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { P->isInFunction++; - e->chunk = (AST*) nct_parse_chunk(P, 1, 0, vartable_new(P->scope), ft); + e->chunk = (AST*) nct_parse_chunk(P, 1, 0, scope_new(P->scope), ft); e->chunk->chunk.functionType = ft; P->isInFunction--; @@ -238,6 +241,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { expect(P, TOKEN_SQUIGGLY_R); } + e->scope = P->scope; e->rangeTokens = P->tokens; e->startTokI = startTokI; e->endTokI = P->i; @@ -272,11 +276,25 @@ AST *nct_parse_expression(Parser *P, int lOP) { expect(P, TOKEN_PAREN_R); + e = (AST*) ret; + } else if(!strcmp(peek(P, 0).content, "@sizeof")) { + get(P); + + ASTExprExtSizeOf *ret = alloc_node(P, sizeof(*ret)); + ret->nodeKind = AST_EXPR_EXT_SIZEOF; + + ret->ofType = nct_parse_typename(P); + if(!ret->ofType) { + ret->ofExpr = nct_parse_expression(P, lOP - 1); + } + + ret->type = primitive_parse("u32"); + e = (AST*) ret; } else { Token varname = get(P); - VarTableEntry *vte = vartable_find(P->scope, varname.content); + ScopeItem *vte = scope_find(P->scope, varname.content); if(!vte) { stahp(varname.row, varname.column, "Unknown variable %s", varname.content); @@ -413,18 +431,20 @@ AST *nct_parse_expression(Parser *P, int lOP) { ret = (AST*) call; } else if(peek(P, 0).type == TOKEN_SQUAREN_L) { - Parametrizations parametrizations = {}; - if(parse_parametrization(P, ¶metrizations)) { + + P->scope = scope_new(P->scope); + + if(parse_parametrization(P)) { // Generic type parametrization // Generic functions are not first-class assert(ret->nodeKind == AST_EXPR_VAR); assert(ret->exprVar.thing != NULL); - assert(ret->exprVar.thing->kind == VARTABLEENTRY_SYMBOL); + assert(ret->exprVar.thing->kind == SCOPEITEM_SYMBOL); - char *cname = parametrize_function_name(ret->expression.type, ret->exprVar.thing->data.symbol.name, parametrizations.typeParams, parametrizations.intParams); + char *cname = parametrize_function_name(ret->expression.type, ret->exprVar.thing->data.symbol.name, P->scope); - VarTableEntry *cvte = vartable_get(P->scope, cname); + ScopeItem *cvte = scope_find(P->scope, cname); if(!cvte) { stahp_token(&P->tokens[P->i], "Parametrization %s not found.", cname); @@ -457,11 +477,12 @@ 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("u16"); + scale->type = primitive_parse("u32"); scale->val = typesize; ASTExprBinaryOp *mul = alloc_node(P, sizeof(*mul)); mul->nodeKind = AST_EXPR_BINARY_OP; + mul->type = child->operands[1]->expression.type; mul->operator = BINOP_MUL; mul->operands[0] = (AST*) scale; mul->operands[1] = child->operands[1]; @@ -479,6 +500,9 @@ AST *nct_parse_expression(Parser *P, int lOP) { ret = (AST*) unop; } + + P->scope = P->scope->parent; + } else abort(); } @@ -615,26 +639,23 @@ AST *nct_parse_expression(Parser *P, int lOP) { return NULL; } +// This function modifies the current scope. // This function may backtrack. -static bool parse_parametrization(Parser *P, Parametrizations *parametrizations) { +static bool parse_parametrization(Parser *P) { size_t oldIdx = P->i; if(!maybe(P, TOKEN_SQUAREN_L)) { goto backtrack; } + intmax_t idx = 0; bool integerMode = false; - Parametrization *head = NULL; - Parametrization *last = NULL; - while(1) { if(maybe(P, TOKEN_SQUAREN_R)) { break; } - Parametrization *par = calloc(1, sizeof(*par)); - if(integerMode) { AST *n = nct_parse_expression(P, 0); @@ -642,7 +663,16 @@ static bool parse_parametrization(Parser *P, Parametrizations *parametrizations) goto backtrack; } - par->param = n; + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_CEXPR; + vte->type = n->expression.type; + vte->data.cexpr.concrete = n; + vte->data.cexpr.paramIdx = idx; + + char buf[64]; + snprintf(buf, sizeof(buf), "%li%s", idx, "i"); + + scope_set(P->scope, buf, vte); } else { Type *t = nct_parse_typename(P); @@ -650,35 +680,26 @@ static bool parse_parametrization(Parser *P, Parametrizations *parametrizations) goto backtrack; } - par->param = t; - } - - if(!par->param) { - goto backtrack; - } - - if(!head) { - head = par; - last = head; + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_TYPE; + vte->type = t; + vte->data.type.ptr = t; - if(integerMode) { - parametrizations->intParams = head; - } else { - parametrizations->typeParams = head; - } - } else if(last) { - last->next = par; - last = par; + char buf[64]; + snprintf(buf, sizeof(buf), "%li%s", idx, "t"); + + scope_set(P->scope, buf, vte); } + idx++; + if(maybe(P, TOKEN_SQUAREN_R)) { break; } if(maybe(P, TOKEN_SEMICOLON)) { + idx = 0; integerMode = true; - head = NULL; - last = NULL; } else if(!maybe(P, TOKEN_COMMA)) { goto backtrack; } @@ -698,7 +719,7 @@ Type *nct_parse_typename(Parser *P) { bool generics = peek(P, 0).type == TOKEN_SQUAREN_L; if(generics) { - P->scope = vartable_new(P->scope); + P->scope = scope_new(P->scope); parse_genericization(P); } @@ -711,8 +732,8 @@ Type *nct_parse_typename(Parser *P) { Token id = expect(P, TOKEN_IDENTIFIER); - VarTableEntry *potentialVTE = vartable_find(P->scope, id.content); - if(potentialVTE && potentialVTE->kind == VARTABLEENTRY_TYPE) { + ScopeItem *potentialVTE = scope_find(P->scope, id.content); + if(potentialVTE && potentialVTE->kind == SCOPEITEM_TYPE) { ret = potentialVTE->data.type.ptr; } else { ret = (Type*) primitive_parse(id.content); @@ -776,17 +797,17 @@ Type *nct_parse_typename(Parser *P) { free(prim); } else if(maybe(P, TOKEN_QUESTION_MARK)) { - arr->length = 0; + arr->length = -1; } else if(peek(P, 0).type == TOKEN_IDENTIFIER) { const char *what = expect(P, TOKEN_IDENTIFIER).content; - VarTableEntry *vte = vartable_find(P->scope, what); + ScopeItem *vte = scope_find(P->scope, what); if(!vte) { goto backtrack; } - if(vte->kind != VARTABLEENTRY_CEXPR) { + if(vte->kind != SCOPEITEM_CEXPR) { stahp_token(&P->tokens[P->i], "Variable '%s' is not constant.", what); } @@ -815,11 +836,12 @@ Type *nct_parse_typename(Parser *P) { P->i--; - Parametrizations parametrizations = {}; - assert(parse_parametrization(P, ¶metrizations)); + P->scope = scope_new(P->scope); - Parametrizations renames = {}; - ret = type_parametrize(ret, ¶metrizations, &renames); + assert(parse_parametrization(P)); + ret = type_parametrize(ret, P->scope); + + P->scope = P->scope->parent; } } } @@ -857,8 +879,8 @@ static AST *parse_declaration(Parser *P) { Token name = expect(P, TOKEN_IDENTIFIER); - VarTableEntry *entry; - if(peek(P, 0).type == TOKEN_COLON && (entry = vartable_get(P->scope, name.content))) { + ScopeItem *entry; + if(peek(P, 0).type == TOKEN_COLON && (entry = scope_get(P->scope, name.content))) { /* Forward declared. */ } else { entry = calloc(sizeof(*entry), 1); @@ -873,7 +895,7 @@ static AST *parse_declaration(Parser *P) { return NULL; } - entry->kind = VARTABLEENTRY_VAR; + entry->kind = SCOPEITEM_VAR; entry->data.var.priority = 1; entry->data.var.color = -1; @@ -902,7 +924,7 @@ static AST *parse_declaration(Parser *P) { return NULL; } - entry->kind = VARTABLEENTRY_SYMBOL; + entry->kind = SCOPEITEM_SYMBOL; entry->data.symbol.isLocal = P->externalify ? false : isLocal; entry->data.symbol.isExternal = P->externalify ? true : isExternal; entry->data.symbol.name = name.content; @@ -918,12 +940,13 @@ static AST *parse_declaration(Parser *P) { } if(decl->expression && decl->expression->nodeKind == AST_EXPR_FUNC && type_is_generic(decl->expression->expression.type)) { + entry->data.symbol.genfunc.scope = decl->expression->exprFunc.scope; entry->data.symbol.genfunc.rangeTokens = decl->expression->exprFunc.rangeTokens; entry->data.symbol.genfunc.startTokI = decl->expression->exprFunc.startTokI; entry->data.symbol.genfunc.endTokI = decl->expression->exprFunc.endTokI; } } else if(isExternal) { - entry->kind = VARTABLEENTRY_SYMBOL; + entry->kind = SCOPEITEM_SYMBOL; entry->data.symbol.isLocal = isLocal; entry->data.symbol.isExternal = isExternal; entry->data.symbol.name = name.content; @@ -934,7 +957,7 @@ static AST *parse_declaration(Parser *P) { ret = (AST*) decl; } - vartable_set(P->scope, name.content, entry); + scope_set(P->scope, name.content, entry); if(P->skimMode) { // In skim mode parsing is not done normally @@ -961,24 +984,42 @@ static char *plus_underscore(char *s, char *ts) { return s; } -static char *parametrize_function_name(Type *t, const char *original, Parametrization *types, Parametrization *ints) { +static char *parametrize_function_name(Type *t, const char *original, Scope *scope) { char *s = calloc(1, strlen(original) + 1 + 1); strcpy(s, original); s[strlen(original)] = '_'; - while(types) { - s = plus_underscore(s, type_to_string(types->param)); + for(int i = 0;; i++) { + char vtename[64]; + snprintf(vtename, sizeof(vtename), "%it", i); - types = types->next; + // scope_get, NOT SCOPE_FIND! + ScopeItem *vte = scope_get(scope, vtename); + + if(!vte) break; + + assert(vte->kind == SCOPEITEM_TYPE); + + s = plus_underscore(s, type_to_string(vte->data.type.ptr)); } - while(ints) { + for(int i = 0;; i++) { + char vtename[64]; + snprintf(vtename, sizeof(vtename), "%ii", i); + + // scope_get, NOT SCOPE_FIND! + ScopeItem *vte = scope_get(scope, vtename); + + if(!vte) break; + + assert(vte->kind == SCOPEITEM_CEXPR); + assert(vte->data.cexpr.concrete); + assert(vte->data.cexpr.concrete->nodeKind == AST_EXPR_PRIMITIVE); + char numstr[32]; - snprintf(numstr, sizeof(numstr), "%i", ((AST*) ints->param)->exprPrim.val); + snprintf(numstr, sizeof(numstr), "%i", vte->data.cexpr.concrete->exprPrim.val); s = plus_underscore(s, numstr); - - ints = ints->next; } // Remove last underscore @@ -987,7 +1028,7 @@ static char *parametrize_function_name(Type *t, const char *original, Parametriz return s; } -static void add_parametrizations_to_scope(Parser *P, Parametrizations *parametrizations, Parametrizations *renames) { +/*static void add_parametrizations_to_scope(Parser *P, Parametrizations *parametrizations, Parametrizations *renames) { Parametrization *c = parametrizations->typeParams; Parametrization *g = renames->typeParams; while(c && g) { @@ -996,10 +1037,10 @@ static void add_parametrizations_to_scope(Parser *P, Parametrizations *parametri assert(!!ct == !!gt); - VarTableEntry *vte = calloc(1, sizeof(*vte)); - vte->kind = VARTABLEENTRY_TYPE; + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_TYPE; vte->data.type.ptr = ct; - vartable_set(P->scope, gt->generic.paramName, vte); + scope_set(P->scope, gt->generic.paramName, vte); c = c->next; g = g->next; @@ -1014,18 +1055,18 @@ static void add_parametrizations_to_scope(Parser *P, Parametrizations *parametri assert(!!node == !!name); - VarTableEntry *vte = calloc(1, sizeof(*vte)); - vte->kind = VARTABLEENTRY_CEXPR; + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_CEXPR; vte->data.cexpr.paramIdx = idx; vte->data.cexpr.paramName = name; vte->data.cexpr.concrete = node; - vartable_set(P->scope, name, vte); + scope_set(P->scope, name, vte); c = c->next; g = g->next; idx++; } -} +}*/ void nct_parse_statement(Parser *P) { if(maybe(P, TOKEN_IF)) { @@ -1137,6 +1178,7 @@ void nct_parse_statement(Parser *P) { return; } else if(maybe(P, TOKEN_USE)) { while(get(P).type != TOKEN_SEMICOLON); + return; } else if(peek(P, 0).type == TOKEN_IDENTIFIER) { if(!strcmp(peek(P, 0).content, "@align")) { ASTStmtExtAlign *ret = alloc_node(P, sizeof(*ret)); @@ -1192,7 +1234,7 @@ void nct_parse_statement(Parser *P) { Token funcname = expect(P, TOKEN_IDENTIFIER); - VarTableEntry *func = vartable_find(P->scope, funcname.content); + ScopeItem *func = scope_find(P->scope, funcname.content); if(!func) { stahp_token(&P->tokens[P->i], "Cannot find function %s for parametrization.", funcname.content); @@ -1200,47 +1242,68 @@ void nct_parse_statement(Parser *P) { assert(type_is_generic(func->type)); - Parametrizations parametrizations = {}; - assert(parse_parametrization(P, ¶metrizations)); + Scope *oldScope = P->scope; + P->scope = scope_new(oldScope); - P->scope = vartable_new(P->scope); + assert(parse_parametrization(P)); - Parametrizations renames = {}; - Type *parametrizedFuncType = type_parametrize(func->type, ¶metrizations, &renames); + P->scope->parent = func->data.symbol.genfunc.scope; - add_parametrizations_to_scope(P, ¶metrizations, &renames); + Type *parametrizedFuncType = type_parametrize(func->type, P->scope); size_t oldIdx = P->i; + Token *oldTokens = P->tokens; + P->tokens = func->data.symbol.genfunc.rangeTokens; P->i = func->data.symbol.genfunc.startTokI; - size_t depth = 0; + expect(P, TOKEN_SQUAREN_L); + intmax_t paramIdx = 0; + bool integerMode = false; while(1) { - TokenKind tk = get(P).type; - if(tk == TOKEN_SQUAREN_L) { - depth++; - } else if(tk == TOKEN_SQUAREN_R) { - if(--depth == 0) { + if(maybe(P, TOKEN_SQUAREN_R)) { + break; + } + + char vtename[64]; + snprintf(vtename, sizeof(vtename), integerMode ? "%lii" : "%lit", paramIdx++); + + ScopeItem *src = scope_get(P->scope, vtename); + + assert(src != NULL); + + scope_set(P->scope, expect(P, TOKEN_IDENTIFIER).content, src); + + if(maybe(P, TOKEN_SEMICOLON)) { + paramIdx = 0; + integerMode = true; + } else { + if(maybe(P, TOKEN_SQUAREN_R)) { break; } + + expect(P, TOKEN_COMMA); } } + // Parse without the genericizing [...] because we've just parsed it ourselves and set the necessary VTEs AST *concreteFunction = nct_parse_expression(P, 0); assert(concreteFunction->nodeKind == AST_EXPR_FUNC); P->i = oldIdx; + P->tokens = oldTokens; - P->scope = P->scope->parent; - - VarTableEntry *vte = calloc(1, sizeof(*vte)); - vte->kind = VARTABLEENTRY_SYMBOL; + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_SYMBOL; vte->type = parametrizedFuncType; - vte->data.symbol.name = parametrize_function_name(func->type, func->data.symbol.name, parametrizations.typeParams, parametrizations.intParams); + vte->data.symbol.name = parametrize_function_name(func->type, func->data.symbol.name, P->scope); vte->data.symbol.isExternal = false; vte->data.symbol.isLocal = false; - vartable_set(P->scope, vte->data.symbol.name, vte); + + // Important order (remove parametrizations from scope, then add parametrized function to global) + P->scope = oldScope; + scope_set(P->scope, vte->data.symbol.name, vte); ASTStmtDecl *decl = alloc_node(P, sizeof(*decl)); decl->nodeKind = AST_STMT_DECL; @@ -1257,6 +1320,13 @@ void nct_parse_statement(Parser *P) { { AST *decl = parse_declaration(P); if(decl) { + if(decl->nodeKind == AST_STMT_DECL) { + if(decl->stmtDecl.thing->kind == SCOPEITEM_SYMBOL && decl->stmtDecl.thing->data.symbol.isExternal) { + P->topLevel->externs = realloc(P->topLevel->externs, sizeof(*P->topLevel->externs) * (++P->topLevel->externCount)); + P->topLevel->externs[P->topLevel->externCount - 1] = decl->stmtDecl.thing; + } + } + // Don't pass declaration statements for generic functions, because they're useless if(decl->nodeKind != AST_STMT_DECL || !type_is_generic(decl->stmtDecl.thing->type)) { pushstat(P, decl); @@ -1315,21 +1385,21 @@ void parse_genericization(Parser *P) { tg->generic.paramName = strdup(get(P).content); tg->generic.paramIdx = nextIdx; - VarTableEntry *vte = calloc(1, sizeof(*vte)); - vte->kind = VARTABLEENTRY_TYPE; + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_TYPE; vte->data.type.ptr = tg; - vartable_set(P->scope, strdup(tg->generic.paramName), vte); + scope_set(P->scope, strdup(tg->generic.paramName), vte); } else { - VarTableEntry *vte = calloc(1, sizeof(*vte)); + ScopeItem *vte = calloc(1, sizeof(*vte)); vte->type = primitive_parse("u32"); - vte->kind = VARTABLEENTRY_CEXPR; + vte->kind = SCOPEITEM_CEXPR; vte->data.cexpr.paramName = strdup(get(P).content); vte->data.cexpr.paramIdx = nextIdx; - vartable_set(P->scope, strdup(vte->data.var.name), vte); + scope_set(P->scope, strdup(vte->data.var.name), vte); } @@ -1355,7 +1425,7 @@ void parse_genericization(Parser *P) { Type *nct_parse_record_definition(Parser *P) { expect(P, TOKEN_RECORD); - P->scope = vartable_new(P->scope); + P->scope = scope_new(P->scope); Token name = expect(P, TOKEN_IDENTIFIER); @@ -1432,12 +1502,22 @@ static void skim_chunk(Parser *P, int isTopLevel) { } } stomp:; - } else if(k == TOKEN_COLON) { + } else if(k == TOKEN_COLON || k == TOKEN_EXTERN) { /* Move back to beginning of declaration. */ - do { + if(k == TOKEN_COLON) { + int squarenDepth = 0; + do { + P->i--; + if(P->tokens[P->i].type == TOKEN_SQUAREN_R) { + squarenDepth++; + } else if(P->tokens[P->i].type == TOKEN_SQUAREN_L) { + squarenDepth--; + } + } while(squarenDepth != 0 || (P->i >= oldIdx && P->tokens[P->i].type != TOKEN_SEMICOLON && P->tokens[P->i].type != TOKEN_SQUIGGLY_R && P->tokens[P->i].type != TOKEN_SQUIGGLY_L)); + P->i++; + } else { P->i--; - } while(P->i >= oldIdx && P->tokens[P->i].type != TOKEN_SEMICOLON && P->tokens[P->i].type != TOKEN_SQUIGGLY_R && P->tokens[P->i].type != TOKEN_SQUIGGLY_L); - P->i++; + } AST *d = parse_declaration(P); if(!d) abort(); @@ -1448,11 +1528,11 @@ static void skim_chunk(Parser *P, int isTopLevel) { Type *tr = nct_parse_record_definition(P); - VarTableEntry *vte = calloc(1, sizeof(*vte)); - vte->kind = VARTABLEENTRY_TYPE; + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_TYPE; vte->data.type.ptr = tr; - vartable_set(P->scope, tr->record.name, vte); + scope_set(P->scope, tr->record.name, vte); } else if(k == TOKEN_USE) { char *path = malp("%s", expect(P, TOKEN_IDENTIFIER).content); @@ -1469,30 +1549,42 @@ static void skim_chunk(Parser *P, int isTopLevel) { path = path2; } - { + FILE *f = NULL; + for(const char **importPaths = ntc_get_import_paths(); *importPaths; importPaths++) { char *path2 = malp("tests/%s.nct", path); - free(path); - path = path2; + + f = fopen(path2, "rb"); + + free(path2); + + if(f) { + // Importee found + break; + } } - FILE *f = fopen(path, "rb"); + if(!f) { + stahp_token(&P->tokens[P->i], "Module %s not found", path); + } - Parser subp = {.tokens = nct_lex(f), .scope = vartable_new(NULL), .externalify = 1}; + free(path); + + Parser subp = {.tokens = nct_lex(f), .scope = scope_new(NULL), .externalify = 1}; skim_chunk(&subp, 1); // Copy all extern symbols from the scope into our TLC's externs array for(size_t i = 0; i < subp.scope->count; i++) { - VarTableEntry *vte = subp.scope->data[i]; - if(vte->kind == VARTABLEENTRY_SYMBOL && vte->data.symbol.isExternal) { + ScopeItem *vte = subp.scope->data[i]; + if(vte->kind == SCOPEITEM_SYMBOL && vte->data.symbol.isExternal) { P->topLevel->externs = realloc(P->topLevel->externs, sizeof(*P->topLevel->externs) * (++P->topLevel->externCount)); P->topLevel->externs[P->topLevel->externCount - 1] = vte; } } subp.scope->parent = P->scope; - vartable_merge(subp.scope); + scope_merge(subp.scope); - free(subp.tokens); + // free(subp.tokens); DO THIS CANNOT fclose(f); } @@ -1502,7 +1594,7 @@ static void skim_chunk(Parser *P, int isTopLevel) { P->skimMode--; } -ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable *toplevelParent, Type *ft) { +ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *toplevelParent, Type *ft) { AST *ret = alloc_node(P, sizeof(ASTChunk)); ret->nodeKind = AST_CHUNK; ret->chunk.statementFirst = ret->chunk.statementLast = NULL; @@ -1513,9 +1605,9 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable AST *oldChunk = (AST*) P->currentChunk; P->currentChunk = &ret->chunk; - VarTable *oldScope = P->scope; + Scope *oldScope = P->scope; - P->scope = isTopLevel ? toplevelParent : vartable_new(oldScope); + P->scope = isTopLevel ? toplevelParent : scope_new(oldScope); ASTChunk *oldTopLevel = P->topLevel; if(isTopLevel) { @@ -1526,16 +1618,17 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable /* Arguments */ if(ft && isTopLevel) { - VarTableEntry **vtes = alloca(sizeof(*vtes) * ft->function.argCount); + ScopeItem **vtes = alloca(sizeof(*vtes) * ft->function.argCount); - for(int i = ft->function.argCount - 1; i >= 0; i--) { - VarTableEntry *vte = calloc(1, sizeof(*vte)); - vte->kind = VARTABLEENTRY_VAR; + // First arguments in a function TLC is the arguments + for(int i = 0; i < ft->function.argCount; i++) { + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_VAR; vte->type = ft->function.args[i]; vte->data.var.name = ft->function.argNames[i]; vte->data.var.color = -1; - vartable_set(toplevelParent, vte->data.var.name, vte); + scope_set(toplevelParent, vte->data.var.name, vte); vtes[i] = vte; } @@ -1547,21 +1640,23 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable nct_parse_statement(P); } - size_t nonSymbols = 0; + // Add all variables used in this chunk into the TLC's variable list + size_t varsToAdd = 0; for(size_t i = 0; i < P->scope->count; i++) { - if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) { - nonSymbols++; - - if(varPrioritize) { - P->scope->data[i]->data.var.priority++; - } + if(P->scope->data[i]->kind == SCOPEITEM_VAR) { + varsToAdd++; } } - P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (P->topLevel->varCount + nonSymbols)); - for(size_t i = 0; i < P->scope->count; i++) { - if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) { - P->topLevel->vars[P->topLevel->varCount++] = P->scope->data[i]; - //P->scope->data[i]->owner = P->topLevel; // not sure why this line ever existed, it makes no sense + + P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (P->topLevel->varCount + varsToAdd)); + + // This makes sure function arguments stay first in the array + memmove(P->topLevel->vars + varsToAdd, P->topLevel->vars, sizeof(*P->topLevel->vars) * P->topLevel->varCount); + + for(size_t i = 0, n = 0; i < P->scope->count; i++) { + if(P->scope->data[i]->kind == SCOPEITEM_VAR) { + P->topLevel->vars[n++] = P->scope->data[i]; + P->topLevel->varCount++; } } @@ -1580,5 +1675,5 @@ AST *nct_parse(Token *tokens) { Parser P; memset(&P, 0, sizeof(P)); P.tokens = tokens; - return (AST*) nct_parse_chunk(&P, 1, 0, vartable_new(NULL), NULL); + return (AST*) nct_parse_chunk(&P, 1, 0, scope_new(NULL), NULL); } diff --git a/src/types.c b/src/types.c index a490f70..97a8fe0 100644 --- a/src/types.c +++ b/src/types.c @@ -6,6 +6,7 @@ #include #include"ast.h" #include"reporting.h" +#include #include"ntc.h" @@ -234,35 +235,12 @@ bool type_is_generic(Type *t) { return false; } -static void *parametrization_get_by_index(Parametrization *list, size_t idx) { - for(size_t i = 0; list && i < idx; i++) { - list = list->next; - } - return list ? list->param : NULL; -} - -static void parametrization_set_by_index(Parametrization **list, size_t idx, void *param) { - if(*list == NULL) { - *list = calloc(1, sizeof(Parametrization)); - } - - for(size_t i = 1; i <= idx; i++) { - if((*list)->next == NULL) { - (*list)->next = calloc(1, sizeof(Parametrization)); - } - - list = &(*list)->next; - } - - (*list)->param = param; -} - -Type *type_parametrize(Type *t, Parametrizations *parametrizations, Parametrizations *renames) { +Type *type_parametrize(Type *t, Scope *scope) { if(t->type == TYPE_TYPE_RECORD) { t = type_shallow_copy(t); for(size_t f = 0; f < t->record.fieldCount; f++) { - t->record.fieldTypes[f] = type_parametrize(t->record.fieldTypes[f], parametrizations, renames); + t->record.fieldTypes[f] = type_parametrize(t->record.fieldTypes[f], scope); } if(!type_is_generic(t)) { @@ -279,51 +257,48 @@ Type *type_parametrize(Type *t, Parametrizations *parametrizations, Parametrizat } else if(t->type == TYPE_TYPE_FUNCTION) { t = type_shallow_copy(t); - t->function.ret = type_parametrize(t->function.ret, parametrizations, renames); + t->function.ret = type_parametrize(t->function.ret, scope); for(size_t i = 0; i < t->function.argCount; i++) { - t->function.args[i] = type_parametrize(t->function.args[i], parametrizations, renames); + t->function.args[i] = type_parametrize(t->function.args[i], scope); } } else if(t->type == TYPE_TYPE_GENERIC) { - Type *newt = parametrization_get_by_index(parametrizations->typeParams, t->generic.paramIdx); + ScopeItem *vte = scope_find_int(scope, t->generic.paramIdx, "t"); - if(renames) { - parametrization_set_by_index(&renames->typeParams, t->generic.paramIdx, t); - } - - if(newt) { - return newt; + if(vte) { + assert(vte->kind == SCOPEITEM_TYPE); + return vte->data.type.ptr; } } else if(t->type == TYPE_TYPE_POINTER) { t = type_shallow_copy(t); - t->pointer.of = type_parametrize(t->pointer.of, parametrizations, renames); + t->pointer.of = type_parametrize(t->pointer.of, scope); } else if(t->type == TYPE_TYPE_ARRAY) { t = type_shallow_copy(t); - t->array.of = type_parametrize(t->array.of, parametrizations, renames); + t->array.of = type_parametrize(t->array.of, scope); if(t->array.lengthIsGeneric) { - AST *n = parametrization_get_by_index(parametrizations->intParams, t->array.lengthGenericParamIdx); + ScopeItem *vte = scope_find_int(scope, t->array.lengthGenericParamIdx, "i"); - if(n) { - while(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR && n->exprVar.thing->data.cexpr.concrete) { - n = n->exprVar.thing->data.cexpr.concrete; - } + if(vte) { + assert(vte->kind == SCOPEITEM_CEXPR); - if(n->nodeKind == AST_EXPR_PRIMITIVE) { - t->array.length = n->exprPrim.val; - t->array.lengthIsGeneric = false; - } else if(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR) { - t->array.lengthGenericParamIdx = n->exprVar.thing->data.cexpr.paramIdx; - t->array.lengthGenericParamName = n->exprVar.thing->data.cexpr.paramName; - t->array.lengthIsGeneric = true; - } else { - stahp_node(n, "Invalid parametrization expression."); + AST *n = vte->data.cexpr.concrete; + + if(n) { + if(n->nodeKind == AST_EXPR_PRIMITIVE) { + t->array.length = n->exprPrim.val; + t->array.lengthIsGeneric = false; + } else if(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == SCOPEITEM_CEXPR) { + t->array.lengthGenericParamIdx = n->exprVar.thing->data.cexpr.paramIdx; + t->array.lengthGenericParamName = n->exprVar.thing->data.cexpr.paramName; + t->array.lengthIsGeneric = true; + } else { + stahp_node(n, "Invalid parametrization expression."); + } } } - - parametrization_set_by_index(&renames->intParams, t->array.lengthGenericParamIdx, t->array.lengthGenericParamName); } } diff --git a/src/types.h b/src/types.h index 106579a..83ad614 100644 --- a/src/types.h +++ b/src/types.h @@ -102,18 +102,8 @@ int type_is_number(Type *t); char *type_to_string(Type*); -typedef struct Parametrization { - void *param; - - struct Parametrization *next; -} Parametrization; - -typedef struct { - Parametrization *typeParams; - Parametrization *intParams; -} Parametrizations; - -Type *type_parametrize(Type *target, Parametrizations *parametrizations, Parametrizations *renames); +struct Scope; +Type *type_parametrize(Type *target, struct Scope *scope); Type *type_shallow_copy(Type *t); diff --git a/src/vartable.c b/src/vartable.c index 3445002..5cb73d7 100644 --- a/src/vartable.c +++ b/src/vartable.c @@ -4,6 +4,7 @@ #include #include #include +#include struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) { struct ReachingDefs *ret = calloc(1, sizeof(*ret)); @@ -30,8 +31,8 @@ void reachingdefs_set(struct ReachingDefs *this, union AST *def) { this->excludeParent = 1; } -VarTable *vartable_new(VarTable *parent) { - VarTable *ret = calloc(1, sizeof(*ret)); +Scope *scope_new(Scope *parent) { + Scope *ret = calloc(1, sizeof(*ret)); ret->parent = parent; ret->count = 0; ret->names = NULL; @@ -40,17 +41,17 @@ VarTable *vartable_new(VarTable *parent) { return ret; } -VarTableEntry *vartable_get(VarTable *this, const char *name) { +ScopeItem *scope_get(Scope *this, const char *name) { for(size_t v = 0; v < this->count; v++) { if(!strcmp(name, this->names[v])) return this->data[v]; } return NULL; } -VarTableEntry *vartable_find(VarTable *this, const char *name) { - VarTable *tbl = this; +ScopeItem *scope_find(Scope *this, const char *name) { + Scope *tbl = this; while(tbl) { - VarTableEntry *entry = vartable_get(tbl, name); + ScopeItem *entry = scope_get(tbl, name); if(entry) { return entry; } @@ -59,43 +60,28 @@ VarTableEntry *vartable_find(VarTable *this, const char *name) { return NULL; } -VarTableEntry *vartable_set(VarTable *this, const char *name, VarTableEntry *e) { +ScopeItem *scope_set(Scope *this, const char *name, ScopeItem *e) { + name = strdup(name); + this->names = realloc(this->names, sizeof(*this->names) * (this->count + 1)); this->data = realloc(this->data, sizeof(*this->data) * (this->count + 1)); this->names[this->count] = name; this->data[this->count] = e; this->count++; - if(e->kind == VARTABLEENTRY_VAR) e->data.var.name = name; + if(e->kind == SCOPEITEM_VAR) e->data.var.name = name; e->owner = this; return e; } -/*void vartable_new_reachingdefs_for_all_vars(VarTable *this) { - for(size_t i = 0; i < this->count; i++) { - if(this->data[i]->kind == VARTABLEENTRY_VAR) { - this->data[i]->data.var.reachingDefs = reachingdefs_push(this->data[i]->data.var.reachingDefs); - } - } +ScopeItem *scope_find_int(Scope *scope, intmax_t val, const char *suffix) { + char buf[64]; + snprintf(buf, sizeof(buf), "%li%s", val, suffix ? suffix : ""); - if(this->parent) { - vartable_new_reachingdefs_for_all_vars(this->parent); - } + return scope_find(scope, buf); } -void vartable_coalesce_reachingdefs_for_all_vars(VarTable *this) { - for(size_t i = 0; i < this->count; i++) { - if(this->data[i]->kind == VARTABLEENTRY_VAR) { - this->data[i]->data.var.reachingDefs = reachingdefs_coalesce(this->data[i]->data.var.reachingDefs); - } - } - - if(this->parent) { - vartable_coalesce_reachingdefs_for_all_vars(this->parent); - } -}*/ - -VarTable *vartable_merge(VarTable *child) { - VarTable *parent = child->parent; +Scope *scope_merge(Scope *child) { + Scope *parent = child->parent; parent->names = realloc(parent->names, sizeof(*parent->names) * (parent->count + child->count)); parent->data = realloc(parent->data, sizeof(*parent->data) * (parent->count + child->count)); @@ -109,17 +95,18 @@ VarTable *vartable_merge(VarTable *child) { parent->count++; } - free(child->names); - free(child->data); - free(child); + //free(child->names); + //free(child->data); + //free(child); return parent; } -void vte_precolor(VarTableEntry *vte, int color) { - assert(vte->kind == VARTABLEENTRY_VAR && "vte must be var"); +void vte_precolor(ScopeItem *vte, int class, int color) { + assert(vte->kind == SCOPEITEM_VAR && "vte must be var"); assert(!vte->data.var.precolored && "already precolored"); vte->data.var.precolored = true; + vte->data.var.registerClass = class; vte->data.var.color = color; } diff --git a/src/vartable.h b/src/vartable.h index 79a02bf..78fb887 100644 --- a/src/vartable.h +++ b/src/vartable.h @@ -8,8 +8,8 @@ struct Token; union AST; typedef enum { - VARTABLEENTRY_SYMBOL, VARTABLEENTRY_VAR, VARTABLEENTRY_TYPE, VARTABLEENTRY_CEXPR -} VarTableEntryKind; + SCOPEITEM_SYMBOL, SCOPEITEM_VAR, SCOPEITEM_TYPE, SCOPEITEM_CEXPR +} ScopeItemKind; union AST; typedef struct UseDef { @@ -31,82 +31,81 @@ struct ReachingDefs *reachingdefs_push(struct ReachingDefs*); struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*); void reachingdefs_set(struct ReachingDefs*, union AST*); -struct VarTable; -typedef struct VarTableEntry { +struct Scope; +typedef struct ScopeItem { Type *type; - struct VarTable *owner; + struct Scope *owner; - VarTableEntryKind kind; - struct { - union { + ScopeItemKind kind; + union { + struct { + char isLocal; + char isExternal; + const char *name; + struct { - char isLocal; - char isExternal; - const char *name; - - struct { - struct Token *rangeTokens; - size_t startTokI; - size_t endTokI; - } genfunc; - } symbol; - struct { - // For debugging - - const char *name; - - // Register allocation - - // vars in loops have higher priority - // a more advanced approach would be to use weights for different colors (e.g. multipliers "should" be in eax) - uint8_t priority; - int16_t color, degree; - bool precolored; - - // Used during parsing - - ReachingDefs *reachingDefs; - - // Optimizations - - UseDef *usedefFirst; - UseDef *usedefLast; - } var; - struct { - Type *ptr; - } type; - struct { - // cexpr is used for expression parametization as opposed to type parametrization - // I don't like the idea of having a special VarTableEntry kind for these, but all other places were worse - const char *paramName; - size_t paramIdx; - - // If the cexpr has been parametrized (as opposed to just being a symbol), this field will be non-NULL - union AST *concrete; - } cexpr; - }; + struct Scope *scope; + struct Token *rangeTokens; + size_t startTokI; + size_t endTokI; + } genfunc; + } symbol; + struct { + // For debugging + + const char *name; + + // Register allocation + + // vars in loops have higher priority + // a more advanced approach would be to use weights for different colors (e.g. multipliers "should" be in eax) + uint8_t priority; + int16_t color, degree; + bool precolored; + int registerClass; + + // Used during parsing + + ReachingDefs *reachingDefs; + + // Optimizations + + UseDef *usedefFirst; + UseDef *usedefLast; + } var; + struct { + Type *ptr; + } type; + struct { + // cexpr is used for expression parametization as opposed to type parametrization + // I don't like the idea of having a special ScopeItem kind for these, but all other places were worse + const char *paramName; + size_t paramIdx; + + // If the cexpr has been parametrized (as opposed to just being a symbol), this field will be non-NULL + union AST *concrete; + } cexpr; } data; -} VarTableEntry; +} ScopeItem; -typedef struct VarTable { - struct VarTable *parent; +typedef struct Scope { + struct Scope *parent; size_t count; const char **names; - VarTableEntry **data; -} VarTable; + ScopeItem **data; +} Scope; -VarTable *vartable_new(VarTable*); -VarTableEntry *vartable_get(VarTable*, const char*); -VarTableEntry *vartable_find(VarTable*, const char*); -VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*); +Scope *scope_new(Scope*); +ScopeItem *scope_get(Scope*, const char*); +ScopeItem *scope_find(Scope*, const char*); +ScopeItem *scope_set(Scope*, const char*, ScopeItem*); -VarTable *vartable_merge(VarTable *child); +ScopeItem *scope_find_int(Scope*, intmax_t, const char*); -//void vartable_new_reachingdefs_for_all_vars(VarTable*); -//void vartable_coalesce_reachingdefs_for_all_vars(VarTable*); +Scope *scope_merge(Scope *child); -void vte_precolor(VarTableEntry *vte, int color); +void vte_precolor(ScopeItem *vte, int resclass, int color); #endif diff --git a/src/x86.h b/src/x86.h index b44b5ed..ee8f779 100644 --- a/src/x86.h +++ b/src/x86.h @@ -3,11 +3,90 @@ #include #include"ntc.h" #include +#include +#include +#include"ast.h" -#define COLOR_EAX 0 -#define COLOR_ECX 1 -#define COLOR_EDX 2 -#define COLOR_EBX 3 +#define HWR_AL 1 +#define HWR_AH 2 +#define HWR_BL 4 +#define HWR_BH 8 +#define HWR_CL 16 +#define HWR_CH 32 +#define HWR_DL 64 +#define HWR_DH 128 +#define HWR_DI 256 +#define HWR_SI 512 + +#define HWR_AX (HWR_AL | HWR_AH) +#define HWR_BX (HWR_BL | HWR_BH) +#define HWR_CX (HWR_CL | HWR_CH) +#define HWR_DX (HWR_DL | HWR_DH) + +#define HWR_EAX HWR_AX +#define HWR_EBX HWR_BX +#define HWR_ECX HWR_CX +#define HWR_EDX HWR_DX + +#define HWR_EDI HWR_DI +#define HWR_ESI HWR_SI + +#define HWR_GPR (HWR_EAX | HWR_EBX | HWR_ECX | HWR_EDX) +#define HWR_IND (HWR_EDI | HWR_ESI) +#define HWR_ALL (HWR_GPR | HWR_IND) + +#define MAX_REGS_PER_CLASS 12 +typedef struct RegisterClass { + uint32_t rMask; + uint16_t w; + uint16_t p; + + uint32_t rs[MAX_REGS_PER_CLASS]; + const char *rsN[MAX_REGS_PER_CLASS]; + uint8_t rsS[MAX_REGS_PER_CLASS]; +} RegisterClass; + +#define REG_CLASS_8 0 +#define REG_CLASS_NOT_8 1 +#define REG_CLASS_16_32 2 +#define REG_CLASS_IND 3 +extern RegisterClass REG_CLASSES[4]; + +// 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; + } +} // Can expression be expressed as a single x86 operand? #define XOP_NOT_XOP 0 @@ -21,10 +100,10 @@ static inline int is_xop(AST *e) { if(e->nodeKind == AST_EXPR_PRIMITIVE) { return XOP_NOT_MEM; } else if(e->nodeKind == AST_EXPR_VAR) { - return e->exprVar.thing->kind == VARTABLEENTRY_VAR ? XOP_NOT_MEM : XOP_MEM; + return e->exprVar.thing->kind == SCOPEITEM_VAR ? XOP_NOT_MEM : XOP_MEM; } 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 && is_xop(e->exprUnOp.operand->exprBinOp.operands[0]) == XOP_NOT_MEM && is_xop(e->exprUnOp.operand->exprBinOp.operands[1]) == XOP_NOT_MEM) { return XOP_MEM; - } 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) { + } 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) { return XOP_NOT_MEM; } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { AST *c = e->exprUnOp.operand; @@ -33,7 +112,7 @@ static inline int is_xop(AST *e) { c = c->exprCast.what; } - if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_VAR) { + if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == SCOPEITEM_VAR) { return XOP_MEM; } else if( (c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && c->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && c->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR) || @@ -158,7 +237,7 @@ static inline WhysItBad_Huh x86_test_mul(AST *stmtPrev, AST *stmt) { return NOT_AT_ALL_IT; } - if(stmt->stmtAssign.what->nodeKind != AST_EXPR_VAR || stmt->stmtAssign.what->exprVar.thing->kind != VARTABLEENTRY_VAR) { + if(stmt->stmtAssign.what->nodeKind != AST_EXPR_VAR || stmt->stmtAssign.what->exprVar.thing->kind != SCOPEITEM_VAR) { return DEST_IS_BAD_XOP; } diff --git a/tests/GenericStruct.nct b/tests/GenericStruct.nct deleted file mode 100644 index 12cc30c..0000000 --- a/tests/GenericStruct.nct +++ /dev/null @@ -1,44 +0,0 @@ -record StaticList[T, S; capacity] { - S size; - T[capacity] data; -} - -StaticList_remove: [T, S; capacity]u0(StaticList[T, S; capacity]* this, S index) -> { - T* data = &((*this).data[index]); - (*this).size = (*this).size - 1; - S sz = (*this).size; - loop { - if(index == sz) { - break; - } - - *data = *(data + 1); - - data = data + 1; - index = index + 1; - } - return; -}; - -StaticList_add: [T, S; capacity]u0(StaticList[T, S; capacity]* this, T value) -> { - (*this).data[(*this).size] = value; - (*this).size = (*this).size + 1; - return; -}; - -@instantiate StaticList_remove[u8, u32; 4]; -@instantiate StaticList_add[u8, u32; 4]; - -/*StaticList[u8, u32; 4] kbbuf; - -kbbuf.size = 4; -kbbuf.data[0] = 0; -kbbuf.data[5] = 2; - -foo: [T]T(T a, T b) -> { - return a + b; -}; - -@instantiate foo[u32]; - -u32 c = foo[u32](5, 3);*/ diff --git a/tests/Importer.nct b/tests/Importer.nct index 3e30b7c..8c3a738 100644 --- a/tests/Importer.nct +++ b/tests/Importer.nct @@ -1,3 +1,4 @@ use Exporter; -u32 a = Exporter.SYMBOL; +Foo f; +f.gaga = SYMBOL;