Compare commits
No commits in common. "438c3b34676d9d487bdf2a6d4eb295f53696fd5e" and "1c4b5a5095d99d8c1535c4e1ff4297ec36f51acc" have entirely different histories.
438c3b3467
...
1c4b5a5095
151
src/ast.c
151
src/ast.c
@ -5,8 +5,6 @@
|
|||||||
#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)
|
||||||
@ -80,10 +78,6 @@ 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();
|
||||||
}
|
}
|
||||||
@ -151,7 +145,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 SCOPEITEM_VAR) holds its own UD-chain
|
* Each local var (VTE of kind VARTABLEENTRY_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
|
||||||
@ -210,8 +204,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(ScopeItem *vte, UseDef *ud) {
|
static void rawadduse(VarTableEntry *vte, UseDef *ud) {
|
||||||
assert(vte->kind == SCOPEITEM_VAR);
|
assert(vte->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
assert(ud->next == NULL);
|
assert(ud->next == NULL);
|
||||||
|
|
||||||
@ -225,8 +219,8 @@ static void rawadduse(ScopeItem *vte, UseDef *ud) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adduse(ScopeItem *vte, AST *use, AST *whole) {
|
static void adduse(VarTableEntry *vte, AST *use, AST *whole) {
|
||||||
assert(vte->kind == SCOPEITEM_VAR);
|
assert(vte->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
assert(vte->data.var.reachingDefs != NULL);
|
assert(vte->data.var.reachingDefs != NULL);
|
||||||
|
|
||||||
@ -247,8 +241,8 @@ static void adduse(ScopeItem *vte, AST *use, AST *whole) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void overwritedefs(ScopeItem *vte, AST *def) {
|
static void overwritedefs(VarTableEntry *vte, AST *def) {
|
||||||
assert(vte->kind == SCOPEITEM_VAR);
|
assert(vte->kind == VARTABLEENTRY_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));
|
||||||
@ -256,12 +250,15 @@ static void overwritedefs(ScopeItem *vte, AST *def) {
|
|||||||
|
|
||||||
vte->data.var.reachingDefs->defCount = 1;
|
vte->data.var.reachingDefs->defCount = 1;
|
||||||
|
|
||||||
vte->data.var.reachingDefs->defs = realloc(vte->data.var.reachingDefs->defs, sizeof(*vte->data.var.reachingDefs->defs));
|
if(!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(ScopeItem *vte) {
|
static void mergedefs(VarTableEntry *vte) {
|
||||||
assert(vte->kind == SCOPEITEM_VAR);
|
assert(vte->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
ReachingDefs *rdefs = vte->data.var.reachingDefs;
|
ReachingDefs *rdefs = vte->data.var.reachingDefs;
|
||||||
|
|
||||||
@ -277,8 +274,8 @@ static void mergedefs(ScopeItem *vte) {
|
|||||||
free(rdefs);
|
free(rdefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pushdefs(ScopeItem *vte) {
|
static void pushdefs(VarTableEntry *vte) {
|
||||||
assert(vte->kind == SCOPEITEM_VAR);
|
assert(vte->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
ReachingDefs *rdefs = calloc(1, sizeof(*rdefs));
|
ReachingDefs *rdefs = calloc(1, sizeof(*rdefs));
|
||||||
rdefs->defCount = 0;
|
rdefs->defCount = 0;
|
||||||
@ -301,8 +298,8 @@ static void mergedefsall(AST *tlc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mergedefsloop(AST *tlc, ScopeItem *vte, AST *daLoopStmt) {
|
static void mergedefsloop(AST *tlc, VarTableEntry *vte, AST *daLoopStmt) {
|
||||||
assert(vte->kind == SCOPEITEM_VAR);
|
assert(vte->kind == VARTABLEENTRY_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;
|
||||||
@ -354,7 +351,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 == SCOPEITEM_VAR) {
|
if(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||||
overwritedefs(a->stmtAssign.what->exprVar.thing, a);
|
overwritedefs(a->stmtAssign.what->exprVar.thing, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +363,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 == SCOPEITEM_VAR) {
|
if(a->exprVar.thing->kind == VARTABLEENTRY_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) {
|
||||||
@ -392,7 +389,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 != SCOPEITEM_VAR || a->stmtDecl.expression);
|
assert(a->stmtDecl.thing->kind != VARTABLEENTRY_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);
|
||||||
@ -404,9 +401,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++) {
|
||||||
ScopeItem *vte = chu->chunk.vars[i];
|
VarTableEntry *vte = chu->chunk.vars[i];
|
||||||
|
|
||||||
assert(vte->kind == SCOPEITEM_VAR);
|
assert(vte->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
vte->data.var.reachingDefs = NULL;
|
vte->data.var.reachingDefs = NULL;
|
||||||
vte->data.var.usedefFirst = NULL;
|
vte->data.var.usedefFirst = NULL;
|
||||||
@ -418,6 +415,16 @@ 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);
|
||||||
@ -456,7 +463,7 @@ char *type_to_string(Type *t) {
|
|||||||
if(t->array.lengthIsGeneric) {
|
if(t->array.lengthIsGeneric) {
|
||||||
len = malp("");
|
len = malp("");
|
||||||
} else {
|
} else {
|
||||||
len = malp("%li", t->array.length);
|
len = malp("%i", t->array.length);
|
||||||
}
|
}
|
||||||
char *r = malp("%s[%s]", of, len);
|
char *r = malp("%s[%s]", of, len);
|
||||||
free(of);
|
free(of);
|
||||||
@ -471,11 +478,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) {
|
||||||
ScopeItem *vte = e->exprVar.thing;
|
VarTableEntry *vte = e->exprVar.thing;
|
||||||
|
|
||||||
if(vte->kind == SCOPEITEM_VAR) {
|
if(vte->kind == VARTABLEENTRY_VAR) {
|
||||||
return strdup(vte->data.var.name);
|
return strdup(vte->data.var.name);
|
||||||
} else if(vte->kind == SCOPEITEM_SYMBOL) {
|
} else if(vte->kind == VARTABLEENTRY_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) {
|
||||||
@ -626,9 +633,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) {
|
||||||
ScopeItem *vte = s->stmtDecl.thing;
|
VarTableEntry *vte = s->stmtDecl.thing;
|
||||||
|
|
||||||
if(vte->kind == SCOPEITEM_SYMBOL) {
|
if(vte->kind == VARTABLEENTRY_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);
|
||||||
@ -665,7 +672,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 == SCOPEITEM_VAR) {
|
if(s->stmtExpr.expr->exprVar.thing->kind == VARTABLEENTRY_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;
|
||||||
@ -691,14 +698,12 @@ 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 = malp("");
|
char *ret = strdup("");
|
||||||
|
|
||||||
|
#define CAT(s) do { char *b = s; ret = cat(ret, (b)); free(b); } while(0)
|
||||||
|
|
||||||
while(stmt) {
|
while(stmt) {
|
||||||
char *new = ast_dumps(stmt);
|
CAT(ast_dumps(stmt));
|
||||||
char *ret2 = malp("%s%s", ret, new);
|
|
||||||
free(ret);
|
|
||||||
free(new);
|
|
||||||
ret = ret2;
|
|
||||||
|
|
||||||
stmt = stmt->statement.next;
|
stmt = stmt->statement.next;
|
||||||
}
|
}
|
||||||
@ -727,18 +732,13 @@ 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 || to->array.length == -1)) {
|
if(to->type == TYPE_TYPE_ARRAY && type_equal(primitive_parse("u8"), to->array.of) && to->array.length == what->exprStrLit.length) {
|
||||||
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(what->exprStrLit.length, sizeof(*ret->items));
|
ret->items = calloc(to->array.length, sizeof(*ret->items));
|
||||||
ret->type = to;
|
ret->type = to;
|
||||||
|
|
||||||
// If this declaration is of an unknown-length array type (eg u8[?]) then update the length
|
for(int i = 0; i < to->array.length; i++) {
|
||||||
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 == SCOPEITEM_CEXPR && what->exprVar.thing->data.cexpr.concrete) {
|
while(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == VARTABLEENTRY_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 == SCOPEITEM_CEXPR));
|
assert(!(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == VARTABLEENTRY_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;
|
||||||
ScopeItem *target; // can be NULL
|
VarTableEntry *target;
|
||||||
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,14 +855,12 @@ static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_spill_to_stack(AST *tlc, ScopeItem *vte) {
|
void ast_spill_to_stack(AST *tlc, VarTableEntry *vte) {
|
||||||
assert(tlc->nodeKind == AST_CHUNK);
|
assert(tlc->nodeKind == AST_CHUNK);
|
||||||
assert(vte != NULL);
|
assert(vte != NULL);
|
||||||
assert(vte->kind == SCOPEITEM_VAR);
|
assert(vte->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
if(ntc_get_int("pdbg")) {
|
fprintf(stderr, "Spilling %s to stack...\n", vte->data.var.name);
|
||||||
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));
|
||||||
@ -871,37 +869,17 @@ void ast_spill_to_stack(AST *tlc, ScopeItem *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_TYPE_FUNCTION) {
|
if(a->exprCall.what->expression.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]->expression.type) || !type_is_number(a->exprBinOp.operands[1]->expression.type)) {
|
if(!type_is_number(a->exprBinOp.operands[0]) || !type_is_number(a->exprBinOp.operands[1])) {
|
||||||
stahp_node(a, "Operands must be numbers.");
|
stahp_node(a, "Operands must be numbers.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -920,25 +898,6 @@ static void typecheck_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk,
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ast_type_check(AST *tlc, ScopeItem *vte) {
|
void ast_type_check(AST *tlc, VarTableEntry *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);
|
|
||||||
}
|
|
||||||
|
34
src/ast.h
34
src/ast.h
@ -5,6 +5,11 @@
|
|||||||
#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__
|
||||||
@ -42,8 +47,7 @@
|
|||||||
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[];
|
||||||
@ -79,10 +83,6 @@ 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;
|
||||||
|
|
||||||
ScopeItem *thing;
|
VarTableEntry *thing;
|
||||||
} ASTExprVar;
|
} ASTExprVar;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -171,7 +171,6 @@ 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;
|
||||||
@ -204,7 +203,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
ASTStmt;
|
ASTStmt;
|
||||||
|
|
||||||
ScopeItem *thing;
|
VarTableEntry *thing;
|
||||||
|
|
||||||
union AST *expression;
|
union AST *expression;
|
||||||
} ASTStmtDecl;
|
} ASTStmtDecl;
|
||||||
@ -214,11 +213,11 @@ typedef struct {
|
|||||||
|
|
||||||
/* Flattened variable array for global register allocation */
|
/* Flattened variable array for global register allocation */
|
||||||
size_t varCount;
|
size_t varCount;
|
||||||
ScopeItem **vars;
|
VarTableEntry **vars;
|
||||||
|
|
||||||
/* extern symbol array */
|
/* extern symbol array */
|
||||||
size_t externCount;
|
size_t externCount;
|
||||||
ScopeItem **externs;
|
VarTableEntry **externs;
|
||||||
|
|
||||||
union AST *statementFirst;
|
union AST *statementFirst;
|
||||||
union AST *statementLast;
|
union AST *statementLast;
|
||||||
@ -316,14 +315,6 @@ 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;
|
||||||
|
|
||||||
@ -352,7 +343,6 @@ 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)
|
||||||
@ -372,12 +362,10 @@ 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, ScopeItem *vte);
|
void ast_spill_to_stack(AST *tlc, VarTableEntry *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
483
src/cg.c
@ -4,12 +4,18 @@
|
|||||||
#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;
|
||||||
@ -47,7 +53,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;
|
||||||
@ -60,38 +66,30 @@ static const char *spec(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(ScopeItem *v, int sz) {
|
static const char *xv_sz(VarTableEntry *v, int sz) {
|
||||||
assert(v->kind == SCOPEITEM_VAR);
|
assert(v->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
#define XVBUFS 8
|
#define XVBUFS 8
|
||||||
#define XVBUFSZ 16
|
#define XVBUFSZ 8
|
||||||
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];
|
||||||
|
|
||||||
if(ntc_get_int("rcd")) {
|
#ifdef DEBUG
|
||||||
snprintf(ret, XVBUFSZ, "%i@%i", v->data.var.registerClass, v->data.var.color);
|
snprintf(ret, XVBUFSZ, "@%i", v->data.var.color);
|
||||||
} else {
|
#else
|
||||||
int cls = v->data.var.registerClass, reg = v->data.var.color;
|
snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(sz)]);
|
||||||
|
#endif
|
||||||
if(type_size(v->type) != sz) {
|
|
||||||
if(sz == 4) {
|
|
||||||
reg_cast_up(&cls, ®);
|
|
||||||
} else abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(ret, XVBUFSZ, "%s", REG_CLASSES[cls].rsN[reg]);
|
|
||||||
}
|
|
||||||
|
|
||||||
bufidx = (bufidx + 1) % XVBUFS;
|
bufidx = (bufidx + 1) % XVBUFS;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *xv(ScopeItem *v) {
|
static const char *xv(VarTableEntry *v) {
|
||||||
return xv_sz(v, type_size(v->type));
|
return xv_sz(v, type_size(v->type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,11 +116,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 == SCOPEITEM_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 == VARTABLEENTRY_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 == SCOPEITEM_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 == VARTABLEENTRY_VAR) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,9 +136,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;
|
||||||
@ -149,12 +147,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 == SCOPEITEM_VAR && p->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_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 == VARTABLEENTRY_VAR && p->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_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 == SCOPEITEM_SYMBOL && p->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_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 == VARTABLEENTRY_SYMBOL && p->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_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,
|
||||||
@ -172,20 +170,18 @@ 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),
|
||||||
REG_CLASSES[vte->data.var.registerClass].rsN[vte->data.var.color],
|
regs[e->exprBinOp.operands[0]->exprVar.thing->data.var.color][2],
|
||||||
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 == 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) {
|
} 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) {
|
||||||
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 == SCOPEITEM_VAR) {
|
} else if(p->nodeKind == AST_EXPR_VAR && p->exprVar.thing->kind == VARTABLEENTRY_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);
|
||||||
@ -194,18 +190,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");
|
snprintf(ret, XOPBUFSZ, "esp", tlc->chunk.stackReservation);
|
||||||
} else if(e->nodeKind == AST_EXPR_VAR) {
|
} else if(e->nodeKind == AST_EXPR_VAR) {
|
||||||
ScopeItem *v = e->exprVar.thing;
|
VarTableEntry *v = e->exprVar.thing;
|
||||||
|
|
||||||
if(v->kind == SCOPEITEM_VAR) {
|
if(v->kind == VARTABLEENTRY_VAR) {
|
||||||
return xv_sz(v, sz);
|
return xv_sz(v, sz);
|
||||||
} else if(v->kind == SCOPEITEM_SYMBOL) {
|
} else if(v->kind == VARTABLEENTRY_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 == SCOPEITEM_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 == VARTABLEENTRY_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;
|
||||||
@ -220,8 +216,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(ScopeItem *a) {
|
static int ud_empty(VarTableEntry *a) {
|
||||||
assert(a->kind == SCOPEITEM_VAR);
|
assert(a->kind == VARTABLEENTRY_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;
|
||||||
@ -255,8 +251,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 == SCOPEITEM_SYMBOL) {
|
} else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == VARTABLEENTRY_SYMBOL) {
|
||||||
ScopeItem *v = s->stmtDecl.thing;
|
VarTableEntry *v = s->stmtDecl.thing;
|
||||||
|
|
||||||
if(v->data.symbol.isExternal) {
|
if(v->data.symbol.isExternal) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
@ -291,8 +287,6 @@ 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);
|
||||||
@ -308,7 +302,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 == SCOPEITEM_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 == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
||||||
|
|
||||||
AST *e = s->stmtAssign.to;
|
AST *e = s->stmtAssign.to;
|
||||||
|
|
||||||
@ -325,7 +319,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 == SCOPEITEM_SYMBOL);
|
assert(e->exprCall.what->nodeKind == AST_EXPR_VAR && e->exprCall.what->exprVar.thing->kind == VARTABLEENTRY_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);
|
||||||
|
|
||||||
@ -341,17 +335,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 == SCOPEITEM_VAR);
|
assert(s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_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, %s\n", xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[1]));
|
printf("imul %s, %s\n", 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 == SCOPEITEM_VAR);
|
assert(s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||||
//assert(s->stmtAssign.what->exprVar.thing->data.var.color == COLOR_EDX);
|
assert(s->stmtAssign.what->exprVar.thing->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);
|
||||||
@ -380,51 +374,42 @@ 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 == SCOPEITEM_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_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 == VARTABLEENTRY_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_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 == SCOPEITEM_SYMBOL && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_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 == VARTABLEENTRY_SYMBOL && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_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 == SCOPEITEM_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 == VARTABLEENTRY_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(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(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)) {
|
||||||
|
|
||||||
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)) {
|
||||||
|
|
||||||
} else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST) {
|
printf("movzx %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to->exprCast.what));
|
||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
printf("mov %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to));
|
if(is_xop(s->stmtAssign.to) == XOP_MEM && type_size(s->stmtAssign.what->expression.type) != type_size(s->stmtAssign.to->expression.type)) {
|
||||||
|
printf("movzx %s, %s\n", xop_sz(cg->tlc, s->stmtAssign.what, 4), xop_sz(cg->tlc, s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type)));
|
||||||
|
} else {
|
||||||
|
printf("mov %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop_sz(cg->tlc, s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -473,8 +458,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 == SCOPEITEM_VAR);
|
assert(s->stmtReturn.val->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||||
//assert(s->stmtReturn.val->exprVar.thing->data.var.color == COLOR_EAX);
|
assert(s->stmtReturn.val->exprVar.thing->data.var.color == COLOR_EAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(a->chunk.stackReservation) {
|
if(a->chunk.stackReservation) {
|
||||||
@ -502,7 +487,7 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Spill2VarState {
|
struct Spill2VarState {
|
||||||
ScopeItem *target;
|
VarTableEntry *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;
|
||||||
@ -512,12 +497,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 == SCOPEITEM_VAR);
|
assert(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
if(a->stmtAssign.what->exprVar.thing == this->target) {
|
if(a->stmtAssign.what->exprVar.thing == this->target) {
|
||||||
|
|
||||||
ScopeItem *new = calloc(1, sizeof(*new));
|
VarTableEntry *new = calloc(1, sizeof(*new));
|
||||||
new->kind = SCOPEITEM_VAR;
|
new->kind = VARTABLEENTRY_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++);
|
||||||
|
|
||||||
@ -553,8 +538,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) {
|
||||||
|
|
||||||
ScopeItem *new = calloc(1, sizeof(*new));
|
VarTableEntry *new = calloc(1, sizeof(*new));
|
||||||
new->kind = SCOPEITEM_VAR;
|
new->kind = VARTABLEENTRY_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++);
|
||||||
|
|
||||||
@ -588,14 +573,14 @@ static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*struct PrecolorState {
|
struct PrecolorState {
|
||||||
ScopeItem *mustBeSpilled;
|
VarTableEntry *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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,9 +594,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 == SCOPEITEM_VAR);
|
assert(n->stmtReturn.val->nodeKind == AST_EXPR_VAR && n->stmtReturn.val->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
ScopeItem *vte = n->stmtReturn.val->exprVar.thing;
|
VarTableEntry *vte = n->stmtReturn.val->exprVar.thing;
|
||||||
|
|
||||||
const int requiredColor = COLOR_EAX;
|
const int requiredColor = COLOR_EAX;
|
||||||
|
|
||||||
@ -624,9 +609,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 == SCOPEITEM_VAR);
|
assert(n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
ScopeItem *vte = n->stmtAssign.what->exprVar.thing;
|
VarTableEntry *vte = n->stmtAssign.what->exprVar.thing;
|
||||||
|
|
||||||
const int requiredColor = COLOR_EAX;
|
const int requiredColor = COLOR_EAX;
|
||||||
|
|
||||||
@ -638,9 +623,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 == SCOPEITEM_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 == VARTABLEENTRY_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MUL) {
|
||||||
|
|
||||||
ScopeItem *vte = n->stmtAssign.what->exprVar.thing;
|
VarTableEntry *vte = n->stmtAssign.what->exprVar.thing;
|
||||||
|
|
||||||
const int requiredColor = COLOR_EAX;
|
const int requiredColor = COLOR_EAX;
|
||||||
|
|
||||||
@ -652,9 +637,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 == SCOPEITEM_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 == VARTABLEENTRY_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MULHI) {
|
||||||
|
|
||||||
ScopeItem *vte = n->stmtAssign.what->exprVar.thing;
|
VarTableEntry *vte = n->stmtAssign.what->exprVar.thing;
|
||||||
|
|
||||||
const int requiredColor = COLOR_EDX;
|
const int requiredColor = COLOR_EDX;
|
||||||
|
|
||||||
@ -667,26 +652,22 @@ 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 ScopeItem *Adjacency[2];
|
typedef VarTableEntry *Adjacency[2];
|
||||||
|
|
||||||
static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) {
|
static bool var_collision(AST *tlc, VarTableEntry *v1, VarTableEntry *v2) {
|
||||||
/* 1D intersection test */
|
/* 1D intersection test */
|
||||||
bool liveRangeIntersection = !ud_empty(v1) && !ud_empty(v2) && (
|
return !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 ScopeItem *get_precolor_spill_candidate(AST *tlc) {
|
static VarTableEntry *get_precolor_spill_candidate(AST *tlc) {
|
||||||
Adjacency *adjs = NULL;
|
Adjacency *adjs = NULL;
|
||||||
size_t adjCount = 0;
|
size_t adjCount = 0;
|
||||||
|
|
||||||
@ -718,7 +699,7 @@ static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) {
|
|||||||
adjs[a][1]->data.var.degree++;
|
adjs[a][1]->data.var.degree++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeItem *maxdeg = tlc->chunk.vars[0];
|
VarTableEntry *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) {
|
||||||
@ -729,13 +710,11 @@ static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) {
|
|||||||
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;
|
||||||
@ -753,191 +732,122 @@ static void callee_saved_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chun
|
|||||||
if(n == tlc) {
|
if(n == tlc) {
|
||||||
// Function entry
|
// Function entry
|
||||||
|
|
||||||
for(int i = 0; i < MAX_REGS_PER_CLASS; i++) {
|
ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
|
||||||
ScopeItem *vte = this->calleeUsers[i];
|
stk->nodeKind = AST_EXPR_STACK_POINTER;
|
||||||
|
stk->type = primitive_parse("u32");
|
||||||
if(!vte) {
|
|
||||||
continue;
|
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
||||||
}
|
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
||||||
|
offset->type = primitive_parse("u32");
|
||||||
ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
|
offset->val = tlc->chunk.stackReservation;
|
||||||
stk->nodeKind = AST_EXPR_STACK_POINTER;
|
|
||||||
stk->type = primitive_parse("u32");
|
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
||||||
|
sum->nodeKind = AST_EXPR_BINARY_OP;
|
||||||
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
sum->type = offset->type;
|
||||||
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
sum->operator = BINOP_ADD;
|
||||||
offset->type = primitive_parse("u32");
|
sum->operands[0] = (AST*) stk;
|
||||||
offset->val = this->calleeOffsets[i];
|
sum->operands[1] = (AST*) offset;
|
||||||
|
|
||||||
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
||||||
sum->nodeKind = AST_EXPR_BINARY_OP;
|
deref->nodeKind = AST_EXPR_UNARY_OP;
|
||||||
sum->type = offset->type;
|
deref->type = offset->type;
|
||||||
sum->operator = BINOP_ADD;
|
deref->operator = UNOP_DEREF;
|
||||||
sum->operands[0] = (AST*) stk;
|
deref->operand = (AST*) sum;
|
||||||
sum->operands[1] = (AST*) offset;
|
|
||||||
|
ASTExprVar *ev = calloc(1, sizeof(*ev));
|
||||||
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
ev->nodeKind = AST_EXPR_VAR;
|
||||||
deref->nodeKind = AST_EXPR_UNARY_OP;
|
ev->type = this->ebxuser->type;
|
||||||
deref->type = offset->type;
|
ev->thing = this->ebxuser;
|
||||||
deref->operator = UNOP_DEREF;
|
|
||||||
deref->operand = (AST*) sum;
|
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
|
||||||
|
assign->nodeKind = AST_STMT_ASSIGN;
|
||||||
ASTExprVar *ev = calloc(1, sizeof(*ev));
|
assign->what = (AST*) deref;
|
||||||
ev->nodeKind = AST_EXPR_VAR;
|
assign->to = (AST*) ev;
|
||||||
ev->type = vte->type;
|
|
||||||
ev->thing = vte;
|
assign->next = tlc->chunk.statementFirst;
|
||||||
|
tlc->chunk.statementFirst = (AST*) assign;
|
||||||
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
|
|
||||||
assign->nodeKind = AST_STMT_ASSIGN;
|
assert(tlc->chunk.statementLast != NULL);
|
||||||
assign->what = (AST*) deref;
|
|
||||||
assign->to = (AST*) ev;
|
tlc->chunk.stackReservation += 4;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
for(int i = 0; i < MAX_REGS_PER_CLASS; i++) {
|
ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
|
||||||
ScopeItem *vte = this->calleeUsers[i];
|
stk->nodeKind = AST_EXPR_STACK_POINTER;
|
||||||
|
stk->type = primitive_parse("u32");
|
||||||
if(!vte) {
|
|
||||||
continue;
|
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
||||||
}
|
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
||||||
|
offset->type = primitive_parse("u32");
|
||||||
ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
|
offset->val = tlc->chunk.stackReservation;
|
||||||
stk->nodeKind = AST_EXPR_STACK_POINTER;
|
|
||||||
stk->type = primitive_parse("u32");
|
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
||||||
|
sum->nodeKind = AST_EXPR_BINARY_OP;
|
||||||
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
sum->type = offset->type;
|
||||||
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
sum->operator = BINOP_ADD;
|
||||||
offset->type = primitive_parse("u32");
|
sum->operands[0] = (AST*) stk;
|
||||||
offset->val = this->calleeOffsets[i];
|
sum->operands[1] = (AST*) offset;
|
||||||
|
|
||||||
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
||||||
sum->nodeKind = AST_EXPR_BINARY_OP;
|
deref->nodeKind = AST_EXPR_UNARY_OP;
|
||||||
sum->type = offset->type;
|
deref->type = offset->type;
|
||||||
sum->operator = BINOP_ADD;
|
deref->operator = UNOP_DEREF;
|
||||||
sum->operands[0] = (AST*) stk;
|
deref->operand = (AST*) sum;
|
||||||
sum->operands[1] = (AST*) offset;
|
|
||||||
|
ASTExprVar *ev = calloc(1, sizeof(*ev));
|
||||||
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
ev->nodeKind = AST_EXPR_VAR;
|
||||||
deref->nodeKind = AST_EXPR_UNARY_OP;
|
ev->type = this->ebxuser->type;
|
||||||
deref->type = offset->type;
|
ev->thing = this->ebxuser;
|
||||||
deref->operator = UNOP_DEREF;
|
|
||||||
deref->operand = (AST*) sum;
|
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
|
||||||
|
assign->nodeKind = AST_STMT_ASSIGN;
|
||||||
ASTExprVar *ev = calloc(1, sizeof(*ev));
|
assign->what = (AST*) ev;
|
||||||
ev->nodeKind = AST_EXPR_VAR;
|
assign->to = (AST*) deref;
|
||||||
ev->type = vte->type;
|
assign->next = stmt;
|
||||||
ev->thing = vte;
|
|
||||||
|
if(stmtPrev) {
|
||||||
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
|
stmtPrev->statement.next = (AST*) assign;
|
||||||
assign->nodeKind = AST_STMT_ASSIGN;
|
} else {
|
||||||
assign->what = (AST*) ev;
|
tlc->chunk.statementFirst = (AST*) assign;
|
||||||
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) {
|
||||||
ScopeItem *ebxuser = NULL, *ediuser = NULL, *esiuser = NULL;
|
VarTableEntry *ebxuser = NULL;
|
||||||
|
|
||||||
for(size_t v = 0; v < tlc->chunk.varCount; v++) {
|
for(size_t v = 0; v < tlc->chunk.varCount; v++) {
|
||||||
if(is_reg_b(tlc->chunk.vars[v]->data.var.registerClass, tlc->chunk.vars[v]->data.var.color)) {
|
if(tlc->chunk.vars[v]->data.var.color == COLOR_EBX) {
|
||||||
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) {
|
||||||
state.calleeOffsets[nextUser] = nextUser * 4;
|
struct CalleeSavedState state;
|
||||||
state.calleeUsers[nextUser] = ebxuser;
|
state.targetTLC = tlc;
|
||||||
nextUser++;
|
state.ebxuser = ebxuser;
|
||||||
}
|
|
||||||
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) {
|
||||||
ScopeItem *const *a = A;
|
VarTableEntry *const *a = A;
|
||||||
ScopeItem *const *b = B;
|
VarTableEntry *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 == SCOPEITEM_SYMBOL);
|
assert(a->chunk.externs[e]->kind == VARTABLEENTRY_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);
|
||||||
@ -948,30 +858,27 @@ 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));
|
||||||
|
|
||||||
ScopeItem **vars = a->chunk.vars;
|
VarTableEntry **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;
|
||||||
|
|
||||||
ScopeItem *v1 = vars[v1i];
|
VarTableEntry *v1 = vars[v1i];
|
||||||
ScopeItem *v2 = vars[v2i];
|
VarTableEntry *v2 = vars[v2i];
|
||||||
|
|
||||||
if(var_collision(a, v1, v2)) {
|
if(var_collision(a, v1, v2)) {
|
||||||
ScopeItem *min = v1 < v2 ? v1 : v2;
|
VarTableEntry *min = v1 < v2 ? v1 : v2;
|
||||||
ScopeItem *max = v1 < v2 ? v2 : v1;
|
VarTableEntry *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) {
|
||||||
@ -995,7 +902,7 @@ cont:;
|
|||||||
|
|
||||||
qsort(vars, a->chunk.varCount, sizeof(*vars), comparator);
|
qsort(vars, a->chunk.varCount, sizeof(*vars), comparator);
|
||||||
|
|
||||||
int mustSpillRegisterClass = -1;
|
int lastColor = 0;
|
||||||
|
|
||||||
/* 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++) {
|
||||||
@ -1005,42 +912,18 @@ 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++) {
|
||||||
ScopeItem *me = NULL, *they = NULL;
|
if(adjs[a][0] == vars[v] && adjs[a][1]->data.var.color != -1 && adjs[a][1]->data.var.color == c) {
|
||||||
|
goto nextColor;
|
||||||
if(adjs[a][0] == vars[v]) {
|
} else if(adjs[a][1] == vars[v] && adjs[a][0]->data.var.color != -1 && adjs[a][0]->data.var.color == c) {
|
||||||
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:;
|
||||||
@ -1049,12 +932,12 @@ nextColor:;
|
|||||||
|
|
||||||
free(adjs);
|
free(adjs);
|
||||||
|
|
||||||
if(mustSpillRegisterClass != -1) {
|
if(lastColor >= 4) {
|
||||||
// Spill node with highest degree
|
// Spill node with highest degree
|
||||||
|
|
||||||
ScopeItem *chosen = NULL;
|
VarTableEntry *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 && vars[i]->data.var.registerClass == mustSpillRegisterClass) {
|
if(!vars[i]->data.var.precolored) {
|
||||||
chosen = vars[i];
|
chosen = vars[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
141
src/dstr.c
Normal file
141
src/dstr.c
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#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));
|
||||||
|
}
|
15
src/dstr.h
Normal file
15
src/dstr.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#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
|
@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
#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.
|
||||||
//
|
//
|
||||||
@ -15,11 +11,14 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
static ScopeItem *create_dumbtemp(AST *tlc, Type *itstype) {
|
#include"x86.h"
|
||||||
|
#include<string.h>
|
||||||
|
|
||||||
|
static VarTableEntry *create_dumbtemp(AST *tlc, Type *itstype) {
|
||||||
static size_t vidx = 0;
|
static size_t vidx = 0;
|
||||||
|
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||||
vte->kind = SCOPEITEM_VAR;
|
vte->kind = VARTABLEENTRY_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;
|
||||||
@ -37,7 +36,7 @@ static ScopeItem *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) {
|
||||||
ScopeItem *vte = create_dumbtemp(tlc, e->expression.type);
|
VarTableEntry *vte = create_dumbtemp(tlc, e->expression.type);
|
||||||
|
|
||||||
// Alter AST
|
// Alter AST
|
||||||
|
|
||||||
@ -119,12 +118,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 == SCOPEITEM_VAR && !strchr(REG_CLASSES[retval->exprVar.thing->data.var.registerClass].rsN[retval->exprVar.thing->data.var.color], 'a')))) {
|
if(retval && (!is_xop(retval) || retval->nodeKind == AST_EXPR_PRIMITIVE || (retval->nodeKind == AST_EXPR_VAR && retval->exprVar.thing->kind == VARTABLEENTRY_VAR && retval->exprVar.thing->data.var.color != COLOR_EAX))) {
|
||||||
|
|
||||||
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, REG_CLASS_16_32, 1);
|
vte_precolor(retval->exprVar.thing, COLOR_EAX);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +136,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, REG_CLASS_16_32, 1);
|
vte_precolor(s->stmtExpr.expr->exprVar.thing, COLOR_EAX);
|
||||||
|
|
||||||
// Purge this statement entirely, otherwise we'd have
|
// Purge this statement entirely, otherwise we'd have
|
||||||
// a = f(x);
|
// a = f(x);
|
||||||
@ -161,10 +160,9 @@ 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 != SCOPEITEM_VAR || !s->stmtAssign.what->exprVar.thing->data.var.precolored)) {
|
if(s->stmtAssign.to->nodeKind == AST_EXPR_CALL && (s->stmtAssign.what->nodeKind != AST_EXPR_VAR || s->stmtAssign.what->exprVar.thing->kind != VARTABLEENTRY_VAR)) {
|
||||||
|
|
||||||
ScopeItem *tmp = create_dumbtemp(tlc, s->stmtAssign.what->expression.type);
|
VarTableEntry *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;
|
||||||
@ -195,7 +193,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 == SCOPEITEM_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 == VARTABLEENTRY_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;
|
||||||
@ -274,7 +272,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, REG_CLASS_16_32, 7);
|
vte_precolor(hihalf->exprVar.thing, COLOR_EDX);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->stmtAssign.what = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[0]);
|
s->stmtAssign.what = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[0]);
|
||||||
@ -287,7 +285,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, REG_CLASS_16_32, 1);
|
vte_precolor(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, COLOR_EAX);
|
||||||
|
|
||||||
this->effective = 1;
|
this->effective = 1;
|
||||||
} else assert(because == NOT_AT_ALL_IT || because == GUCCI);
|
} else assert(because == NOT_AT_ALL_IT || because == GUCCI);
|
||||||
@ -320,9 +318,6 @@ 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,13 +328,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 == ud) {
|
if(n == tlc) {
|
||||||
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++) {
|
||||||
ScopeItem *vte = n->chunk.vars[i];
|
VarTableEntry *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;
|
||||||
@ -475,28 +470,12 @@ 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, tlc, pre_dumb_visitor, NULL);
|
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, 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++) {
|
||||||
@ -505,28 +484,23 @@ 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) {
|
||||||
stahp(0, 0, "TOO MANY DUMBS. TOO MANY DUMBS.");
|
puts("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));
|
||||||
|
|
||||||
@ -538,11 +512,6 @@ void dumben_go(AST* tlc) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ntc_get_int("pdbg")) {
|
fputs(ast_dump(tlc), stderr);
|
||||||
fprintf(stderr, "### DUMBED DOWN %lu ###\n", i++);
|
|
||||||
char *astdump = ast_dump(tlc);
|
|
||||||
fputs(astdump, stderr);
|
|
||||||
free(astdump);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,6 @@ 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';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,9 +354,6 @@ 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);
|
||||||
|
|
||||||
|
73
src/ntc.c
73
src/ntc.c
@ -1,7 +1,6 @@
|
|||||||
#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"
|
||||||
@ -10,45 +9,19 @@
|
|||||||
#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;
|
||||||
|
|
||||||
static char **includePaths;
|
const char* ntc_get_arg(const char *name) {
|
||||||
const char **ntc_get_import_paths() {
|
for(int i = 1; i < argc; i++) {
|
||||||
return (const char**) includePaths;
|
if(strstr(argv[i], name) == argv[i]) {
|
||||||
}
|
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_;
|
||||||
@ -59,26 +32,8 @@ 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);
|
||||||
@ -87,23 +42,23 @@ int main(int argc_, char **argv_) {
|
|||||||
|
|
||||||
free(tokens);
|
free(tokens);
|
||||||
|
|
||||||
if(ntc_get_int("pdbg")) {
|
fputs("; === Original AST ===\n", stderr);
|
||||||
char *astdump = ast_dump(chunk);
|
fputs(ast_dump(chunk), stderr);
|
||||||
fprintf(stderr, "### ORIGINAL ###\n%s\n", astdump);
|
fputc('\n', stderr);
|
||||||
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);
|
||||||
|
|
||||||
if(ntc_get_int("pdbg")) {
|
fputs("\n; === Spill ===\n", stderr);
|
||||||
char *astdump = ast_dump(chunk);
|
fputs(ast_dump(chunk), stderr);
|
||||||
fprintf(stderr, "### CG FAILURE ###\n%s\n", astdump);
|
fputc('\n', stderr);
|
||||||
free(astdump);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
#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);
|
||||||
|
|
||||||
intmax_t ntc_get_int(const char *name);
|
#endif
|
||||||
|
|
||||||
#endif
|
|
75
src/optims.c
Normal file
75
src/optims.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#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;
|
||||||
|
}*/
|
||||||
|
}
|
5
src/optims.h
Normal file
5
src/optims.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include"ast.h"
|
||||||
|
|
||||||
|
void optim_chunk(ASTChunk*);
|
375
src/parse.c
375
src/parse.c
@ -29,7 +29,7 @@ typedef struct {
|
|||||||
Token *tokens;
|
Token *tokens;
|
||||||
intmax_t i;
|
intmax_t i;
|
||||||
|
|
||||||
Scope *scope;
|
VarTable *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
|
||||||
Scope *loopScope;
|
VarTable *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;
|
||||||
long base = 10;
|
int 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,13 +120,10 @@ static ASTExprPrimitive *parse_prim(Parser *P) {
|
|||||||
str++; /* Go past the r. */
|
str++; /* Go past the r. */
|
||||||
}
|
}
|
||||||
|
|
||||||
long val;
|
if(!unstupid_strtol(str, NULL, base, &ret->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);
|
||||||
@ -135,8 +132,8 @@ static ASTExprPrimitive *parse_prim(Parser *P) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AST *exprvar(Parser *P, ScopeItem *v) {
|
static AST *exprvar(Parser *P, VarTableEntry *v) {
|
||||||
assert(v->kind != SCOPEITEM_TYPE);
|
assert(v->kind != VARTABLEENTRY_TYPE);
|
||||||
|
|
||||||
AST *a = alloc_node(P, sizeof(ASTExprVar));
|
AST *a = alloc_node(P, sizeof(ASTExprVar));
|
||||||
|
|
||||||
@ -148,7 +145,7 @@ static AST *exprvar(Parser *P, ScopeItem *v) {
|
|||||||
// XXX: O(n)!!!!!!!!!
|
// XXX: O(n)!!!!!!!!!
|
||||||
|
|
||||||
int inloop = 0;
|
int inloop = 0;
|
||||||
for(Scope *vt = v->owner; vt; vt = vt->parent) {
|
for(VarTable *vt = v->owner; vt; vt = vt->parent) {
|
||||||
if(vt->parent == P->loopScope) {
|
if(vt->parent == P->loopScope) {
|
||||||
inloop = 1;
|
inloop = 1;
|
||||||
break;
|
break;
|
||||||
@ -177,10 +174,10 @@ static AST *exprvar(Parser *P, ScopeItem *v) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTChunk *nct_parse_chunk(Parser*, int, int, Scope*, Type *ft);
|
ASTChunk *nct_parse_chunk(Parser*, int, int, VarTable*, Type *ft);
|
||||||
Type *nct_parse_typename(Parser *P);
|
Type *nct_parse_typename(Parser *P);
|
||||||
static bool parse_parametrization(Parser *P);
|
static bool parse_parametrization(Parser *P, Parametrizations *parametrizations);
|
||||||
static char *parametrize_function_name(Type *t, const char *original, Scope *scope);
|
static char *parametrize_function_name(Type *t, const char *original, Parametrization *types, Parametrization *ints);
|
||||||
|
|
||||||
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)) {
|
||||||
@ -233,7 +230,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
|
|
||||||
P->isInFunction++;
|
P->isInFunction++;
|
||||||
|
|
||||||
e->chunk = (AST*) nct_parse_chunk(P, 1, 0, scope_new(P->scope), ft);
|
e->chunk = (AST*) nct_parse_chunk(P, 1, 0, vartable_new(P->scope), ft);
|
||||||
e->chunk->chunk.functionType = ft;
|
e->chunk->chunk.functionType = ft;
|
||||||
|
|
||||||
P->isInFunction--;
|
P->isInFunction--;
|
||||||
@ -241,7 +238,6 @@ 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;
|
||||||
@ -276,25 +272,11 @@ 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);
|
||||||
|
|
||||||
ScopeItem *vte = scope_find(P->scope, varname.content);
|
VarTableEntry *vte = vartable_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);
|
||||||
@ -431,20 +413,18 @@ 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 = {};
|
||||||
P->scope = scope_new(P->scope);
|
if(parse_parametrization(P, ¶metrizations)) {
|
||||||
|
|
||||||
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 == SCOPEITEM_SYMBOL);
|
assert(ret->exprVar.thing->kind == VARTABLEENTRY_SYMBOL);
|
||||||
|
|
||||||
char *cname = parametrize_function_name(ret->expression.type, ret->exprVar.thing->data.symbol.name, P->scope);
|
char *cname = parametrize_function_name(ret->expression.type, ret->exprVar.thing->data.symbol.name, parametrizations.typeParams, parametrizations.intParams);
|
||||||
|
|
||||||
ScopeItem *cvte = scope_find(P->scope, cname);
|
VarTableEntry *cvte = vartable_get(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);
|
||||||
@ -477,12 +457,11 @@ 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("u32");
|
scale->type = primitive_parse("u16");
|
||||||
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];
|
||||||
@ -500,9 +479,6 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
|
|
||||||
ret = (AST*) unop;
|
ret = (AST*) unop;
|
||||||
}
|
}
|
||||||
|
|
||||||
P->scope = P->scope->parent;
|
|
||||||
|
|
||||||
} else abort();
|
} else abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,23 +615,26 @@ 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) {
|
static bool parse_parametrization(Parser *P, Parametrizations *parametrizations) {
|
||||||
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);
|
||||||
|
|
||||||
@ -663,16 +642,7 @@ static bool parse_parametrization(Parser *P) {
|
|||||||
goto backtrack;
|
goto backtrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
par->param = n;
|
||||||
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);
|
||||||
|
|
||||||
@ -680,26 +650,35 @@ static bool parse_parametrization(Parser *P) {
|
|||||||
goto backtrack;
|
goto backtrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
par->param = t;
|
||||||
vte->kind = SCOPEITEM_TYPE;
|
|
||||||
vte->type = t;
|
|
||||||
vte->data.type.ptr = t;
|
|
||||||
|
|
||||||
char buf[64];
|
|
||||||
snprintf(buf, sizeof(buf), "%li%s", idx, "t");
|
|
||||||
|
|
||||||
scope_set(P->scope, buf, vte);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idx++;
|
if(!par->param) {
|
||||||
|
goto backtrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!head) {
|
||||||
|
head = par;
|
||||||
|
last = head;
|
||||||
|
|
||||||
|
if(integerMode) {
|
||||||
|
parametrizations->intParams = head;
|
||||||
|
} else {
|
||||||
|
parametrizations->typeParams = head;
|
||||||
|
}
|
||||||
|
} else if(last) {
|
||||||
|
last->next = par;
|
||||||
|
last = par;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@ -719,7 +698,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 = scope_new(P->scope);
|
P->scope = vartable_new(P->scope);
|
||||||
|
|
||||||
parse_genericization(P);
|
parse_genericization(P);
|
||||||
}
|
}
|
||||||
@ -732,8 +711,8 @@ Type *nct_parse_typename(Parser *P) {
|
|||||||
|
|
||||||
Token id = expect(P, TOKEN_IDENTIFIER);
|
Token id = expect(P, TOKEN_IDENTIFIER);
|
||||||
|
|
||||||
ScopeItem *potentialVTE = scope_find(P->scope, id.content);
|
VarTableEntry *potentialVTE = vartable_find(P->scope, id.content);
|
||||||
if(potentialVTE && potentialVTE->kind == SCOPEITEM_TYPE) {
|
if(potentialVTE && potentialVTE->kind == VARTABLEENTRY_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);
|
||||||
@ -797,17 +776,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 = -1;
|
arr->length = 0;
|
||||||
} 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;
|
||||||
|
|
||||||
ScopeItem *vte = scope_find(P->scope, what);
|
VarTableEntry *vte = vartable_find(P->scope, what);
|
||||||
|
|
||||||
if(!vte) {
|
if(!vte) {
|
||||||
goto backtrack;
|
goto backtrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(vte->kind != SCOPEITEM_CEXPR) {
|
if(vte->kind != VARTABLEENTRY_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,12 +815,11 @@ Type *nct_parse_typename(Parser *P) {
|
|||||||
|
|
||||||
P->i--;
|
P->i--;
|
||||||
|
|
||||||
P->scope = scope_new(P->scope);
|
Parametrizations parametrizations = {};
|
||||||
|
assert(parse_parametrization(P, ¶metrizations));
|
||||||
|
|
||||||
assert(parse_parametrization(P));
|
Parametrizations renames = {};
|
||||||
ret = type_parametrize(ret, P->scope);
|
ret = type_parametrize(ret, ¶metrizations, &renames);
|
||||||
|
|
||||||
P->scope = P->scope->parent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -879,8 +857,8 @@ static AST *parse_declaration(Parser *P) {
|
|||||||
|
|
||||||
Token name = expect(P, TOKEN_IDENTIFIER);
|
Token name = expect(P, TOKEN_IDENTIFIER);
|
||||||
|
|
||||||
ScopeItem *entry;
|
VarTableEntry *entry;
|
||||||
if(peek(P, 0).type == TOKEN_COLON && (entry = scope_get(P->scope, name.content))) {
|
if(peek(P, 0).type == TOKEN_COLON && (entry = vartable_get(P->scope, name.content))) {
|
||||||
/* Forward declared. */
|
/* Forward declared. */
|
||||||
} else {
|
} else {
|
||||||
entry = calloc(sizeof(*entry), 1);
|
entry = calloc(sizeof(*entry), 1);
|
||||||
@ -895,7 +873,7 @@ static AST *parse_declaration(Parser *P) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->kind = SCOPEITEM_VAR;
|
entry->kind = VARTABLEENTRY_VAR;
|
||||||
entry->data.var.priority = 1;
|
entry->data.var.priority = 1;
|
||||||
entry->data.var.color = -1;
|
entry->data.var.color = -1;
|
||||||
|
|
||||||
@ -924,7 +902,7 @@ static AST *parse_declaration(Parser *P) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->kind = SCOPEITEM_SYMBOL;
|
entry->kind = VARTABLEENTRY_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;
|
||||||
@ -940,13 +918,12 @@ 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 = SCOPEITEM_SYMBOL;
|
entry->kind = VARTABLEENTRY_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;
|
||||||
@ -957,7 +934,7 @@ static AST *parse_declaration(Parser *P) {
|
|||||||
ret = (AST*) decl;
|
ret = (AST*) decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
scope_set(P->scope, name.content, entry);
|
vartable_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
|
||||||
@ -984,42 +961,24 @@ static char *plus_underscore(char *s, char *ts) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *parametrize_function_name(Type *t, const char *original, Scope *scope) {
|
static char *parametrize_function_name(Type *t, const char *original, Parametrization *types, Parametrization *ints) {
|
||||||
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)] = '_';
|
||||||
|
|
||||||
for(int i = 0;; i++) {
|
while(types) {
|
||||||
char vtename[64];
|
s = plus_underscore(s, type_to_string(types->param));
|
||||||
snprintf(vtename, sizeof(vtename), "%it", i);
|
|
||||||
|
|
||||||
// scope_get, NOT SCOPE_FIND!
|
types = types->next;
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0;; i++) {
|
while(ints) {
|
||||||
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", vte->data.cexpr.concrete->exprPrim.val);
|
snprintf(numstr, sizeof(numstr), "%i", ((AST*) ints->param)->exprPrim.val);
|
||||||
|
|
||||||
s = plus_underscore(s, numstr);
|
s = plus_underscore(s, numstr);
|
||||||
|
|
||||||
|
ints = ints->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove last underscore
|
// Remove last underscore
|
||||||
@ -1028,7 +987,7 @@ static char *parametrize_function_name(Type *t, const char *original, Scope *sco
|
|||||||
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) {
|
||||||
@ -1037,10 +996,10 @@ static char *parametrize_function_name(Type *t, const char *original, Scope *sco
|
|||||||
|
|
||||||
assert(!!ct == !!gt);
|
assert(!!ct == !!gt);
|
||||||
|
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||||
vte->kind = SCOPEITEM_TYPE;
|
vte->kind = VARTABLEENTRY_TYPE;
|
||||||
vte->data.type.ptr = ct;
|
vte->data.type.ptr = ct;
|
||||||
scope_set(P->scope, gt->generic.paramName, vte);
|
vartable_set(P->scope, gt->generic.paramName, vte);
|
||||||
|
|
||||||
c = c->next;
|
c = c->next;
|
||||||
g = g->next;
|
g = g->next;
|
||||||
@ -1055,18 +1014,18 @@ static char *parametrize_function_name(Type *t, const char *original, Scope *sco
|
|||||||
|
|
||||||
assert(!!node == !!name);
|
assert(!!node == !!name);
|
||||||
|
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||||
vte->kind = SCOPEITEM_CEXPR;
|
vte->kind = VARTABLEENTRY_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;
|
||||||
scope_set(P->scope, name, vte);
|
vartable_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)) {
|
||||||
@ -1178,7 +1137,6 @@ 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));
|
||||||
@ -1234,7 +1192,7 @@ void nct_parse_statement(Parser *P) {
|
|||||||
|
|
||||||
Token funcname = expect(P, TOKEN_IDENTIFIER);
|
Token funcname = expect(P, TOKEN_IDENTIFIER);
|
||||||
|
|
||||||
ScopeItem *func = scope_find(P->scope, funcname.content);
|
VarTableEntry *func = vartable_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);
|
||||||
@ -1242,68 +1200,47 @@ void nct_parse_statement(Parser *P) {
|
|||||||
|
|
||||||
assert(type_is_generic(func->type));
|
assert(type_is_generic(func->type));
|
||||||
|
|
||||||
Scope *oldScope = P->scope;
|
Parametrizations parametrizations = {};
|
||||||
P->scope = scope_new(oldScope);
|
assert(parse_parametrization(P, ¶metrizations));
|
||||||
|
|
||||||
assert(parse_parametrization(P));
|
P->scope = vartable_new(P->scope);
|
||||||
|
|
||||||
P->scope->parent = func->data.symbol.genfunc.scope;
|
Parametrizations renames = {};
|
||||||
|
Type *parametrizedFuncType = type_parametrize(func->type, ¶metrizations, &renames);
|
||||||
|
|
||||||
Type *parametrizedFuncType = type_parametrize(func->type, P->scope);
|
add_parametrizations_to_scope(P, ¶metrizations, &renames);
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
expect(P, TOKEN_SQUAREN_L);
|
size_t depth = 0;
|
||||||
intmax_t paramIdx = 0;
|
|
||||||
bool integerMode = false;
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if(maybe(P, TOKEN_SQUAREN_R)) {
|
TokenKind tk = get(P).type;
|
||||||
break;
|
if(tk == TOKEN_SQUAREN_L) {
|
||||||
}
|
depth++;
|
||||||
|
} else if(tk == TOKEN_SQUAREN_R) {
|
||||||
char vtename[64];
|
if(--depth == 0) {
|
||||||
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;
|
|
||||||
|
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
P->scope = P->scope->parent;
|
||||||
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, P->scope);
|
vte->data.symbol.name = parametrize_function_name(func->type, func->data.symbol.name, parametrizations.typeParams, parametrizations.intParams);
|
||||||
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;
|
||||||
@ -1320,13 +1257,6 @@ 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);
|
||||||
@ -1385,21 +1315,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;
|
||||||
|
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||||
vte->kind = SCOPEITEM_TYPE;
|
vte->kind = VARTABLEENTRY_TYPE;
|
||||||
vte->data.type.ptr = tg;
|
vte->data.type.ptr = tg;
|
||||||
|
|
||||||
scope_set(P->scope, strdup(tg->generic.paramName), vte);
|
vartable_set(P->scope, strdup(tg->generic.paramName), vte);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||||
vte->type = primitive_parse("u32");
|
vte->type = primitive_parse("u32");
|
||||||
vte->kind = SCOPEITEM_CEXPR;
|
vte->kind = VARTABLEENTRY_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;
|
||||||
|
|
||||||
scope_set(P->scope, strdup(vte->data.var.name), vte);
|
vartable_set(P->scope, strdup(vte->data.var.name), vte);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1425,7 +1355,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 = scope_new(P->scope);
|
P->scope = vartable_new(P->scope);
|
||||||
|
|
||||||
Token name = expect(P, TOKEN_IDENTIFIER);
|
Token name = expect(P, TOKEN_IDENTIFIER);
|
||||||
|
|
||||||
@ -1502,22 +1432,12 @@ static void skim_chunk(Parser *P, int isTopLevel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
stomp:;
|
stomp:;
|
||||||
} else if(k == TOKEN_COLON || k == TOKEN_EXTERN) {
|
} else if(k == TOKEN_COLON) {
|
||||||
/* Move back to beginning of declaration. */
|
/* Move back to beginning of declaration. */
|
||||||
if(k == TOKEN_COLON) {
|
do {
|
||||||
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();
|
||||||
@ -1528,11 +1448,11 @@ static void skim_chunk(Parser *P, int isTopLevel) {
|
|||||||
|
|
||||||
Type *tr = nct_parse_record_definition(P);
|
Type *tr = nct_parse_record_definition(P);
|
||||||
|
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||||
vte->kind = SCOPEITEM_TYPE;
|
vte->kind = VARTABLEENTRY_TYPE;
|
||||||
vte->data.type.ptr = tr;
|
vte->data.type.ptr = tr;
|
||||||
|
|
||||||
scope_set(P->scope, tr->record.name, vte);
|
vartable_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);
|
||||||
@ -1549,42 +1469,30 @@ 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);
|
||||||
f = fopen(path2, "rb");
|
path = path2;
|
||||||
|
|
||||||
free(path2);
|
|
||||||
|
|
||||||
if(f) {
|
|
||||||
// Importee found
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!f) {
|
FILE *f = fopen(path, "rb");
|
||||||
stahp_token(&P->tokens[P->i], "Module %s not found", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(path);
|
Parser subp = {.tokens = nct_lex(f), .scope = vartable_new(NULL), .externalify = 1};
|
||||||
|
|
||||||
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++) {
|
||||||
ScopeItem *vte = subp.scope->data[i];
|
VarTableEntry *vte = subp.scope->data[i];
|
||||||
if(vte->kind == SCOPEITEM_SYMBOL && vte->data.symbol.isExternal) {
|
if(vte->kind == VARTABLEENTRY_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;
|
||||||
scope_merge(subp.scope);
|
vartable_merge(subp.scope);
|
||||||
|
|
||||||
// free(subp.tokens); DO THIS CANNOT
|
free(subp.tokens);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1594,7 +1502,7 @@ static void skim_chunk(Parser *P, int isTopLevel) {
|
|||||||
P->skimMode--;
|
P->skimMode--;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *toplevelParent, Type *ft) {
|
ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable *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;
|
||||||
@ -1605,9 +1513,9 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *t
|
|||||||
AST *oldChunk = (AST*) P->currentChunk;
|
AST *oldChunk = (AST*) P->currentChunk;
|
||||||
P->currentChunk = &ret->chunk;
|
P->currentChunk = &ret->chunk;
|
||||||
|
|
||||||
Scope *oldScope = P->scope;
|
VarTable *oldScope = P->scope;
|
||||||
|
|
||||||
P->scope = isTopLevel ? toplevelParent : scope_new(oldScope);
|
P->scope = isTopLevel ? toplevelParent : vartable_new(oldScope);
|
||||||
|
|
||||||
ASTChunk *oldTopLevel = P->topLevel;
|
ASTChunk *oldTopLevel = P->topLevel;
|
||||||
if(isTopLevel) {
|
if(isTopLevel) {
|
||||||
@ -1618,17 +1526,16 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *t
|
|||||||
|
|
||||||
/* Arguments */
|
/* Arguments */
|
||||||
if(ft && isTopLevel) {
|
if(ft && isTopLevel) {
|
||||||
ScopeItem **vtes = alloca(sizeof(*vtes) * ft->function.argCount);
|
VarTableEntry **vtes = alloca(sizeof(*vtes) * ft->function.argCount);
|
||||||
|
|
||||||
// First arguments in a function TLC is the arguments
|
for(int i = ft->function.argCount - 1; i >= 0; i--) {
|
||||||
for(int i = 0; i < ft->function.argCount; i++) {
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||||
ScopeItem *vte = calloc(1, sizeof(*vte));
|
vte->kind = VARTABLEENTRY_VAR;
|
||||||
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;
|
||||||
|
|
||||||
scope_set(toplevelParent, vte->data.var.name, vte);
|
vartable_set(toplevelParent, vte->data.var.name, vte);
|
||||||
|
|
||||||
vtes[i] = vte;
|
vtes[i] = vte;
|
||||||
}
|
}
|
||||||
@ -1640,23 +1547,21 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *t
|
|||||||
nct_parse_statement(P);
|
nct_parse_statement(P);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all variables used in this chunk into the TLC's variable list
|
size_t nonSymbols = 0;
|
||||||
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 == SCOPEITEM_VAR) {
|
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
|
||||||
varsToAdd++;
|
nonSymbols++;
|
||||||
|
|
||||||
|
if(varPrioritize) {
|
||||||
|
P->scope->data[i]->data.var.priority++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (P->topLevel->varCount + nonSymbols));
|
||||||
P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (P->topLevel->varCount + varsToAdd));
|
for(size_t i = 0; i < P->scope->count; i++) {
|
||||||
|
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
|
||||||
// This makes sure function arguments stay first in the array
|
P->topLevel->vars[P->topLevel->varCount++] = P->scope->data[i];
|
||||||
memmove(P->topLevel->vars + varsToAdd, P->topLevel->vars, sizeof(*P->topLevel->vars) * P->topLevel->varCount);
|
//P->scope->data[i]->owner = P->topLevel; // not sure why this line ever existed, it makes no sense
|
||||||
|
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1675,5 +1580,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, scope_new(NULL), NULL);
|
return (AST*) nct_parse_chunk(&P, 1, 0, vartable_new(NULL), NULL);
|
||||||
}
|
}
|
||||||
|
79
src/types.c
79
src/types.c
@ -6,7 +6,6 @@
|
|||||||
#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"
|
||||||
|
|
||||||
@ -235,12 +234,35 @@ bool type_is_generic(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *type_parametrize(Type *t, Scope *scope) {
|
static void *parametrization_get_by_index(Parametrization *list, size_t idx) {
|
||||||
|
for(size_t i = 0; list && i < idx; i++) {
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
return list ? list->param : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parametrization_set_by_index(Parametrization **list, size_t idx, void *param) {
|
||||||
|
if(*list == NULL) {
|
||||||
|
*list = calloc(1, sizeof(Parametrization));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 1; i <= idx; i++) {
|
||||||
|
if((*list)->next == NULL) {
|
||||||
|
(*list)->next = calloc(1, sizeof(Parametrization));
|
||||||
|
}
|
||||||
|
|
||||||
|
list = &(*list)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*list)->param = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *type_parametrize(Type *t, Parametrizations *parametrizations, Parametrizations *renames) {
|
||||||
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], scope);
|
t->record.fieldTypes[f] = type_parametrize(t->record.fieldTypes[f], parametrizations, renames);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!type_is_generic(t)) {
|
if(!type_is_generic(t)) {
|
||||||
@ -257,48 +279,51 @@ Type *type_parametrize(Type *t, Scope *scope) {
|
|||||||
} 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, scope);
|
t->function.ret = type_parametrize(t->function.ret, parametrizations, renames);
|
||||||
|
|
||||||
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], scope);
|
t->function.args[i] = type_parametrize(t->function.args[i], parametrizations, renames);
|
||||||
}
|
}
|
||||||
} else if(t->type == TYPE_TYPE_GENERIC) {
|
} else if(t->type == TYPE_TYPE_GENERIC) {
|
||||||
ScopeItem *vte = scope_find_int(scope, t->generic.paramIdx, "t");
|
Type *newt = parametrization_get_by_index(parametrizations->typeParams, t->generic.paramIdx);
|
||||||
|
|
||||||
if(vte) {
|
if(renames) {
|
||||||
assert(vte->kind == SCOPEITEM_TYPE);
|
parametrization_set_by_index(&renames->typeParams, t->generic.paramIdx, t);
|
||||||
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, scope);
|
t->pointer.of = type_parametrize(t->pointer.of, parametrizations, renames);
|
||||||
} 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, scope);
|
t->array.of = type_parametrize(t->array.of, parametrizations, renames);
|
||||||
|
|
||||||
if(t->array.lengthIsGeneric) {
|
if(t->array.lengthIsGeneric) {
|
||||||
ScopeItem *vte = scope_find_int(scope, t->array.lengthGenericParamIdx, "i");
|
AST *n = parametrization_get_by_index(parametrizations->intParams, t->array.lengthGenericParamIdx);
|
||||||
|
|
||||||
if(vte) {
|
if(n) {
|
||||||
assert(vte->kind == SCOPEITEM_CEXPR);
|
while(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR && n->exprVar.thing->data.cexpr.concrete) {
|
||||||
|
n = n->exprVar.thing->data.cexpr.concrete;
|
||||||
|
}
|
||||||
|
|
||||||
AST *n = vte->data.cexpr.concrete;
|
if(n->nodeKind == AST_EXPR_PRIMITIVE) {
|
||||||
|
t->array.length = n->exprPrim.val;
|
||||||
if(n) {
|
t->array.lengthIsGeneric = false;
|
||||||
if(n->nodeKind == AST_EXPR_PRIMITIVE) {
|
} else if(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR) {
|
||||||
t->array.length = n->exprPrim.val;
|
t->array.lengthGenericParamIdx = n->exprVar.thing->data.cexpr.paramIdx;
|
||||||
t->array.lengthIsGeneric = false;
|
t->array.lengthGenericParamName = n->exprVar.thing->data.cexpr.paramName;
|
||||||
} else if(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == SCOPEITEM_CEXPR) {
|
t->array.lengthIsGeneric = true;
|
||||||
t->array.lengthGenericParamIdx = n->exprVar.thing->data.cexpr.paramIdx;
|
} else {
|
||||||
t->array.lengthGenericParamName = n->exprVar.thing->data.cexpr.paramName;
|
stahp_node(n, "Invalid parametrization expression.");
|
||||||
t->array.lengthIsGeneric = true;
|
|
||||||
} else {
|
|
||||||
stahp_node(n, "Invalid parametrization expression.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parametrization_set_by_index(&renames->intParams, t->array.lengthGenericParamIdx, t->array.lengthGenericParamName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
src/types.h
14
src/types.h
@ -102,8 +102,18 @@ int type_is_number(Type *t);
|
|||||||
|
|
||||||
char *type_to_string(Type*);
|
char *type_to_string(Type*);
|
||||||
|
|
||||||
struct Scope;
|
typedef struct Parametrization {
|
||||||
Type *type_parametrize(Type *target, struct Scope *scope);
|
void *param;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#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));
|
||||||
@ -31,8 +30,8 @@ void reachingdefs_set(struct ReachingDefs *this, union AST *def) {
|
|||||||
this->excludeParent = 1;
|
this->excludeParent = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope *scope_new(Scope *parent) {
|
VarTable *vartable_new(VarTable *parent) {
|
||||||
Scope *ret = calloc(1, sizeof(*ret));
|
VarTable *ret = calloc(1, sizeof(*ret));
|
||||||
ret->parent = parent;
|
ret->parent = parent;
|
||||||
ret->count = 0;
|
ret->count = 0;
|
||||||
ret->names = NULL;
|
ret->names = NULL;
|
||||||
@ -41,17 +40,17 @@ Scope *scope_new(Scope *parent) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeItem *scope_get(Scope *this, const char *name) {
|
VarTableEntry *vartable_get(VarTable *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;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeItem *scope_find(Scope *this, const char *name) {
|
VarTableEntry *vartable_find(VarTable *this, const char *name) {
|
||||||
Scope *tbl = this;
|
VarTable *tbl = this;
|
||||||
while(tbl) {
|
while(tbl) {
|
||||||
ScopeItem *entry = scope_get(tbl, name);
|
VarTableEntry *entry = vartable_get(tbl, name);
|
||||||
if(entry) {
|
if(entry) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@ -60,28 +59,43 @@ ScopeItem *scope_find(Scope *this, const char *name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeItem *scope_set(Scope *this, const char *name, ScopeItem *e) {
|
VarTableEntry *vartable_set(VarTable *this, const char *name, VarTableEntry *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 == SCOPEITEM_VAR) e->data.var.name = name;
|
if(e->kind == VARTABLEENTRY_VAR) e->data.var.name = name;
|
||||||
e->owner = this;
|
e->owner = this;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeItem *scope_find_int(Scope *scope, intmax_t val, const char *suffix) {
|
/*void vartable_new_reachingdefs_for_all_vars(VarTable *this) {
|
||||||
char buf[64];
|
for(size_t i = 0; i < this->count; i++) {
|
||||||
snprintf(buf, sizeof(buf), "%li%s", val, suffix ? suffix : "");
|
if(this->data[i]->kind == VARTABLEENTRY_VAR) {
|
||||||
|
this->data[i]->data.var.reachingDefs = reachingdefs_push(this->data[i]->data.var.reachingDefs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return scope_find(scope, buf);
|
if(this->parent) {
|
||||||
|
vartable_new_reachingdefs_for_all_vars(this->parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope *scope_merge(Scope *child) {
|
void vartable_coalesce_reachingdefs_for_all_vars(VarTable *this) {
|
||||||
Scope *parent = child->parent;
|
for(size_t i = 0; i < this->count; i++) {
|
||||||
|
if(this->data[i]->kind == VARTABLEENTRY_VAR) {
|
||||||
|
this->data[i]->data.var.reachingDefs = reachingdefs_coalesce(this->data[i]->data.var.reachingDefs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this->parent) {
|
||||||
|
vartable_coalesce_reachingdefs_for_all_vars(this->parent);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
VarTable *vartable_merge(VarTable *child) {
|
||||||
|
VarTable *parent = child->parent;
|
||||||
|
|
||||||
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));
|
||||||
@ -95,18 +109,17 @@ Scope *scope_merge(Scope *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(ScopeItem *vte, int class, int color) {
|
void vte_precolor(VarTableEntry *vte, int color) {
|
||||||
assert(vte->kind == SCOPEITEM_VAR && "vte must be var");
|
assert(vte->kind == VARTABLEENTRY_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;
|
||||||
}
|
}
|
||||||
|
131
src/vartable.h
131
src/vartable.h
@ -8,8 +8,8 @@ struct Token;
|
|||||||
union AST;
|
union AST;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SCOPEITEM_SYMBOL, SCOPEITEM_VAR, SCOPEITEM_TYPE, SCOPEITEM_CEXPR
|
VARTABLEENTRY_SYMBOL, VARTABLEENTRY_VAR, VARTABLEENTRY_TYPE, VARTABLEENTRY_CEXPR
|
||||||
} ScopeItemKind;
|
} VarTableEntryKind;
|
||||||
|
|
||||||
union AST;
|
union AST;
|
||||||
typedef struct UseDef {
|
typedef struct UseDef {
|
||||||
@ -31,81 +31,82 @@ 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 Scope;
|
struct VarTable;
|
||||||
typedef struct ScopeItem {
|
typedef struct VarTableEntry {
|
||||||
Type *type;
|
Type *type;
|
||||||
|
|
||||||
struct Scope *owner;
|
struct VarTable *owner;
|
||||||
|
|
||||||
ScopeItemKind kind;
|
VarTableEntryKind kind;
|
||||||
union {
|
struct {
|
||||||
struct {
|
union {
|
||||||
char isLocal;
|
|
||||||
char isExternal;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct Scope *scope;
|
char isLocal;
|
||||||
struct Token *rangeTokens;
|
char isExternal;
|
||||||
size_t startTokI;
|
const char *name;
|
||||||
size_t endTokI;
|
|
||||||
} genfunc;
|
struct {
|
||||||
} symbol;
|
struct Token *rangeTokens;
|
||||||
struct {
|
size_t startTokI;
|
||||||
// For debugging
|
size_t endTokI;
|
||||||
|
} genfunc;
|
||||||
const char *name;
|
} symbol;
|
||||||
|
struct {
|
||||||
// Register allocation
|
// For debugging
|
||||||
|
|
||||||
// vars in loops have higher priority
|
const char *name;
|
||||||
// a more advanced approach would be to use weights for different colors (e.g. multipliers "should" be in eax)
|
|
||||||
uint8_t priority;
|
// Register allocation
|
||||||
int16_t color, degree;
|
|
||||||
bool precolored;
|
// vars in loops have higher priority
|
||||||
int registerClass;
|
// a more advanced approach would be to use weights for different colors (e.g. multipliers "should" be in eax)
|
||||||
|
uint8_t priority;
|
||||||
// Used during parsing
|
int16_t color, degree;
|
||||||
|
bool precolored;
|
||||||
ReachingDefs *reachingDefs;
|
|
||||||
|
// Used during parsing
|
||||||
// Optimizations
|
|
||||||
|
ReachingDefs *reachingDefs;
|
||||||
UseDef *usedefFirst;
|
|
||||||
UseDef *usedefLast;
|
// Optimizations
|
||||||
} var;
|
|
||||||
struct {
|
UseDef *usedefFirst;
|
||||||
Type *ptr;
|
UseDef *usedefLast;
|
||||||
} type;
|
} var;
|
||||||
struct {
|
struct {
|
||||||
// cexpr is used for expression parametization as opposed to type parametrization
|
Type *ptr;
|
||||||
// I don't like the idea of having a special ScopeItem kind for these, but all other places were worse
|
} type;
|
||||||
const char *paramName;
|
struct {
|
||||||
size_t paramIdx;
|
// cexpr is used for expression parametization as opposed to type parametrization
|
||||||
|
// I don't like the idea of having a special VarTableEntry kind for these, but all other places were worse
|
||||||
// If the cexpr has been parametrized (as opposed to just being a symbol), this field will be non-NULL
|
const char *paramName;
|
||||||
union AST *concrete;
|
size_t paramIdx;
|
||||||
} 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;
|
||||||
} ScopeItem;
|
} VarTableEntry;
|
||||||
|
|
||||||
typedef struct Scope {
|
typedef struct VarTable {
|
||||||
struct Scope *parent;
|
struct VarTable *parent;
|
||||||
|
|
||||||
size_t count;
|
size_t count;
|
||||||
const char **names;
|
const char **names;
|
||||||
ScopeItem **data;
|
VarTableEntry **data;
|
||||||
} Scope;
|
} VarTable;
|
||||||
|
|
||||||
Scope *scope_new(Scope*);
|
VarTable *vartable_new(VarTable*);
|
||||||
ScopeItem *scope_get(Scope*, const char*);
|
VarTableEntry *vartable_get(VarTable*, const char*);
|
||||||
ScopeItem *scope_find(Scope*, const char*);
|
VarTableEntry *vartable_find(VarTable*, const char*);
|
||||||
ScopeItem *scope_set(Scope*, const char*, ScopeItem*);
|
VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*);
|
||||||
|
|
||||||
ScopeItem *scope_find_int(Scope*, intmax_t, const char*);
|
VarTable *vartable_merge(VarTable *child);
|
||||||
|
|
||||||
Scope *scope_merge(Scope *child);
|
//void vartable_new_reachingdefs_for_all_vars(VarTable*);
|
||||||
|
//void vartable_coalesce_reachingdefs_for_all_vars(VarTable*);
|
||||||
|
|
||||||
void vte_precolor(ScopeItem *vte, int resclass, int color);
|
void vte_precolor(VarTableEntry *vte, int color);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
95
src/x86.h
95
src/x86.h
@ -3,90 +3,11 @@
|
|||||||
#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 HWR_AL 1
|
#define COLOR_EAX 0
|
||||||
#define HWR_AH 2
|
#define COLOR_ECX 1
|
||||||
#define HWR_BL 4
|
#define COLOR_EDX 2
|
||||||
#define HWR_BH 8
|
#define COLOR_EBX 3
|
||||||
#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
|
||||||
@ -100,10 +21,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 == SCOPEITEM_VAR ? XOP_NOT_MEM : XOP_MEM;
|
return e->exprVar.thing->kind == VARTABLEENTRY_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 == SCOPEITEM_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 == VARTABLEENTRY_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;
|
||||||
@ -112,7 +33,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 == SCOPEITEM_VAR) {
|
if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_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) ||
|
||||||
@ -237,7 +158,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 != SCOPEITEM_VAR) {
|
if(stmt->stmtAssign.what->nodeKind != AST_EXPR_VAR || stmt->stmtAssign.what->exprVar.thing->kind != VARTABLEENTRY_VAR) {
|
||||||
return DEST_IS_BAD_XOP;
|
return DEST_IS_BAD_XOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
44
tests/GenericStruct.nct
Normal file
44
tests/GenericStruct.nct
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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);*/
|
@ -1,68 +0,0 @@
|
|||||||
record LibCSockAddrInet6 {
|
|
||||||
u16 family;
|
|
||||||
u16 port;
|
|
||||||
u32 flowinfo;
|
|
||||||
u8[16] address;
|
|
||||||
}
|
|
||||||
|
|
||||||
@section(".text");
|
|
||||||
|
|
||||||
extern u32(u32 domain, u32 type, u32 protocol) socket;
|
|
||||||
extern u32(u32 sockfd, u8* addr, u32 socklen) bind;
|
|
||||||
extern u32(u32 sockfd, u32 backlog) listen;
|
|
||||||
extern u32(u32 sockfd, u8* addr, u32* socklen) accept;
|
|
||||||
extern u32(u32 sockfd, u8* data, u32 length) write;
|
|
||||||
extern u32(u32 sockfd, u8* data, u32 length) read;
|
|
||||||
extern u32(u32 fd) close;
|
|
||||||
|
|
||||||
main: u0() -> {
|
|
||||||
SERV_SOCKET = socket(10, 1, 0);
|
|
||||||
|
|
||||||
LibCSockAddrInet6 addr;
|
|
||||||
addr.family = 10; /* AF_INET6 */
|
|
||||||
addr.port = 43105; /* 25000 in reversed endian */
|
|
||||||
addr.flowinfo = 0;
|
|
||||||
addr.address[0] = 0;
|
|
||||||
addr.address[1] = 0;
|
|
||||||
addr.address[2] = 0;
|
|
||||||
addr.address[3] = 0;
|
|
||||||
addr.address[4] = 0;
|
|
||||||
addr.address[5] = 0;
|
|
||||||
addr.address[6] = 0;
|
|
||||||
addr.address[7] = 0;
|
|
||||||
addr.address[8] = 0;
|
|
||||||
addr.address[9] = 0;
|
|
||||||
addr.address[10] = 0;
|
|
||||||
addr.address[11] = 0;
|
|
||||||
addr.address[12] = 0;
|
|
||||||
addr.address[13] = 0;
|
|
||||||
addr.address[14] = 0;
|
|
||||||
addr.address[15] = 0;
|
|
||||||
bind(SERV_SOCKET, &addr, @sizeof(addr));
|
|
||||||
|
|
||||||
listen(SERV_SOCKET, 16);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
u32 fd = accept(SERV_SOCKET, &addr, &SOCK_LEN);
|
|
||||||
if(fd == -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
read(fd, &BUFFER, @sizeof(BUFFER));
|
|
||||||
write(fd, &RESPONSE, @sizeof(RESPONSE));
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
@section(".data");
|
|
||||||
|
|
||||||
u32 SOCK_LEN:;
|
|
||||||
|
|
||||||
u32 SERV_SOCKET:;
|
|
||||||
|
|
||||||
u8[?] RESPONSE: "HTTP/1.0 200 OK\r\nServer: NectarTestHTTPFileServer\r\nContent-Type: text/plain\r\n\r\nYo.";
|
|
||||||
|
|
||||||
u8[1024] BUFFER:;
|
|
@ -1,4 +1,3 @@
|
|||||||
use Exporter;
|
use Exporter;
|
||||||
|
|
||||||
Foo f;
|
u32 a = Exporter.SYMBOL;
|
||||||
f.gaga = SYMBOL;
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
u8 a = 12;
|
|
||||||
u8 b = 19;
|
|
||||||
u8 c = a + b;
|
|
||||||
u32 d = 1;
|
|
||||||
u8 e = d + 1;
|
|
||||||
u32 f = 10;
|
|
||||||
u32 g = 55;
|
|
||||||
a;
|
|
||||||
b;
|
|
||||||
c;
|
|
||||||
d;
|
|
||||||
e;
|
|
||||||
f;
|
|
||||||
g;
|
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* ListDLC: Dynamic, Linear growth, C-managed
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern u8*(u8*, u32) realloc;
|
|
||||||
|
|
||||||
record ListDLC[T, S; growth] {
|
|
||||||
S capacity;
|
|
||||||
S size;
|
|
||||||
T[?]* data;
|
|
||||||
}
|
|
||||||
|
|
||||||
ListDLC_remove: [T, S; growth]u0(ListDLC[T, S; growth]* this, S index) -> {
|
|
||||||
T* data0 = &((*((*this).data))[index]);
|
|
||||||
T* data1 = data0 + @sizeof T;
|
|
||||||
S sz = (*this).size;
|
|
||||||
(*this).size = (*this).size - 1;
|
|
||||||
loop {
|
|
||||||
if(index == sz) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*data0 = *data1;
|
|
||||||
|
|
||||||
data0 = data0 + @sizeof T;
|
|
||||||
data1 = data1 + @sizeof T;
|
|
||||||
index = index + 1;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
ListDLC_add: [T, S; growth]u0(ListDLC[T, S; growth]* this, T value) -> {
|
|
||||||
if((*this).size == (*this).capacity) {
|
|
||||||
u32 newcap = (*this).capacity + growth;
|
|
||||||
(*this).capacity = newcap;
|
|
||||||
(*this).data = realloc((*this).data, newcap * @sizeof T);
|
|
||||||
}
|
|
||||||
|
|
||||||
(*((*this).data))[(*this).size] = value;
|
|
||||||
(*this).size = (*this).size + 1;
|
|
||||||
|
|
||||||
return;
|
|
||||||
};
|
|
@ -1,27 +0,0 @@
|
|||||||
record ListS[T, S; capacity] {
|
|
||||||
S size;
|
|
||||||
T[capacity] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
ListS_remove: [T, S; capacity]u0(ListS[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;
|
|
||||||
};
|
|
||||||
|
|
||||||
ListS_add: [T, S; capacity]u0(ListS[T, S; capacity]* this, T value) -> {
|
|
||||||
(*this).data[(*this).size] = value;
|
|
||||||
(*this).size = (*this).size + 1;
|
|
||||||
return;
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
use ListDLC;
|
|
||||||
|
|
||||||
@section(".text");
|
|
||||||
|
|
||||||
@instantiate ListDLC_remove[u32, u32; 9];
|
|
||||||
@instantiate ListDLC_add[u32, u32; 9];
|
|
||||||
|
|
||||||
main: u0() -> {
|
|
||||||
ListDLC_add[u32, u32; 9](&list, 1234);
|
|
||||||
ListDLC_add[u32, u32; 9](&list, 4321);
|
|
||||||
ListDLC_add[u32, u32; 9](&list, 7777);
|
|
||||||
ListDLC_add[u32, u32; 9](&list, 6969);
|
|
||||||
ListDLC_remove[u32, u32; 9](&list, 1);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
@section(".bss");
|
|
||||||
|
|
||||||
ListDLC[u32, u32; 9] list:;
|
|
Loading…
Reference in New Issue
Block a user