penis sex fuck penis cock, irregular register allocation and rename VarTable to Scope

This commit is contained in:
Mid 2025-06-10 22:07:22 +03:00
parent 1c4b5a5095
commit 6ec68a766f
19 changed files with 985 additions and 882 deletions

151
src/ast.c
View File

@ -5,6 +5,8 @@
#include<stdlib.h> #include<stdlib.h>
#include<assert.h> #include<assert.h>
#include<stdarg.h> #include<stdarg.h>
#include"ntc.h"
#include"reporting.h"
const char *AST_KIND_STR[] = { const char *AST_KIND_STR[] = {
AST_KINDS(GEN_STRI) 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_EXT_SALLOC) {
} else if(n->nodeKind == AST_EXPR_DOT) { } else if(n->nodeKind == AST_EXPR_DOT) {
generic_visitor(&n->exprDot.a, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); 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 { } else {
abort(); 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 * Because an AST may hold outdated UD-chains, this pass MUST be called
* before using the UD-chains to make sure they are valid. * 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: * that specifies the exact nodes in the AST where:
* 1. It is used * 1. It is used
* 2. The whole statement in which 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. * Until dead code removal is implemented, this will not be a problem.
*/ */
static void rawadduse(VarTableEntry *vte, UseDef *ud) { static void rawadduse(ScopeItem *vte, UseDef *ud) {
assert(vte->kind == VARTABLEENTRY_VAR); assert(vte->kind == SCOPEITEM_VAR);
assert(ud->next == NULL); assert(ud->next == NULL);
@ -219,8 +225,8 @@ static void rawadduse(VarTableEntry *vte, UseDef *ud) {
} }
} }
static void adduse(VarTableEntry *vte, AST *use, AST *whole) { static void adduse(ScopeItem *vte, AST *use, AST *whole) {
assert(vte->kind == VARTABLEENTRY_VAR); assert(vte->kind == SCOPEITEM_VAR);
assert(vte->data.var.reachingDefs != NULL); 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) { static void overwritedefs(ScopeItem *vte, AST *def) {
assert(vte->kind == VARTABLEENTRY_VAR); assert(vte->kind == SCOPEITEM_VAR);
if(!vte->data.var.reachingDefs) { if(!vte->data.var.reachingDefs) {
vte->data.var.reachingDefs = calloc(1, sizeof(*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; vte->data.var.reachingDefs->defCount = 1;
if(!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 = calloc(1, sizeof(*vte->data.var.reachingDefs->defs));
}
vte->data.var.reachingDefs->defs[0] = def; vte->data.var.reachingDefs->defs[0] = def;
} }
static void mergedefs(VarTableEntry *vte) { static void mergedefs(ScopeItem *vte) {
assert(vte->kind == VARTABLEENTRY_VAR); assert(vte->kind == SCOPEITEM_VAR);
ReachingDefs *rdefs = vte->data.var.reachingDefs; ReachingDefs *rdefs = vte->data.var.reachingDefs;
@ -274,8 +277,8 @@ static void mergedefs(VarTableEntry *vte) {
free(rdefs); free(rdefs);
} }
static void pushdefs(VarTableEntry *vte) { static void pushdefs(ScopeItem *vte) {
assert(vte->kind == VARTABLEENTRY_VAR); assert(vte->kind == SCOPEITEM_VAR);
ReachingDefs *rdefs = calloc(1, sizeof(*rdefs)); ReachingDefs *rdefs = calloc(1, sizeof(*rdefs));
rdefs->defCount = 0; rdefs->defCount = 0;
@ -298,8 +301,8 @@ static void mergedefsall(AST *tlc) {
} }
} }
static void mergedefsloop(AST *tlc, VarTableEntry *vte, AST *daLoopStmt) { static void mergedefsloop(AST *tlc, ScopeItem *vte, AST *daLoopStmt) {
assert(vte->kind == VARTABLEENTRY_VAR); assert(vte->kind == SCOPEITEM_VAR);
for(size_t d = 0; d < vte->data.var.reachingDefs->defCount; d++) { for(size_t d = 0; d < vte->data.var.reachingDefs->defCount; d++) {
UseDef *ud = vte->data.var.usedefFirst; UseDef *ud = vte->data.var.usedefFirst;
@ -351,7 +354,7 @@ static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) {
mergedefsloopall(tlc, a); mergedefsloopall(tlc, a);
} else if(a->nodeKind == AST_STMT_ASSIGN) { } 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); 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) { } else if(a->nodeKind == AST_STMT_EXPR) {
ast_usedef_pass(tlc, a->stmtExpr.expr, wholestmt); ast_usedef_pass(tlc, a->stmtExpr.expr, wholestmt);
} else if(a->nodeKind == AST_EXPR_VAR) { } 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); adduse(a->exprVar.thing, a, wholestmt);
} }
} else if(a->nodeKind == AST_EXPR_BINARY_OP) { } 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_ORG) {
} else if(a->nodeKind == AST_STMT_EXT_SECTION) { } else if(a->nodeKind == AST_STMT_EXT_SECTION) {
} else if(a->nodeKind == AST_STMT_DECL) { } 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) { } else if(a->nodeKind == AST_STMT_RETURN) {
if(a->stmtReturn.val) { if(a->stmtReturn.val) {
ast_usedef_pass(tlc, a->stmtReturn.val, wholestmt); 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) { void ast_usedef_reset(AST *chu) {
for(size_t i = 0; i < chu->chunk.varCount; i++) { 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.reachingDefs = NULL;
vte->data.var.usedefFirst = NULL; vte->data.var.usedefFirst = NULL;
@ -415,16 +418,6 @@ void ast_usedef_reset(AST *chu) {
return ast_usedef_pass(chu, chu, NULL); 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, ...) { __attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...) {
va_list v1, v2; va_list v1, v2;
va_start(v1, fmt); va_start(v1, fmt);
@ -463,7 +456,7 @@ char *type_to_string(Type *t) {
if(t->array.lengthIsGeneric) { if(t->array.lengthIsGeneric) {
len = malp(""); len = malp("");
} else { } else {
len = malp("%i", t->array.length); len = malp("%li", t->array.length);
} }
char *r = malp("%s[%s]", of, len); char *r = malp("%s[%s]", of, len);
free(of); free(of);
@ -478,11 +471,11 @@ static char *ast_dumpe(AST *e) {
if(e->nodeKind == AST_EXPR_PRIMITIVE) { if(e->nodeKind == AST_EXPR_PRIMITIVE) {
return malp("%i", e->exprPrim.val); return malp("%i", e->exprPrim.val);
} else if(e->nodeKind == AST_EXPR_VAR) { } 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); return strdup(vte->data.var.name);
} else if(vte->kind == VARTABLEENTRY_SYMBOL) { } else if(vte->kind == SCOPEITEM_SYMBOL) {
return strdup(vte->data.symbol.name); return strdup(vte->data.symbol.name);
} else abort(); } else abort();
} else if(e->nodeKind == AST_EXPR_UNARY_OP) { } else if(e->nodeKind == AST_EXPR_UNARY_OP) {
@ -633,9 +626,9 @@ char *ast_dump(AST *tlc);
static char *ast_dumps(AST *s) { static char *ast_dumps(AST *s) {
if(s->nodeKind == AST_STMT_DECL) { 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 *t = type_to_string(vte->type);
char *e = s->stmtDecl.expression ? ast_dumpe(s->stmtDecl.expression) : strdup(""); 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); 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) { } else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_VAR) {
const char *name; 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; name = s->stmtExpr.expr->exprVar.thing->data.var.name;
} else { } else {
name = s->stmtExpr.expr->exprVar.thing->data.symbol.name; name = s->stmtExpr.expr->exprVar.thing->data.symbol.name;
@ -698,12 +691,14 @@ static char *ast_dumps(AST *s) {
char *ast_dump(AST *tlc) { char *ast_dump(AST *tlc) {
AST *stmt = tlc->chunk.statementFirst; AST *stmt = tlc->chunk.statementFirst;
char *ret = strdup(""); char *ret = malp("");
#define CAT(s) do { char *b = s; ret = cat(ret, (b)); free(b); } while(0)
while(stmt) { 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; 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 */ /* Only exists at parse-time, hence not part of type system and is handled separately */
if(what->nodeKind == AST_EXPR_STRING_LITERAL) { 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)); ASTExprArray *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_ARRAY; 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; 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]; uint8_t bajt = what->exprStrLit.data[i];
ASTExprPrimitive *item = calloc(1, sizeof(*item)); 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 // 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; 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; if(type_equal(what->expression.type, to)) return what;
@ -802,7 +802,7 @@ fail:
struct Spill2StackState { struct Spill2StackState {
AST *targetTLC; AST *targetTLC;
VarTableEntry *target; ScopeItem *target; // can be NULL
size_t stackGrowth; size_t stackGrowth;
}; };
static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { 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(tlc->nodeKind == AST_CHUNK);
assert(vte != NULL); 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; struct Spill2StackState state;
memset(&state, 0, sizeof(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; state.stackGrowth = (type_size(vte->type) + 7) & ~7;
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor, NULL); 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) { static void typecheck_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
AST *a = *aptr; AST *a = *aptr;
if(a->nodeKind == AST_EXPR_CALL) { 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."); stahp_node(a, "Only function types may be called.");
} }
} else if(a->nodeKind == AST_EXPR_BINARY_OP) { } 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."); 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); 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);
}

View File

@ -5,11 +5,6 @@
#include"lexer.h" #include"lexer.h"
#include"vartable.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) #pragma pack(push, 1)
#ifdef __GNUC__ #ifdef __GNUC__
@ -47,7 +42,8 @@
K(AST_STMT_EXT_SECTION) \ K(AST_STMT_EXT_SECTION) \
K(AST_STMT_RETURN) \ K(AST_STMT_RETURN) \
K(AST_EXPR_EXT_SALLOC) \ 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; typedef enum ENUMPAK { AST_KINDS(GEN_ENUM) } ASTKind;
extern const char *AST_KIND_STR[]; 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; 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) { static inline BinaryOp binop_comp_opposite(BinaryOp op) {
if(op == BINOP_EQUAL) { if(op == BINOP_EQUAL) {
return BINOP_NEQUAL; return BINOP_NEQUAL;
@ -143,7 +143,7 @@ typedef struct {
typedef struct { typedef struct {
ASTExpr; ASTExpr;
VarTableEntry *thing; ScopeItem *thing;
} ASTExprVar; } ASTExprVar;
typedef struct { typedef struct {
@ -171,6 +171,7 @@ typedef struct {
union AST *chunk; union AST *chunk;
// Necessary for when the parser jumps to a generic function // Necessary for when the parser jumps to a generic function
Scope *scope;
Token *rangeTokens; Token *rangeTokens;
size_t startTokI; size_t startTokI;
size_t endTokI; size_t endTokI;
@ -203,7 +204,7 @@ typedef struct {
typedef struct { typedef struct {
ASTStmt; ASTStmt;
VarTableEntry *thing; ScopeItem *thing;
union AST *expression; union AST *expression;
} ASTStmtDecl; } ASTStmtDecl;
@ -213,11 +214,11 @@ typedef struct {
/* Flattened variable array for global register allocation */ /* Flattened variable array for global register allocation */
size_t varCount; size_t varCount;
VarTableEntry **vars; ScopeItem **vars;
/* extern symbol array */ /* extern symbol array */
size_t externCount; size_t externCount;
VarTableEntry **externs; ScopeItem **externs;
union AST *statementFirst; union AST *statementFirst;
union AST *statementLast; union AST *statementLast;
@ -315,6 +316,14 @@ typedef struct {
union AST *val; union AST *val;
} ASTStmtReturn; } ASTStmtReturn;
typedef struct {
ASTExpr;
// One of these will be NULL
union AST *ofExpr;
Type *ofType;
} ASTExprExtSizeOf;
typedef union AST { typedef union AST {
ASTBase; ASTBase;
@ -343,6 +352,7 @@ typedef union AST {
ASTExprExtSalloc exprExtSalloc; ASTExprExtSalloc exprExtSalloc;
ASTStmtExtOrg stmtExtOrg; ASTStmtExtOrg stmtExtOrg;
ASTStmtExtSection stmtExtSection; ASTStmtExtSection stmtExtSection;
ASTExprExtSizeOf exprExtSizeOf;
} AST; } AST;
#pragma pack(pop) #pragma pack(pop)
@ -362,10 +372,12 @@ AST *ast_deep_copy(AST*);
AST *ast_cast_expr(AST *what, Type *to); 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_typecheck(AST *tlc);
void ast_grow_stack_frame(AST *tlc, size_t bytes);
__attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...); __attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...);
#endif #endif

483
src/cg.c
View File

@ -4,18 +4,12 @@
#include<signal.h> #include<signal.h>
#include<string.h> #include<string.h>
#include<assert.h> #include<assert.h>
#include"dumberdowner.h"
#include"reporting.h"
#include"ast.h"
#include"x86.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 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; static size_t nextLocalLabel = 0;
@ -53,7 +47,7 @@ static const char *spec(int size) {
abort(); abort();
} }
static int log_size(int size) { /*static int log_size(int size) {
switch(size) { switch(size) {
case 0: case 0:
case 1: return 0; case 1: return 0;
@ -66,30 +60,38 @@ static int log_size(int size) {
static const char *specexpr(AST *e) { static const char *specexpr(AST *e) {
return spec(type_size(e->expression.type)); return spec(type_size(e->expression.type));
} }*/
static const char *xv_sz(VarTableEntry *v, int sz) { static const char *xv_sz(ScopeItem *v, int sz) {
assert(v->kind == VARTABLEENTRY_VAR); assert(v->kind == SCOPEITEM_VAR);
#define XVBUFS 8 #define XVBUFS 8
#define XVBUFSZ 8 #define XVBUFSZ 16
static char bufs[XVBUFS][XVBUFSZ]; static char bufs[XVBUFS][XVBUFSZ];
static int bufidx = 0; static int bufidx = 0;
char *ret = bufs[bufidx]; char *ret = bufs[bufidx];
#ifdef DEBUG if(ntc_get_int("rcd")) {
snprintf(ret, XVBUFSZ, "@%i", v->data.var.color); snprintf(ret, XVBUFSZ, "%i@%i", v->data.var.registerClass, v->data.var.color);
#else } else {
snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(sz)]); int cls = v->data.var.registerClass, reg = v->data.var.color;
#endif
if(type_size(v->type) != sz) {
if(sz == 4) {
reg_cast_up(&cls, &reg);
} else abort();
}
snprintf(ret, XVBUFSZ, "%s", REG_CLASSES[cls].rsN[reg]);
}
bufidx = (bufidx + 1) % XVBUFS; bufidx = (bufidx + 1) % XVBUFS;
return ret; return ret;
} }
static const char *xv(VarTableEntry *v) { static const char *xv(ScopeItem *v) {
return xv_sz(v, type_size(v->type)); return xv_sz(v, type_size(v->type));
} }
@ -116,11 +118,11 @@ static AST *is_field_access(AST *e) {
e = e->exprCast.what; 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; 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; return e;
} }
@ -136,9 +138,9 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
char *ret = bufs[bufidx]; 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 && 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; e = e->exprCast.what;
} }*/
if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
AST *p = e->exprUnOp.operand; AST *p = e->exprUnOp.operand;
@ -147,12 +149,12 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
p = p->exprCast.what; 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]", snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
spec(sz), spec(sz),
xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 4), xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 4),
xv_sz(p->exprBinOp.operands[1]->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]", snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
spec(sz), spec(sz),
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, 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 { } else {
assert(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR); assert(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR);
ScopeItem *vte = e->exprBinOp.operands[0]->exprVar.thing;
snprintf(ret, XOPBUFSZ, "%s [%s + %i]", snprintf(ret, XOPBUFSZ, "%s [%s + %i]",
spec(sz), 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); 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]", snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]",
spec(sz), spec(sz),
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
p->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val, p->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val,
xv_sz(p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 4)); 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)); 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) { } 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); 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) { } 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) { } 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); 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); snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), v->data.symbol.name);
} else abort(); } else abort();
} else if(e->nodeKind == AST_EXPR_PRIMITIVE) { } else if(e->nodeKind == AST_EXPR_PRIMITIVE) {
snprintf(ret, XOPBUFSZ, "%s %i", spec(type_size(e->exprPrim.type)), e->exprPrim.val); 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); snprintf(ret, XOPBUFSZ, "%s", e->exprUnOp.operand->exprVar.thing->data.symbol.name);
} else { } else {
return NULL; return NULL;
@ -216,8 +220,8 @@ static const char *xop(AST *tlc, AST *e) {
return xop_sz(tlc, e, type_size(e->expression.type)); return xop_sz(tlc, e, type_size(e->expression.type));
} }
static int ud_empty(VarTableEntry *a) { static int ud_empty(ScopeItem *a) {
assert(a->kind == VARTABLEENTRY_VAR); assert(a->kind == SCOPEITEM_VAR);
assert(!a->data.var.usedefFirst == !a->data.var.usedefLast); assert(!a->data.var.usedefFirst == !a->data.var.usedefLast);
return !a->data.var.usedefFirst; return !a->data.var.usedefFirst;
@ -251,8 +255,8 @@ void cg_chunk(CGState *cg, AST *a) {
printf("align %u\n", val); printf("align %u\n", val);
} }
} else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == VARTABLEENTRY_SYMBOL) { } else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == SCOPEITEM_SYMBOL) {
VarTableEntry *v = s->stmtDecl.thing; ScopeItem *v = s->stmtDecl.thing;
if(v->data.symbol.isExternal) { if(v->data.symbol.isExternal) {
// Do nothing. // Do nothing.
@ -287,6 +291,8 @@ void cg_chunk(CGState *cg, AST *a) {
// Generic functions have non-NULL code blocks // Generic functions have non-NULL code blocks
if(!type_is_generic(s->stmtDecl.expression->expression.type)) { if(!type_is_generic(s->stmtDecl.expression->expression.type)) {
dumben_pre(s->stmtDecl.expression->exprFunc.chunk);
dumben_go(s->stmtDecl.expression->exprFunc.chunk); dumben_go(s->stmtDecl.expression->exprFunc.chunk);
while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) { while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) {
dumben_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; 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; 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); 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) { } else if(s->stmtAssign.to) {
if(x86_imul_supported() && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) { 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->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]))) { 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 { } 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])); 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) { } 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->nodeKind == AST_EXPR_VAR);
assert(s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR); assert(s->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR);
assert(s->stmtAssign.what->exprVar.thing->data.var.color == COLOR_EDX); //assert(s->stmtAssign.what->exprVar.thing->data.var.color == COLOR_EDX);
assert(s->statement.next->nodeKind == AST_STMT_ASSIGN); assert(s->statement.next->nodeKind == AST_STMT_ASSIGN);
assert(s->statement.next->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP); assert(s->statement.next->stmtAssign.to->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])); 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", printf("lea %s, [%s + %s]\n",
xv(s->stmtAssign.what->exprVar.thing), xv(s->stmtAssign.what->exprVar.thing),
xv(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing), xv(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing),
xv(s->stmtAssign.to->exprBinOp.operands[1]->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", printf("lea %s, [%s + %s]\n",
xv(s->stmtAssign.what->exprVar.thing), xv(s->stmtAssign.what->exprVar.thing),
s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
xv(s->stmtAssign.to->exprBinOp.operands[1]->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_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", printf("lea %s, [%s + %i]\n",
xv_sz(s->stmtAssign.what->exprVar.thing, 4), xv_sz(s->stmtAssign.what->exprVar.thing, 4),
xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 4), xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 4),
s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val); 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)); 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 { } else {
if(is_xop(s->stmtAssign.to) == XOP_MEM && type_size(s->stmtAssign.what->expression.type) != type_size(s->stmtAssign.to->expression.type)) { printf("mov %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to));
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)));
}
} }
} }
@ -458,8 +473,8 @@ void cg_chunk(CGState *cg, AST *a) {
if(s->stmtReturn.val) { if(s->stmtReturn.val) {
assert(s->stmtReturn.val->nodeKind == AST_EXPR_VAR); assert(s->stmtReturn.val->nodeKind == AST_EXPR_VAR);
assert(s->stmtReturn.val->exprVar.thing->kind == VARTABLEENTRY_VAR); assert(s->stmtReturn.val->exprVar.thing->kind == SCOPEITEM_VAR);
assert(s->stmtReturn.val->exprVar.thing->data.var.color == COLOR_EAX); //assert(s->stmtReturn.val->exprVar.thing->data.var.color == COLOR_EAX);
} }
if(a->chunk.stackReservation) { if(a->chunk.stackReservation) {
@ -487,7 +502,7 @@ void cg_chunk(CGState *cg, AST *a) {
} }
struct Spill2VarState { struct Spill2VarState {
VarTableEntry *target; ScopeItem *target;
}; };
static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
static size_t vidx = 0; static size_t vidx = 0;
@ -497,12 +512,12 @@ static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk,
AST *a = *aptr; AST *a = *aptr;
if(a->nodeKind == AST_STMT_ASSIGN && a->stmtAssign.to->nodeKind == AST_EXPR_CALL) { 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) { if(a->stmtAssign.what->exprVar.thing == this->target) {
VarTableEntry *new = calloc(1, sizeof(*new)); ScopeItem *new = calloc(1, sizeof(*new));
new->kind = VARTABLEENTRY_VAR; new->kind = SCOPEITEM_VAR;
new->type = a->stmtAssign.what->exprVar.thing->type; new->type = a->stmtAssign.what->exprVar.thing->type;
new->data.var.name = malp("$s2v_%lu", vidx++); 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) { 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)); ScopeItem *new = calloc(1, sizeof(*new));
new->kind = VARTABLEENTRY_VAR; new->kind = SCOPEITEM_VAR;
new->type = a->stmtReturn.val->exprVar.thing->type; new->type = a->stmtReturn.val->exprVar.thing->type;
new->data.var.name = malp("$s2v_%lu", vidx++); 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 { /*struct PrecolorState {
VarTableEntry *mustBeSpilled; ScopeItem *mustBeSpilled;
}; };
static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
struct PrecolorState *this = ud; struct PrecolorState *this = ud;
if(this->mustBeSpilled) { 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; 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) { 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; 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.color = requiredColor;
vte->data.var.precolored = true; vte->data.var.precolored = true;
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.to->nodeKind == AST_EXPR_CALL) { } 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; 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.color = requiredColor;
vte->data.var.precolored = true; 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; 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.color = requiredColor;
vte->data.var.precolored = true; 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; 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.color = requiredColor;
vte->data.var.precolored = true; 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 */ /* 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, 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, 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, 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) && 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; Adjacency *adjs = NULL;
size_t adjCount = 0; size_t adjCount = 0;
@ -699,7 +718,7 @@ static VarTableEntry *get_precolor_spill_candidate(AST *tlc) {
adjs[a][1]->data.var.degree++; 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++) { for(size_t v = 1; v < tlc->chunk.varCount; v++) {
if(maxdeg->data.var.degree < tlc->chunk.vars[v]->data.var.degree) { 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); free(adjs);
return maxdeg; return maxdeg;
} }*/
struct CalleeSavedState { struct CalleeSavedState {
AST *targetTLC; 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 // To make sure we don't process the same return statement to infinity
AST *lastProcessedReturn; AST *lastProcessedReturn;
@ -732,122 +753,191 @@ static void callee_saved_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chun
if(n == tlc) { if(n == tlc) {
// Function entry // Function entry
ASTExprStackPointer *stk = calloc(1, sizeof(*stk)); for(int i = 0; i < MAX_REGS_PER_CLASS; i++) {
stk->nodeKind = AST_EXPR_STACK_POINTER; ScopeItem *vte = this->calleeUsers[i];
stk->type = primitive_parse("u32");
if(!vte) {
ASTExprPrimitive *offset = calloc(1, sizeof(*offset)); continue;
offset->nodeKind = AST_EXPR_PRIMITIVE; }
offset->type = primitive_parse("u32");
offset->val = tlc->chunk.stackReservation; ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
stk->nodeKind = AST_EXPR_STACK_POINTER;
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum)); stk->type = primitive_parse("u32");
sum->nodeKind = AST_EXPR_BINARY_OP;
sum->type = offset->type; ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
sum->operator = BINOP_ADD; offset->nodeKind = AST_EXPR_PRIMITIVE;
sum->operands[0] = (AST*) stk; offset->type = primitive_parse("u32");
sum->operands[1] = (AST*) offset; offset->val = this->calleeOffsets[i];
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref)); ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
deref->nodeKind = AST_EXPR_UNARY_OP; sum->nodeKind = AST_EXPR_BINARY_OP;
deref->type = offset->type; sum->type = offset->type;
deref->operator = UNOP_DEREF; sum->operator = BINOP_ADD;
deref->operand = (AST*) sum; sum->operands[0] = (AST*) stk;
sum->operands[1] = (AST*) offset;
ASTExprVar *ev = calloc(1, sizeof(*ev));
ev->nodeKind = AST_EXPR_VAR; ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
ev->type = this->ebxuser->type; deref->nodeKind = AST_EXPR_UNARY_OP;
ev->thing = this->ebxuser; deref->type = offset->type;
deref->operator = UNOP_DEREF;
ASTStmtAssign *assign = calloc(1, sizeof(*assign)); deref->operand = (AST*) sum;
assign->nodeKind = AST_STMT_ASSIGN;
assign->what = (AST*) deref; ASTExprVar *ev = calloc(1, sizeof(*ev));
assign->to = (AST*) ev; ev->nodeKind = AST_EXPR_VAR;
ev->type = vte->type;
assign->next = tlc->chunk.statementFirst; ev->thing = vte;
tlc->chunk.statementFirst = (AST*) assign;
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
assert(tlc->chunk.statementLast != NULL); assign->nodeKind = AST_STMT_ASSIGN;
assign->what = (AST*) deref;
tlc->chunk.stackReservation += 4; 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) { } else if(n->nodeKind == AST_STMT_RETURN && n != this->lastProcessedReturn) {
// Function exit // Function exit
this->lastProcessedReturn = n; this->lastProcessedReturn = n;
ASTExprStackPointer *stk = calloc(1, sizeof(*stk)); for(int i = 0; i < MAX_REGS_PER_CLASS; i++) {
stk->nodeKind = AST_EXPR_STACK_POINTER; ScopeItem *vte = this->calleeUsers[i];
stk->type = primitive_parse("u32");
if(!vte) {
ASTExprPrimitive *offset = calloc(1, sizeof(*offset)); continue;
offset->nodeKind = AST_EXPR_PRIMITIVE; }
offset->type = primitive_parse("u32");
offset->val = tlc->chunk.stackReservation; ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
stk->nodeKind = AST_EXPR_STACK_POINTER;
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum)); stk->type = primitive_parse("u32");
sum->nodeKind = AST_EXPR_BINARY_OP;
sum->type = offset->type; ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
sum->operator = BINOP_ADD; offset->nodeKind = AST_EXPR_PRIMITIVE;
sum->operands[0] = (AST*) stk; offset->type = primitive_parse("u32");
sum->operands[1] = (AST*) offset; offset->val = this->calleeOffsets[i];
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref)); ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
deref->nodeKind = AST_EXPR_UNARY_OP; sum->nodeKind = AST_EXPR_BINARY_OP;
deref->type = offset->type; sum->type = offset->type;
deref->operator = UNOP_DEREF; sum->operator = BINOP_ADD;
deref->operand = (AST*) sum; sum->operands[0] = (AST*) stk;
sum->operands[1] = (AST*) offset;
ASTExprVar *ev = calloc(1, sizeof(*ev));
ev->nodeKind = AST_EXPR_VAR; ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
ev->type = this->ebxuser->type; deref->nodeKind = AST_EXPR_UNARY_OP;
ev->thing = this->ebxuser; deref->type = offset->type;
deref->operator = UNOP_DEREF;
ASTStmtAssign *assign = calloc(1, sizeof(*assign)); deref->operand = (AST*) sum;
assign->nodeKind = AST_STMT_ASSIGN;
assign->what = (AST*) ev; ASTExprVar *ev = calloc(1, sizeof(*ev));
assign->to = (AST*) deref; ev->nodeKind = AST_EXPR_VAR;
assign->next = stmt; ev->type = vte->type;
ev->thing = vte;
if(stmtPrev) {
stmtPrev->statement.next = (AST*) assign; ASTStmtAssign *assign = calloc(1, sizeof(*assign));
} else { assign->nodeKind = AST_STMT_ASSIGN;
tlc->chunk.statementFirst = (AST*) 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) { 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++) { 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]; 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) { if(ebxuser) {
struct CalleeSavedState state; state.calleeOffsets[nextUser] = nextUser * 4;
state.targetTLC = tlc; state.calleeUsers[nextUser] = ebxuser;
state.ebxuser = 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); 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 */ /* Welsh-Powell graph coloring */
static int comparator(const void *A, const void *B) { static int comparator(const void *A, const void *B) {
VarTableEntry *const *a = A; ScopeItem *const *a = A;
VarTableEntry *const *b = B; ScopeItem *const *b = B;
return ((*a)->data.var.degree * (*a)->data.var.priority) - ((*b)->data.var.degree * (*b)->data.var.priority); return ((*a)->data.var.degree * (*a)->data.var.priority) - ((*b)->data.var.degree * (*b)->data.var.priority);
} }
int cg_go(AST *a) { int cg_go(AST *a) {
assert(a->nodeKind == AST_CHUNK); assert(a->nodeKind == AST_CHUNK);
for(size_t e = 0; e < a->chunk.externCount; e++) { 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); assert(a->chunk.externs[e]->data.symbol.isExternal);
printf("extern %s\n", a->chunk.externs[e]->data.symbol.name); printf("extern %s\n", a->chunk.externs[e]->data.symbol.name);
@ -858,27 +948,30 @@ int cg_go(AST *a) {
size_t adjCount = 0; size_t adjCount = 0;
Adjacency *adjs = calloc(adjCount, sizeof(*adjs)); 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++) { for(size_t vi = 0; vi < a->chunk.varCount; vi++) {
vars[vi]->data.var.priority = 1; vars[vi]->data.var.priority = 1;
vars[vi]->data.var.degree = 0; vars[vi]->data.var.degree = 0;
vars[vi]->data.var.registerClass = -1;
if(!vars[vi]->data.var.precolored) { if(!vars[vi]->data.var.precolored) {
vars[vi]->data.var.color = -1; vars[vi]->data.var.color = -1;
} }
} }
determine_register_classes(a);
for(size_t v1i = 0; v1i < a->chunk.varCount; v1i++) { for(size_t v1i = 0; v1i < a->chunk.varCount; v1i++) {
for(size_t v2i = 0; v2i < a->chunk.varCount; v2i++) { for(size_t v2i = 0; v2i < a->chunk.varCount; v2i++) {
if(v1i == v2i) continue; if(v1i == v2i) continue;
VarTableEntry *v1 = vars[v1i]; ScopeItem *v1 = vars[v1i];
VarTableEntry *v2 = vars[v2i]; ScopeItem *v2 = vars[v2i];
if(var_collision(a, v1, v2)) { if(var_collision(a, v1, v2)) {
VarTableEntry *min = v1 < v2 ? v1 : v2; ScopeItem *min = v1 < v2 ? v1 : v2;
VarTableEntry *max = v1 < v2 ? v2 : v1; ScopeItem *max = v1 < v2 ? v2 : v1;
for(size_t a = 0; a < adjCount; a++) { for(size_t a = 0; a < adjCount; a++) {
if(adjs[a][0] == min && adjs[a][1] == max) { if(adjs[a][0] == min && adjs[a][1] == max) {
@ -902,7 +995,7 @@ cont:;
qsort(vars, a->chunk.varCount, sizeof(*vars), comparator); qsort(vars, a->chunk.varCount, sizeof(*vars), comparator);
int lastColor = 0; int mustSpillRegisterClass = -1;
/* Welsh plow my ass */ /* Welsh plow my ass */
for(int v = 0; v < a->chunk.varCount; v++) { for(int v = 0; v < a->chunk.varCount; v++) {
@ -912,18 +1005,42 @@ cont:;
} }
for(int c = 0;; c++) { 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++) { 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) { ScopeItem *me = NULL, *they = NULL;
goto nextColor;
} else if(adjs[a][1] == vars[v] && adjs[a][0]->data.var.color != -1 && adjs[a][0]->data.var.color == c) { 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; goto nextColor;
} }
} }
vars[v]->data.var.color = c; vars[v]->data.var.color = c;
lastColor = lastColor < c ? c : lastColor;
break; break;
nextColor:; nextColor:;
@ -932,12 +1049,12 @@ nextColor:;
free(adjs); free(adjs);
if(lastColor >= 4) { if(mustSpillRegisterClass != -1) {
// Spill node with highest degree // Spill node with highest degree
VarTableEntry *chosen = NULL; ScopeItem *chosen = NULL;
for(ssize_t i = a->chunk.varCount - 1; i >= 0; i--) { 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]; chosen = vars[i];
break; break;
} }

View File

@ -1,141 +0,0 @@
#include"dstr.h"
#include<stdarg.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
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));
}

View File

@ -1,15 +0,0 @@
#ifndef _DSTR_H
#define _DSTR_H
#include<stddef.h>
/* 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

View File

@ -2,6 +2,10 @@
#include<stdlib.h> #include<stdlib.h>
#include<assert.h> #include<assert.h>
#include<string.h>
#include"x86.h"
#include"reporting.h"
// This is the dumbing down pass. // 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 // This file along with CG is strictly for IA-32 and will fail for other
// architectures. // architectures.
#include"x86.h" static ScopeItem *create_dumbtemp(AST *tlc, Type *itstype) {
#include<string.h>
static VarTableEntry *create_dumbtemp(AST *tlc, Type *itstype) {
static size_t vidx = 0; static size_t vidx = 0;
VarTableEntry *vte = calloc(1, sizeof(*vte)); ScopeItem *vte = calloc(1, sizeof(*vte));
vte->kind = VARTABLEENTRY_VAR; vte->kind = SCOPEITEM_VAR;
vte->type = itstype; vte->type = itstype;
vte->data.var.color = -1; vte->data.var.color = -1;
vte->data.var.precolored = false; 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 */ /* Split away complex expression into a new local variable */
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) { 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 // 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 // ret specifically returns in eax always, so it needs to be in a precolored var
AST *retval = s->stmtReturn.val; 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); retval = s->stmtReturn.val = varify(tlc, chu, stmtPrev, s, retval);
this->effective = 1; 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); 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 // Purge this statement entirely, otherwise we'd have
// a = f(x); // a = f(x);
@ -160,9 +161,10 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
this->effective = 1; this->effective = 1;
} else { } 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))}; ASTExprVar *ev[2] = {calloc(1, sizeof(**ev)), calloc(1, sizeof(**ev))};
ev[0]->nodeKind = AST_EXPR_VAR; 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); s->stmtAssign.what->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what->exprUnOp.operand);
this->effective = 1; 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; ASTExprCall *call = &s->stmtAssign.to->exprCall;
int argCount = call->what->expression.type->function.argCount; 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); 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]); 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; 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; this->effective = 1;
} else assert(because == NOT_AT_ALL_IT || because == GUCCI); } 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])) { } 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]); s->stmtAssign.to->exprBinOp.operands[1] = xopify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[1]);
this->effective = 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) { static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
AST *n = *nptr; AST *n = *nptr;
if(n == tlc) { if(n == ud) {
if(tlc->chunk.functionType) { if(tlc->chunk.functionType) {
size_t argCount = n->chunk.functionType->function.argCount; size_t argCount = n->chunk.functionType->function.argCount;
// First argCount vtes in list are the arguments // First argCount vtes in list are the arguments
for(size_t i = 0; i < argCount; i++) { 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)); ASTExprStackPointer *stck = calloc(1, sizeof(*stck));
stck->nodeKind = AST_EXPR_STACK_POINTER; 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; *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; *success = true;
} }
} }
void dumben_pre(AST *tlc) { 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); generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, decompose_symbol_record_field_access, NULL);
for(size_t t = 0; t < tlc->chunk.varCount; t++) { 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; bool success;
do { do {
success = false; success = false;
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor, NULL); generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor, NULL);
} while(success); } while(success);
ast_commutativity_pass(tlc);
} }
void dumben_go(AST* tlc) { void dumben_go(AST* tlc) {
size_t i = 0; size_t i = 0;
while(1) { while(1) {
if(i == 20000) { if(i == 20000) {
puts("TOO MANY DUMBS"); stahp(0, 0, "TOO MANY DUMBS. TOO MANY DUMBS.");
abort();
} }
fprintf(stderr, "; Dumbing down %lu...\n", i++);
struct DumbenState state; struct DumbenState state;
memset(&state, 0, sizeof(state)); memset(&state, 0, sizeof(state));
@ -512,6 +538,11 @@ void dumben_go(AST* tlc) {
break; 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);
}
} }
} }

View File

@ -225,6 +225,7 @@ Token nct_tokenize(FILE *f) {
if(c == '0') c = 0; if(c == '0') c = 0;
else if(c == 'n') c = '\n'; else if(c == 'n') c = '\n';
else if(c == 'r') c = '\r';
else if(c == 't') c = '\t'; else if(c == 't') c = '\t';
} }
@ -354,6 +355,9 @@ Token *nct_lex(FILE *f) {
size_t length = 8, index = 0; size_t length = 8, index = 0;
Token *list = malloc(sizeof(*list) * length); Token *list = malloc(sizeof(*list) * length);
currentRow = 1;
currentColumn = 0;
while(1) { while(1) {
list[index] = nct_tokenize(f); list[index] = nct_tokenize(f);

View File

@ -1,6 +1,7 @@
#include<errno.h> #include<errno.h>
#include<string.h> #include<string.h>
#include<stdlib.h> #include<stdlib.h>
#include<libgen.h>
#include"lexer.h" #include"lexer.h"
#include"parse.h" #include"parse.h"
@ -9,19 +10,45 @@
#include"cg.h" #include"cg.h"
#include"dumberdowner.h" #include"dumberdowner.h"
#include"x86.h" #include"x86.h"
#include"utils.h"
static int argc; static int argc;
static char **argv; static char **argv;
const char* ntc_get_arg(const char *name) { static char **includePaths;
for(int i = 1; i < argc; i++) { const char **ntc_get_import_paths() {
if(strstr(argv[i], name) == argv[i]) { return (const char**) includePaths;
return argv[i] + strlen(name) + 1; }
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; 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_) { int main(int argc_, char **argv_) {
argc = argc_; argc = argc_;
argv = argv_; argv = argv_;
@ -32,8 +59,26 @@ int main(int argc_, char **argv_) {
const char *in = ntc_get_arg("in"); 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; FILE *f = in ? fopen(in, "rb") : stdin;
if(!f) {
stahp(0, 0, "Failed to read input (%s)", strerror(errno));
}
Token *tokens = nct_lex(f); Token *tokens = nct_lex(f);
if(in) fclose(f); if(in) fclose(f);
@ -42,23 +87,23 @@ int main(int argc_, char **argv_) {
free(tokens); free(tokens);
fputs("; === Original AST ===\n", stderr); if(ntc_get_int("pdbg")) {
fputs(ast_dump(chunk), stderr); char *astdump = ast_dump(chunk);
fputc('\n', stderr); fprintf(stderr, "### ORIGINAL ###\n%s\n", astdump);
free(astdump);
}
dumben_pre(chunk); dumben_pre(chunk);
dumben_go(chunk); dumben_go(chunk);
fputs("\n; === Dumbified ===\n", stderr);
fputs(ast_dump(chunk), stderr);
fputc('\n', stderr);
while(!cg_go(chunk)) { while(!cg_go(chunk)) {
dumben_go(chunk); dumben_go(chunk);
fputs("\n; === Spill ===\n", stderr); if(ntc_get_int("pdbg")) {
fputs(ast_dump(chunk), stderr); char *astdump = ast_dump(chunk);
fputc('\n', stderr); fprintf(stderr, "### CG FAILURE ###\n%s\n", astdump);
free(astdump);
}
} }
return 0; return 0;

View File

@ -1,6 +1,13 @@
#ifndef NTC_H #ifndef NTC_H
#define NTC_H #define NTC_H
#include<stddef.h>
#include<stdint.h>
const char **ntc_get_import_paths();
const char* ntc_get_arg(const char *name); const char* ntc_get_arg(const char *name);
#endif intmax_t ntc_get_int(const char *name);
#endif

View File

@ -1,75 +0,0 @@
#include"optims.h"
#include<assert.h>
// 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;
}*/
}

View File

@ -1,5 +0,0 @@
#pragma once
#include"ast.h"
void optim_chunk(ASTChunk*);

View File

@ -29,7 +29,7 @@ typedef struct {
Token *tokens; Token *tokens;
intmax_t i; intmax_t i;
VarTable *scope; Scope *scope;
// Used to coalesce all scopes into one after parsing, to perform global register allocation // Used to coalesce all scopes into one after parsing, to perform global register allocation
ASTChunk *topLevel; ASTChunk *topLevel;
@ -38,7 +38,7 @@ typedef struct {
ASTChunk *currentChunk; ASTChunk *currentChunk;
// Used to place guard variable uses after loops to stop reg allocation from fucking up // Used to place guard variable uses after loops to stop reg allocation from fucking up
VarTable *loopScope; Scope *loopScope;
size_t guardedVarCount; size_t guardedVarCount;
ASTExprVar **guardedVars; ASTExprVar **guardedVars;
@ -112,7 +112,7 @@ static ASTExprPrimitive *parse_prim(Parser *P) {
Token tok = get(P); Token tok = get(P);
const char *str = tok.content; const char *str = tok.content;
int base = 10; long base = 10;
if(strchr(str, 'r')) { if(strchr(str, 'r')) {
if(!unstupid_strtol(str, (char**) &str, 10, &base)) { if(!unstupid_strtol(str, (char**) &str, 10, &base)) {
return NULL; return NULL;
@ -120,10 +120,13 @@ static ASTExprPrimitive *parse_prim(Parser *P) {
str++; /* Go past the r. */ str++; /* Go past the r. */
} }
if(!unstupid_strtol(str, NULL, base, &ret->val)) { long val;
if(!unstupid_strtol(str, NULL, base, &val)) {
return NULL; return NULL;
} }
ret->val = val;
// Smallest integer type to store number // Smallest integer type to store number
char buf[8]; char buf[8];
snprintf(buf, sizeof(buf), "s%i", ret->val ? (64 - __builtin_clzl(ret->val - 1)) : 1); 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; return ret;
} }
static AST *exprvar(Parser *P, VarTableEntry *v) { static AST *exprvar(Parser *P, ScopeItem *v) {
assert(v->kind != VARTABLEENTRY_TYPE); assert(v->kind != SCOPEITEM_TYPE);
AST *a = alloc_node(P, sizeof(ASTExprVar)); AST *a = alloc_node(P, sizeof(ASTExprVar));
@ -145,7 +148,7 @@ static AST *exprvar(Parser *P, VarTableEntry *v) {
// XXX: O(n)!!!!!!!!! // XXX: O(n)!!!!!!!!!
int inloop = 0; 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) { if(vt->parent == P->loopScope) {
inloop = 1; inloop = 1;
break; break;
@ -174,10 +177,10 @@ static AST *exprvar(Parser *P, VarTableEntry *v) {
return a; 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); Type *nct_parse_typename(Parser *P);
static bool parse_parametrization(Parser *P, Parametrizations *parametrizations); static bool parse_parametrization(Parser *P);
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);
static void binop_implicit_cast(/*Parser *P, */ASTExprBinaryOp *binop) { static void binop_implicit_cast(/*Parser *P, */ASTExprBinaryOp *binop) {
if(type_size(binop->operands[0]->expression.type) < type_size(binop->operands[1]->expression.type)) { 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++; 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; e->chunk->chunk.functionType = ft;
P->isInFunction--; P->isInFunction--;
@ -238,6 +241,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
expect(P, TOKEN_SQUIGGLY_R); expect(P, TOKEN_SQUIGGLY_R);
} }
e->scope = P->scope;
e->rangeTokens = P->tokens; e->rangeTokens = P->tokens;
e->startTokI = startTokI; e->startTokI = startTokI;
e->endTokI = P->i; e->endTokI = P->i;
@ -272,11 +276,25 @@ AST *nct_parse_expression(Parser *P, int lOP) {
expect(P, TOKEN_PAREN_R); 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; e = (AST*) ret;
} else { } else {
Token varname = get(P); Token varname = get(P);
VarTableEntry *vte = vartable_find(P->scope, varname.content); ScopeItem *vte = scope_find(P->scope, varname.content);
if(!vte) { if(!vte) {
stahp(varname.row, varname.column, "Unknown variable %s", varname.content); 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; ret = (AST*) call;
} else if(peek(P, 0).type == TOKEN_SQUAREN_L) { } else if(peek(P, 0).type == TOKEN_SQUAREN_L) {
Parametrizations parametrizations = {};
if(parse_parametrization(P, &parametrizations)) { P->scope = scope_new(P->scope);
if(parse_parametrization(P)) {
// Generic type parametrization // Generic type parametrization
// Generic functions are not first-class // Generic functions are not first-class
assert(ret->nodeKind == AST_EXPR_VAR); assert(ret->nodeKind == AST_EXPR_VAR);
assert(ret->exprVar.thing != NULL); 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) { if(!cvte) {
stahp_token(&P->tokens[P->i], "Parametrization %s not found.", cname); 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) { if(typesize != 1) {
ASTExprPrimitive *scale = alloc_node(P, sizeof(*scale)); ASTExprPrimitive *scale = alloc_node(P, sizeof(*scale));
scale->nodeKind = AST_EXPR_PRIMITIVE; scale->nodeKind = AST_EXPR_PRIMITIVE;
scale->type = primitive_parse("u16"); scale->type = primitive_parse("u32");
scale->val = typesize; scale->val = typesize;
ASTExprBinaryOp *mul = alloc_node(P, sizeof(*mul)); ASTExprBinaryOp *mul = alloc_node(P, sizeof(*mul));
mul->nodeKind = AST_EXPR_BINARY_OP; mul->nodeKind = AST_EXPR_BINARY_OP;
mul->type = child->operands[1]->expression.type;
mul->operator = BINOP_MUL; mul->operator = BINOP_MUL;
mul->operands[0] = (AST*) scale; mul->operands[0] = (AST*) scale;
mul->operands[1] = child->operands[1]; mul->operands[1] = child->operands[1];
@ -479,6 +500,9 @@ AST *nct_parse_expression(Parser *P, int lOP) {
ret = (AST*) unop; ret = (AST*) unop;
} }
P->scope = P->scope->parent;
} else abort(); } else abort();
} }
@ -615,26 +639,23 @@ AST *nct_parse_expression(Parser *P, int lOP) {
return NULL; return NULL;
} }
// This function modifies the current scope.
// This function may backtrack. // This function may backtrack.
static bool parse_parametrization(Parser *P, Parametrizations *parametrizations) { static bool parse_parametrization(Parser *P) {
size_t oldIdx = P->i; size_t oldIdx = P->i;
if(!maybe(P, TOKEN_SQUAREN_L)) { if(!maybe(P, TOKEN_SQUAREN_L)) {
goto backtrack; goto backtrack;
} }
intmax_t idx = 0;
bool integerMode = false; bool integerMode = false;
Parametrization *head = NULL;
Parametrization *last = NULL;
while(1) { while(1) {
if(maybe(P, TOKEN_SQUAREN_R)) { if(maybe(P, TOKEN_SQUAREN_R)) {
break; break;
} }
Parametrization *par = calloc(1, sizeof(*par));
if(integerMode) { if(integerMode) {
AST *n = nct_parse_expression(P, 0); AST *n = nct_parse_expression(P, 0);
@ -642,7 +663,16 @@ static bool parse_parametrization(Parser *P, Parametrizations *parametrizations)
goto backtrack; 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 { } else {
Type *t = nct_parse_typename(P); Type *t = nct_parse_typename(P);
@ -650,35 +680,26 @@ static bool parse_parametrization(Parser *P, Parametrizations *parametrizations)
goto backtrack; goto backtrack;
} }
par->param = t; ScopeItem *vte = calloc(1, sizeof(*vte));
} vte->kind = SCOPEITEM_TYPE;
vte->type = t;
if(!par->param) { vte->data.type.ptr = t;
goto backtrack;
}
if(!head) {
head = par;
last = head;
if(integerMode) { char buf[64];
parametrizations->intParams = head; snprintf(buf, sizeof(buf), "%li%s", idx, "t");
} else {
parametrizations->typeParams = head; scope_set(P->scope, buf, vte);
}
} else if(last) {
last->next = par;
last = par;
} }
idx++;
if(maybe(P, TOKEN_SQUAREN_R)) { if(maybe(P, TOKEN_SQUAREN_R)) {
break; break;
} }
if(maybe(P, TOKEN_SEMICOLON)) { if(maybe(P, TOKEN_SEMICOLON)) {
idx = 0;
integerMode = true; integerMode = true;
head = NULL;
last = NULL;
} else if(!maybe(P, TOKEN_COMMA)) { } else if(!maybe(P, TOKEN_COMMA)) {
goto backtrack; goto backtrack;
} }
@ -698,7 +719,7 @@ Type *nct_parse_typename(Parser *P) {
bool generics = peek(P, 0).type == TOKEN_SQUAREN_L; bool generics = peek(P, 0).type == TOKEN_SQUAREN_L;
if(generics) { if(generics) {
P->scope = vartable_new(P->scope); P->scope = scope_new(P->scope);
parse_genericization(P); parse_genericization(P);
} }
@ -711,8 +732,8 @@ Type *nct_parse_typename(Parser *P) {
Token id = expect(P, TOKEN_IDENTIFIER); Token id = expect(P, TOKEN_IDENTIFIER);
VarTableEntry *potentialVTE = vartable_find(P->scope, id.content); ScopeItem *potentialVTE = scope_find(P->scope, id.content);
if(potentialVTE && potentialVTE->kind == VARTABLEENTRY_TYPE) { if(potentialVTE && potentialVTE->kind == SCOPEITEM_TYPE) {
ret = potentialVTE->data.type.ptr; ret = potentialVTE->data.type.ptr;
} else { } else {
ret = (Type*) primitive_parse(id.content); ret = (Type*) primitive_parse(id.content);
@ -776,17 +797,17 @@ Type *nct_parse_typename(Parser *P) {
free(prim); free(prim);
} else if(maybe(P, TOKEN_QUESTION_MARK)) { } else if(maybe(P, TOKEN_QUESTION_MARK)) {
arr->length = 0; arr->length = -1;
} else if(peek(P, 0).type == TOKEN_IDENTIFIER) { } else if(peek(P, 0).type == TOKEN_IDENTIFIER) {
const char *what = expect(P, TOKEN_IDENTIFIER).content; const char *what = expect(P, TOKEN_IDENTIFIER).content;
VarTableEntry *vte = vartable_find(P->scope, what); ScopeItem *vte = scope_find(P->scope, what);
if(!vte) { if(!vte) {
goto backtrack; goto backtrack;
} }
if(vte->kind != VARTABLEENTRY_CEXPR) { if(vte->kind != SCOPEITEM_CEXPR) {
stahp_token(&P->tokens[P->i], "Variable '%s' is not constant.", what); stahp_token(&P->tokens[P->i], "Variable '%s' is not constant.", what);
} }
@ -815,11 +836,12 @@ Type *nct_parse_typename(Parser *P) {
P->i--; P->i--;
Parametrizations parametrizations = {}; P->scope = scope_new(P->scope);
assert(parse_parametrization(P, &parametrizations));
Parametrizations renames = {}; assert(parse_parametrization(P));
ret = type_parametrize(ret, &parametrizations, &renames); 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); Token name = expect(P, TOKEN_IDENTIFIER);
VarTableEntry *entry; ScopeItem *entry;
if(peek(P, 0).type == TOKEN_COLON && (entry = vartable_get(P->scope, name.content))) { if(peek(P, 0).type == TOKEN_COLON && (entry = scope_get(P->scope, name.content))) {
/* Forward declared. */ /* Forward declared. */
} else { } else {
entry = calloc(sizeof(*entry), 1); entry = calloc(sizeof(*entry), 1);
@ -873,7 +895,7 @@ static AST *parse_declaration(Parser *P) {
return NULL; return NULL;
} }
entry->kind = VARTABLEENTRY_VAR; entry->kind = SCOPEITEM_VAR;
entry->data.var.priority = 1; entry->data.var.priority = 1;
entry->data.var.color = -1; entry->data.var.color = -1;
@ -902,7 +924,7 @@ static AST *parse_declaration(Parser *P) {
return NULL; return NULL;
} }
entry->kind = VARTABLEENTRY_SYMBOL; entry->kind = SCOPEITEM_SYMBOL;
entry->data.symbol.isLocal = P->externalify ? false : isLocal; entry->data.symbol.isLocal = P->externalify ? false : isLocal;
entry->data.symbol.isExternal = P->externalify ? true : isExternal; entry->data.symbol.isExternal = P->externalify ? true : isExternal;
entry->data.symbol.name = name.content; 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)) { 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.rangeTokens = decl->expression->exprFunc.rangeTokens;
entry->data.symbol.genfunc.startTokI = decl->expression->exprFunc.startTokI; entry->data.symbol.genfunc.startTokI = decl->expression->exprFunc.startTokI;
entry->data.symbol.genfunc.endTokI = decl->expression->exprFunc.endTokI; entry->data.symbol.genfunc.endTokI = decl->expression->exprFunc.endTokI;
} }
} else if(isExternal) { } else if(isExternal) {
entry->kind = VARTABLEENTRY_SYMBOL; entry->kind = SCOPEITEM_SYMBOL;
entry->data.symbol.isLocal = isLocal; entry->data.symbol.isLocal = isLocal;
entry->data.symbol.isExternal = isExternal; entry->data.symbol.isExternal = isExternal;
entry->data.symbol.name = name.content; entry->data.symbol.name = name.content;
@ -934,7 +957,7 @@ static AST *parse_declaration(Parser *P) {
ret = (AST*) decl; ret = (AST*) decl;
} }
vartable_set(P->scope, name.content, entry); scope_set(P->scope, name.content, entry);
if(P->skimMode) { if(P->skimMode) {
// In skim mode parsing is not done normally // In skim mode parsing is not done normally
@ -961,24 +984,42 @@ static char *plus_underscore(char *s, char *ts) {
return s; 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); char *s = calloc(1, strlen(original) + 1 + 1);
strcpy(s, original); strcpy(s, original);
s[strlen(original)] = '_'; s[strlen(original)] = '_';
while(types) { for(int i = 0;; i++) {
s = plus_underscore(s, type_to_string(types->param)); 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]; 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); s = plus_underscore(s, numstr);
ints = ints->next;
} }
// Remove last underscore // Remove last underscore
@ -987,7 +1028,7 @@ static char *parametrize_function_name(Type *t, const char *original, Parametriz
return s; 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 *c = parametrizations->typeParams;
Parametrization *g = renames->typeParams; Parametrization *g = renames->typeParams;
while(c && g) { while(c && g) {
@ -996,10 +1037,10 @@ static void add_parametrizations_to_scope(Parser *P, Parametrizations *parametri
assert(!!ct == !!gt); assert(!!ct == !!gt);
VarTableEntry *vte = calloc(1, sizeof(*vte)); ScopeItem *vte = calloc(1, sizeof(*vte));
vte->kind = VARTABLEENTRY_TYPE; vte->kind = SCOPEITEM_TYPE;
vte->data.type.ptr = ct; vte->data.type.ptr = ct;
vartable_set(P->scope, gt->generic.paramName, vte); scope_set(P->scope, gt->generic.paramName, vte);
c = c->next; c = c->next;
g = g->next; g = g->next;
@ -1014,18 +1055,18 @@ static void add_parametrizations_to_scope(Parser *P, Parametrizations *parametri
assert(!!node == !!name); assert(!!node == !!name);
VarTableEntry *vte = calloc(1, sizeof(*vte)); ScopeItem *vte = calloc(1, sizeof(*vte));
vte->kind = VARTABLEENTRY_CEXPR; vte->kind = SCOPEITEM_CEXPR;
vte->data.cexpr.paramIdx = idx; vte->data.cexpr.paramIdx = idx;
vte->data.cexpr.paramName = name; vte->data.cexpr.paramName = name;
vte->data.cexpr.concrete = node; vte->data.cexpr.concrete = node;
vartable_set(P->scope, name, vte); scope_set(P->scope, name, vte);
c = c->next; c = c->next;
g = g->next; g = g->next;
idx++; idx++;
} }
} }*/
void nct_parse_statement(Parser *P) { void nct_parse_statement(Parser *P) {
if(maybe(P, TOKEN_IF)) { if(maybe(P, TOKEN_IF)) {
@ -1137,6 +1178,7 @@ void nct_parse_statement(Parser *P) {
return; return;
} else if(maybe(P, TOKEN_USE)) { } else if(maybe(P, TOKEN_USE)) {
while(get(P).type != TOKEN_SEMICOLON); while(get(P).type != TOKEN_SEMICOLON);
return;
} else if(peek(P, 0).type == TOKEN_IDENTIFIER) { } else if(peek(P, 0).type == TOKEN_IDENTIFIER) {
if(!strcmp(peek(P, 0).content, "@align")) { if(!strcmp(peek(P, 0).content, "@align")) {
ASTStmtExtAlign *ret = alloc_node(P, sizeof(*ret)); ASTStmtExtAlign *ret = alloc_node(P, sizeof(*ret));
@ -1192,7 +1234,7 @@ void nct_parse_statement(Parser *P) {
Token funcname = expect(P, TOKEN_IDENTIFIER); Token funcname = expect(P, TOKEN_IDENTIFIER);
VarTableEntry *func = vartable_find(P->scope, funcname.content); ScopeItem *func = scope_find(P->scope, funcname.content);
if(!func) { if(!func) {
stahp_token(&P->tokens[P->i], "Cannot find function %s for parametrization.", funcname.content); 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)); assert(type_is_generic(func->type));
Parametrizations parametrizations = {}; Scope *oldScope = P->scope;
assert(parse_parametrization(P, &parametrizations)); P->scope = scope_new(oldScope);
P->scope = vartable_new(P->scope); assert(parse_parametrization(P));
Parametrizations renames = {}; P->scope->parent = func->data.symbol.genfunc.scope;
Type *parametrizedFuncType = type_parametrize(func->type, &parametrizations, &renames);
add_parametrizations_to_scope(P, &parametrizations, &renames); Type *parametrizedFuncType = type_parametrize(func->type, P->scope);
size_t oldIdx = P->i; size_t oldIdx = P->i;
Token *oldTokens = P->tokens;
P->tokens = func->data.symbol.genfunc.rangeTokens;
P->i = func->data.symbol.genfunc.startTokI; 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) { while(1) {
TokenKind tk = get(P).type; if(maybe(P, TOKEN_SQUAREN_R)) {
if(tk == TOKEN_SQUAREN_L) { break;
depth++; }
} else if(tk == TOKEN_SQUAREN_R) {
if(--depth == 0) { 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; 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); AST *concreteFunction = nct_parse_expression(P, 0);
assert(concreteFunction->nodeKind == AST_EXPR_FUNC); assert(concreteFunction->nodeKind == AST_EXPR_FUNC);
P->i = oldIdx; P->i = oldIdx;
P->tokens = oldTokens;
P->scope = P->scope->parent; ScopeItem *vte = calloc(1, sizeof(*vte));
vte->kind = SCOPEITEM_SYMBOL;
VarTableEntry *vte = calloc(1, sizeof(*vte));
vte->kind = VARTABLEENTRY_SYMBOL;
vte->type = parametrizedFuncType; 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.isExternal = false;
vte->data.symbol.isLocal = 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)); ASTStmtDecl *decl = alloc_node(P, sizeof(*decl));
decl->nodeKind = AST_STMT_DECL; decl->nodeKind = AST_STMT_DECL;
@ -1257,6 +1320,13 @@ void nct_parse_statement(Parser *P) {
{ {
AST *decl = parse_declaration(P); AST *decl = parse_declaration(P);
if(decl) { 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 // 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)) { if(decl->nodeKind != AST_STMT_DECL || !type_is_generic(decl->stmtDecl.thing->type)) {
pushstat(P, decl); pushstat(P, decl);
@ -1315,21 +1385,21 @@ void parse_genericization(Parser *P) {
tg->generic.paramName = strdup(get(P).content); tg->generic.paramName = strdup(get(P).content);
tg->generic.paramIdx = nextIdx; tg->generic.paramIdx = nextIdx;
VarTableEntry *vte = calloc(1, sizeof(*vte)); ScopeItem *vte = calloc(1, sizeof(*vte));
vte->kind = VARTABLEENTRY_TYPE; vte->kind = SCOPEITEM_TYPE;
vte->data.type.ptr = tg; vte->data.type.ptr = tg;
vartable_set(P->scope, strdup(tg->generic.paramName), vte); scope_set(P->scope, strdup(tg->generic.paramName), vte);
} else { } else {
VarTableEntry *vte = calloc(1, sizeof(*vte)); ScopeItem *vte = calloc(1, sizeof(*vte));
vte->type = primitive_parse("u32"); vte->type = primitive_parse("u32");
vte->kind = VARTABLEENTRY_CEXPR; vte->kind = SCOPEITEM_CEXPR;
vte->data.cexpr.paramName = strdup(get(P).content); vte->data.cexpr.paramName = strdup(get(P).content);
vte->data.cexpr.paramIdx = nextIdx; 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) { Type *nct_parse_record_definition(Parser *P) {
expect(P, TOKEN_RECORD); expect(P, TOKEN_RECORD);
P->scope = vartable_new(P->scope); P->scope = scope_new(P->scope);
Token name = expect(P, TOKEN_IDENTIFIER); Token name = expect(P, TOKEN_IDENTIFIER);
@ -1432,12 +1502,22 @@ static void skim_chunk(Parser *P, int isTopLevel) {
} }
} }
stomp:; stomp:;
} else if(k == TOKEN_COLON) { } else if(k == TOKEN_COLON || k == TOKEN_EXTERN) {
/* Move back to beginning of declaration. */ /* 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--; 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); AST *d = parse_declaration(P);
if(!d) abort(); if(!d) abort();
@ -1448,11 +1528,11 @@ static void skim_chunk(Parser *P, int isTopLevel) {
Type *tr = nct_parse_record_definition(P); Type *tr = nct_parse_record_definition(P);
VarTableEntry *vte = calloc(1, sizeof(*vte)); ScopeItem *vte = calloc(1, sizeof(*vte));
vte->kind = VARTABLEENTRY_TYPE; vte->kind = SCOPEITEM_TYPE;
vte->data.type.ptr = tr; 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) { } else if(k == TOKEN_USE) {
char *path = malp("%s", expect(P, TOKEN_IDENTIFIER).content); char *path = malp("%s", expect(P, TOKEN_IDENTIFIER).content);
@ -1469,30 +1549,42 @@ static void skim_chunk(Parser *P, int isTopLevel) {
path = path2; path = path2;
} }
{ FILE *f = NULL;
for(const char **importPaths = ntc_get_import_paths(); *importPaths; importPaths++) {
char *path2 = malp("tests/%s.nct", path); 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); skim_chunk(&subp, 1);
// Copy all extern symbols from the scope into our TLC's externs array // Copy all extern symbols from the scope into our TLC's externs array
for(size_t i = 0; i < subp.scope->count; i++) { for(size_t i = 0; i < subp.scope->count; i++) {
VarTableEntry *vte = subp.scope->data[i]; ScopeItem *vte = subp.scope->data[i];
if(vte->kind == VARTABLEENTRY_SYMBOL && vte->data.symbol.isExternal) { 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 = realloc(P->topLevel->externs, sizeof(*P->topLevel->externs) * (++P->topLevel->externCount));
P->topLevel->externs[P->topLevel->externCount - 1] = vte; P->topLevel->externs[P->topLevel->externCount - 1] = vte;
} }
} }
subp.scope->parent = P->scope; subp.scope->parent = P->scope;
vartable_merge(subp.scope); scope_merge(subp.scope);
free(subp.tokens); // free(subp.tokens); DO THIS CANNOT
fclose(f); fclose(f);
} }
@ -1502,7 +1594,7 @@ static void skim_chunk(Parser *P, int isTopLevel) {
P->skimMode--; 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)); AST *ret = alloc_node(P, sizeof(ASTChunk));
ret->nodeKind = AST_CHUNK; ret->nodeKind = AST_CHUNK;
ret->chunk.statementFirst = ret->chunk.statementLast = NULL; 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; AST *oldChunk = (AST*) P->currentChunk;
P->currentChunk = &ret->chunk; 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; ASTChunk *oldTopLevel = P->topLevel;
if(isTopLevel) { if(isTopLevel) {
@ -1526,16 +1618,17 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable
/* Arguments */ /* Arguments */
if(ft && isTopLevel) { 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--) { // First arguments in a function TLC is the arguments
VarTableEntry *vte = calloc(1, sizeof(*vte)); for(int i = 0; i < ft->function.argCount; i++) {
vte->kind = VARTABLEENTRY_VAR; ScopeItem *vte = calloc(1, sizeof(*vte));
vte->kind = SCOPEITEM_VAR;
vte->type = ft->function.args[i]; vte->type = ft->function.args[i];
vte->data.var.name = ft->function.argNames[i]; vte->data.var.name = ft->function.argNames[i];
vte->data.var.color = -1; vte->data.var.color = -1;
vartable_set(toplevelParent, vte->data.var.name, vte); scope_set(toplevelParent, vte->data.var.name, vte);
vtes[i] = vte; vtes[i] = vte;
} }
@ -1547,21 +1640,23 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable
nct_parse_statement(P); 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++) { for(size_t i = 0; i < P->scope->count; i++) {
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) { if(P->scope->data[i]->kind == SCOPEITEM_VAR) {
nonSymbols++; varsToAdd++;
if(varPrioritize) {
P->scope->data[i]->data.var.priority++;
}
} }
} }
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++) { P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (P->topLevel->varCount + varsToAdd));
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
P->topLevel->vars[P->topLevel->varCount++] = P->scope->data[i]; // This makes sure function arguments stay first in the array
//P->scope->data[i]->owner = P->topLevel; // not sure why this line ever existed, it makes no sense 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; Parser P;
memset(&P, 0, sizeof(P)); memset(&P, 0, sizeof(P));
P.tokens = tokens; 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);
} }

View File

@ -6,6 +6,7 @@
#include<stdint.h> #include<stdint.h>
#include"ast.h" #include"ast.h"
#include"reporting.h" #include"reporting.h"
#include<assert.h>
#include"ntc.h" #include"ntc.h"
@ -234,35 +235,12 @@ bool type_is_generic(Type *t) {
return false; return false;
} }
static void *parametrization_get_by_index(Parametrization *list, size_t idx) { Type *type_parametrize(Type *t, Scope *scope) {
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) {
if(t->type == TYPE_TYPE_RECORD) { if(t->type == TYPE_TYPE_RECORD) {
t = type_shallow_copy(t); t = type_shallow_copy(t);
for(size_t f = 0; f < t->record.fieldCount; f++) { 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)) { if(!type_is_generic(t)) {
@ -279,51 +257,48 @@ Type *type_parametrize(Type *t, Parametrizations *parametrizations, Parametrizat
} else if(t->type == TYPE_TYPE_FUNCTION) { } else if(t->type == TYPE_TYPE_FUNCTION) {
t = type_shallow_copy(t); 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++) { 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) { } 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) { if(vte) {
parametrization_set_by_index(&renames->typeParams, t->generic.paramIdx, t); assert(vte->kind == SCOPEITEM_TYPE);
} return vte->data.type.ptr;
if(newt) {
return newt;
} }
} else if(t->type == TYPE_TYPE_POINTER) { } else if(t->type == TYPE_TYPE_POINTER) {
t = type_shallow_copy(t); 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) { } else if(t->type == TYPE_TYPE_ARRAY) {
t = type_shallow_copy(t); 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) { 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) { if(vte) {
while(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR && n->exprVar.thing->data.cexpr.concrete) { assert(vte->kind == SCOPEITEM_CEXPR);
n = n->exprVar.thing->data.cexpr.concrete;
}
if(n->nodeKind == AST_EXPR_PRIMITIVE) { AST *n = vte->data.cexpr.concrete;
t->array.length = n->exprPrim.val;
t->array.lengthIsGeneric = false; if(n) {
} else if(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR) { if(n->nodeKind == AST_EXPR_PRIMITIVE) {
t->array.lengthGenericParamIdx = n->exprVar.thing->data.cexpr.paramIdx; t->array.length = n->exprPrim.val;
t->array.lengthGenericParamName = n->exprVar.thing->data.cexpr.paramName; t->array.lengthIsGeneric = false;
t->array.lengthIsGeneric = true; } else if(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == SCOPEITEM_CEXPR) {
} else { t->array.lengthGenericParamIdx = n->exprVar.thing->data.cexpr.paramIdx;
stahp_node(n, "Invalid parametrization expression."); 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);
} }
} }

View File

@ -102,18 +102,8 @@ int type_is_number(Type *t);
char *type_to_string(Type*); char *type_to_string(Type*);
typedef struct Parametrization { struct Scope;
void *param; Type *type_parametrize(Type *target, struct Scope *scope);
struct Parametrization *next;
} Parametrization;
typedef struct {
Parametrization *typeParams;
Parametrization *intParams;
} Parametrizations;
Type *type_parametrize(Type *target, Parametrizations *parametrizations, Parametrizations *renames);
Type *type_shallow_copy(Type *t); Type *type_shallow_copy(Type *t);

View File

@ -4,6 +4,7 @@
#include<stdlib.h> #include<stdlib.h>
#include<string.h> #include<string.h>
#include<assert.h> #include<assert.h>
#include<stdio.h>
struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) { struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) {
struct ReachingDefs *ret = calloc(1, sizeof(*ret)); struct ReachingDefs *ret = calloc(1, sizeof(*ret));
@ -30,8 +31,8 @@ void reachingdefs_set(struct ReachingDefs *this, union AST *def) {
this->excludeParent = 1; this->excludeParent = 1;
} }
VarTable *vartable_new(VarTable *parent) { Scope *scope_new(Scope *parent) {
VarTable *ret = calloc(1, sizeof(*ret)); Scope *ret = calloc(1, sizeof(*ret));
ret->parent = parent; ret->parent = parent;
ret->count = 0; ret->count = 0;
ret->names = NULL; ret->names = NULL;
@ -40,17 +41,17 @@ VarTable *vartable_new(VarTable *parent) {
return ret; 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++) { for(size_t v = 0; v < this->count; v++) {
if(!strcmp(name, this->names[v])) return this->data[v]; if(!strcmp(name, this->names[v])) return this->data[v];
} }
return NULL; return NULL;
} }
VarTableEntry *vartable_find(VarTable *this, const char *name) { ScopeItem *scope_find(Scope *this, const char *name) {
VarTable *tbl = this; Scope *tbl = this;
while(tbl) { while(tbl) {
VarTableEntry *entry = vartable_get(tbl, name); ScopeItem *entry = scope_get(tbl, name);
if(entry) { if(entry) {
return entry; return entry;
} }
@ -59,43 +60,28 @@ VarTableEntry *vartable_find(VarTable *this, const char *name) {
return NULL; 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->names = realloc(this->names, sizeof(*this->names) * (this->count + 1));
this->data = realloc(this->data, sizeof(*this->data) * (this->count + 1)); this->data = realloc(this->data, sizeof(*this->data) * (this->count + 1));
this->names[this->count] = name; this->names[this->count] = name;
this->data[this->count] = e; this->data[this->count] = e;
this->count++; 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; e->owner = this;
return e; return e;
} }
/*void vartable_new_reachingdefs_for_all_vars(VarTable *this) { ScopeItem *scope_find_int(Scope *scope, intmax_t val, const char *suffix) {
for(size_t i = 0; i < this->count; i++) { char buf[64];
if(this->data[i]->kind == VARTABLEENTRY_VAR) { snprintf(buf, sizeof(buf), "%li%s", val, suffix ? suffix : "");
this->data[i]->data.var.reachingDefs = reachingdefs_push(this->data[i]->data.var.reachingDefs);
}
}
if(this->parent) { return scope_find(scope, buf);
vartable_new_reachingdefs_for_all_vars(this->parent);
}
} }
void vartable_coalesce_reachingdefs_for_all_vars(VarTable *this) { Scope *scope_merge(Scope *child) {
for(size_t i = 0; i < this->count; i++) { Scope *parent = child->parent;
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;
parent->names = realloc(parent->names, sizeof(*parent->names) * (parent->count + child->count)); parent->names = realloc(parent->names, sizeof(*parent->names) * (parent->count + child->count));
parent->data = realloc(parent->data, sizeof(*parent->data) * (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++; parent->count++;
} }
free(child->names); //free(child->names);
free(child->data); //free(child->data);
free(child); //free(child);
return parent; return parent;
} }
void vte_precolor(VarTableEntry *vte, int color) { void vte_precolor(ScopeItem *vte, int class, int color) {
assert(vte->kind == VARTABLEENTRY_VAR && "vte must be var"); assert(vte->kind == SCOPEITEM_VAR && "vte must be var");
assert(!vte->data.var.precolored && "already precolored"); assert(!vte->data.var.precolored && "already precolored");
vte->data.var.precolored = true; vte->data.var.precolored = true;
vte->data.var.registerClass = class;
vte->data.var.color = color; vte->data.var.color = color;
} }

View File

@ -8,8 +8,8 @@ struct Token;
union AST; union AST;
typedef enum { typedef enum {
VARTABLEENTRY_SYMBOL, VARTABLEENTRY_VAR, VARTABLEENTRY_TYPE, VARTABLEENTRY_CEXPR SCOPEITEM_SYMBOL, SCOPEITEM_VAR, SCOPEITEM_TYPE, SCOPEITEM_CEXPR
} VarTableEntryKind; } ScopeItemKind;
union AST; union AST;
typedef struct UseDef { typedef struct UseDef {
@ -31,82 +31,81 @@ struct ReachingDefs *reachingdefs_push(struct ReachingDefs*);
struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*); struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*);
void reachingdefs_set(struct ReachingDefs*, union AST*); void reachingdefs_set(struct ReachingDefs*, union AST*);
struct VarTable; struct Scope;
typedef struct VarTableEntry { typedef struct ScopeItem {
Type *type; Type *type;
struct VarTable *owner; struct Scope *owner;
VarTableEntryKind kind; ScopeItemKind kind;
struct { union {
union { struct {
char isLocal;
char isExternal;
const char *name;
struct { struct {
char isLocal; struct Scope *scope;
char isExternal; struct Token *rangeTokens;
const char *name; size_t startTokI;
size_t endTokI;
struct { } genfunc;
struct Token *rangeTokens; } symbol;
size_t startTokI; struct {
size_t endTokI; // For debugging
} genfunc;
} symbol; const char *name;
struct {
// For debugging // Register allocation
const char *name; // 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)
// Register allocation uint8_t priority;
int16_t color, degree;
// vars in loops have higher priority bool precolored;
// a more advanced approach would be to use weights for different colors (e.g. multipliers "should" be in eax) int registerClass;
uint8_t priority;
int16_t color, degree; // Used during parsing
bool precolored;
ReachingDefs *reachingDefs;
// Used during parsing
// Optimizations
ReachingDefs *reachingDefs;
UseDef *usedefFirst;
// Optimizations UseDef *usedefLast;
} var;
UseDef *usedefFirst; struct {
UseDef *usedefLast; Type *ptr;
} var; } type;
struct { struct {
Type *ptr; // cexpr is used for expression parametization as opposed to type parametrization
} type; // I don't like the idea of having a special ScopeItem kind for these, but all other places were worse
struct { const char *paramName;
// cexpr is used for expression parametization as opposed to type parametrization size_t paramIdx;
// I don't like the idea of having a special VarTableEntry kind for these, but all other places were worse
const char *paramName; // If the cexpr has been parametrized (as opposed to just being a symbol), this field will be non-NULL
size_t paramIdx; union AST *concrete;
} cexpr;
// If the cexpr has been parametrized (as opposed to just being a symbol), this field will be non-NULL
union AST *concrete;
} cexpr;
};
} data; } data;
} VarTableEntry; } ScopeItem;
typedef struct VarTable { typedef struct Scope {
struct VarTable *parent; struct Scope *parent;
size_t count; size_t count;
const char **names; const char **names;
VarTableEntry **data; ScopeItem **data;
} VarTable; } Scope;
VarTable *vartable_new(VarTable*); Scope *scope_new(Scope*);
VarTableEntry *vartable_get(VarTable*, const char*); ScopeItem *scope_get(Scope*, const char*);
VarTableEntry *vartable_find(VarTable*, const char*); ScopeItem *scope_find(Scope*, const char*);
VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*); 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*); Scope *scope_merge(Scope *child);
//void vartable_coalesce_reachingdefs_for_all_vars(VarTable*);
void vte_precolor(VarTableEntry *vte, int color); void vte_precolor(ScopeItem *vte, int resclass, int color);
#endif #endif

View File

@ -3,11 +3,90 @@
#include<string.h> #include<string.h>
#include"ntc.h" #include"ntc.h"
#include<assert.h> #include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
#include"ast.h"
#define COLOR_EAX 0 #define HWR_AL 1
#define COLOR_ECX 1 #define HWR_AH 2
#define COLOR_EDX 2 #define HWR_BL 4
#define COLOR_EBX 3 #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? // Can expression be expressed as a single x86 operand?
#define XOP_NOT_XOP 0 #define XOP_NOT_XOP 0
@ -21,10 +100,10 @@ static inline int is_xop(AST *e) {
if(e->nodeKind == AST_EXPR_PRIMITIVE) { if(e->nodeKind == AST_EXPR_PRIMITIVE) {
return XOP_NOT_MEM; return XOP_NOT_MEM;
} else if(e->nodeKind == AST_EXPR_VAR) { } 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) { } 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; 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; return XOP_NOT_MEM;
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
AST *c = e->exprUnOp.operand; AST *c = e->exprUnOp.operand;
@ -33,7 +112,7 @@ static inline int is_xop(AST *e) {
c = c->exprCast.what; 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; return XOP_MEM;
} else if( } 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) || (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; 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; return DEST_IS_BAD_XOP;
} }

View File

@ -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);*/

View File

@ -1,3 +1,4 @@
use Exporter; use Exporter;
u32 a = Exporter.SYMBOL; Foo f;
f.gaga = SYMBOL;