Compare commits

...

10 Commits

Author SHA1 Message Date
Mid
f406b2a032 Sections are now top-level nodes (which contain TLCs)
Previously, `@section` was a statement inside a top-level chunk, which
caused issues when the TLC allocated stack memory (the prologue was
generated before the `@section`).

This way, Nectar source code is now defined as a list of sections,
first and foremost.
2025-11-12 12:29:15 +02:00
Mid
7a8b14308b Make dereferencing operator binary, to account for segmentation 2025-10-17 18:16:58 +03:00
Mid
fee8ea5cb3 Bug fixed in string literal -> int cast 2025-10-17 14:09:40 +03:00
Mid
2aa64f4a37 More declarations 2025-10-17 14:09:25 +03:00
Mid
8c164a3b09 sgpr and smem 2025-10-17 14:09:10 +03:00
Mid
8c4754b563 Joe expansion 2025-10-15 14:11:41 +03:00
Mid
9d975eeceb Force assign declaration statement for all virtual/temp variables 2025-10-15 14:11:24 +03:00
Mid
ecab77f9e9 Holy fucking bug omg 2025-10-15 14:11:02 +03:00
Mid
132cedff09 ebp is also callee-saved 2025-10-15 14:10:54 +03:00
Mid
f978b66662 Conditionally save volatile regs 2025-10-15 14:10:42 +03:00
15 changed files with 328 additions and 198 deletions

View File

@@ -46,8 +46,28 @@ MapDQCOaLDhS_try_add: [K, V, S]u1(MapDQCOaLDhS[K, V, S]* this, K* key, V* value)
}; };
MapDQCOaLDhS_expand: [K, V, S]u1(MapDQCOaLDhS[K, V, S]* this) -> { MapDQCOaLDhS_expand: [K, V, S]u1(MapDQCOaLDhS[K, V, S]* this) -> {
/* Unimplemented. */ S capacity = this.capacity;
return 0; KVPair[K, V][?]* old_data = this.data;
u8[?]* old_occupied = this.occupied;
S new_capacity = capacity * 2;
this.capacity = new_capacity;
this.data = calloc(new_capacity, @sizeof KVPair[K, V]);
this.occupied = calloc(new_capacity, @sizeof((*this.occupied)[0]));
S i = 0;
loop {
if(i == capacity) {
break;
}
if((*old_occupied)[i] != 0) {
KVPair[K, V]* pair = &((*old_data)[i]);
MapDQCOaLDhS_try_add[K, V, S](this, &pair.key, &pair.value);
}
i = i + 1;
}
return 1;
}; };
MapDQCOaLDhS_add: [K, V, S]u1(MapDQCOaLDhS[K, V, S]* this, K* key, V* value) -> { MapDQCOaLDhS_add: [K, V, S]u1(MapDQCOaLDhS[K, V, S]* this, K* key, V* value) -> {

View File

@@ -49,14 +49,22 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v
} else if(n->nodeKind == AST_STMT_EXPR) { } else if(n->nodeKind == AST_STMT_EXPR) {
generic_visitor(&n->stmtExpr.expr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); generic_visitor(&n->stmtExpr.expr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_STMT_EXT_ORG) { } else if(n->nodeKind == AST_STMT_EXT_ORG) {
} else if(n->nodeKind == AST_STMT_EXT_SECTION) { } else if(n->nodeKind == AST_SECTION) {
generic_visitor(&n->section.tlc, stmt, stmtPrev, n->section.tlc, n->section.tlc, ud, preHandler, postHandler);
if(n->section.next) {
generic_visitor(&n->section.next, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_RETURN) { } else if(n->nodeKind == AST_STMT_RETURN) {
if(n->stmtReturn.val) { if(n->stmtReturn.val) {
generic_visitor(&n->stmtReturn.val, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); generic_visitor(&n->stmtReturn.val, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} }
} else if(n->nodeKind == AST_EXPR_BINARY_OP) { } else if(n->nodeKind == AST_EXPR_BINARY_OP) {
if(n->exprBinOp.operands[0]) {
generic_visitor(&n->exprBinOp.operands[0], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); generic_visitor(&n->exprBinOp.operands[0], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
if(n->exprBinOp.operands[1]) {
generic_visitor(&n->exprBinOp.operands[1], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); generic_visitor(&n->exprBinOp.operands[1], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_EXPR_CALL) { } else if(n->nodeKind == AST_EXPR_CALL) {
generic_visitor(&n->exprCall.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); generic_visitor(&n->exprCall.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
@@ -101,6 +109,9 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v
} }
int ast_expression_equal(AST *a, AST *b) { int ast_expression_equal(AST *a, AST *b) {
if(!a && !b) return 1;
if(a == b) return 1;
if(a->nodeKind != b->nodeKind) return 0; if(a->nodeKind != b->nodeKind) return 0;
if(a->nodeKind == AST_EXPR_PRIMITIVE) { if(a->nodeKind == AST_EXPR_PRIMITIVE) {
@@ -238,7 +249,8 @@ AST *ast_cast_expr(AST *what, Type *to) {
ASTExprPrimitive *ret = calloc(1, sizeof(*ret)); ASTExprPrimitive *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE; ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = to; ret->type = to;
memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val)); ret->val = 0;
memcpy(&ret->val, what->exprStrLit.data, what->exprStrLit.length);
return (AST*) ret; return (AST*) ret;
} else abort(); } else abort();
} }

View File

@@ -38,7 +38,7 @@
K(AST_EXPR_ARRAY) \ K(AST_EXPR_ARRAY) \
K(AST_EXPR_FUNC) \ K(AST_EXPR_FUNC) \
K(AST_STMT_EXT_ORG) \ K(AST_STMT_EXT_ORG) \
K(AST_STMT_EXT_SECTION) \ K(AST_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) \
@@ -77,6 +77,8 @@ typedef enum ENUMPAK {
BINOP_LOGICAL_AND = 15, BINOP_LOGICAL_AND = 15,
BINOP_LOGICAL_OR = 16, BINOP_LOGICAL_OR = 16,
BINOP_DEREF = 17,
BINOP_WTF = 999, BINOP_WTF = 999,
} BinaryOp; } BinaryOp;
@@ -106,7 +108,6 @@ static inline BinaryOp binop_comp_opposite(BinaryOp op) {
} }
typedef enum ENUMPAK { typedef enum ENUMPAK {
UNOP_DEREF = 0,
UNOP_NEGATE = 1, UNOP_NEGATE = 1,
UNOP_BITWISE_NOT = 2, UNOP_BITWISE_NOT = 2,
UNOP_REF = 3, UNOP_REF = 3,
@@ -203,7 +204,17 @@ typedef struct {
union AST *expression; union AST *expression;
} ASTStmtDecl; } ASTStmtDecl;
typedef struct { struct ASTChunk;
typedef struct ASTSection {
ASTBase;
Token name;
struct ASTChunk *tlc;
struct ASTSection *next;
} ASTSection;
typedef struct ASTChunk {
ASTBase; ASTBase;
/* Flattened variable array for global register allocation */ /* Flattened variable array for global register allocation */
@@ -299,12 +310,6 @@ typedef struct {
size_t val; size_t val;
} ASTStmtExtOrg; } ASTStmtExtOrg;
typedef struct {
ASTStmt;
Token name;
} ASTStmtExtSection;
typedef struct { typedef struct {
ASTStmt; ASTStmt;
@@ -363,7 +368,7 @@ typedef union AST {
ASTExprDot exprDot; ASTExprDot exprDot;
ASTExprExtSalloc exprExtSalloc; ASTExprExtSalloc exprExtSalloc;
ASTStmtExtOrg stmtExtOrg; ASTStmtExtOrg stmtExtOrg;
ASTStmtExtSection stmtExtSection; ASTSection section;
ASTExprExtSizeOf exprExtSizeOf; ASTExprExtSizeOf exprExtSizeOf;
ASTStmtJump stmtJump; ASTStmtJump stmtJump;
ASTStmtLabel stmtLabel; ASTStmtLabel stmtLabel;

View File

@@ -38,6 +38,7 @@ static AST *varify(AST *tlc, AST *chunk, AST **stmtPrev, AST *stmt, AST *e) {
assign->nodeKind = AST_STMT_ASSIGN; assign->nodeKind = AST_STMT_ASSIGN;
assign->what = (AST*) ev[0]; assign->what = (AST*) ev[0];
assign->to = e; assign->to = e;
vte->data.var.declaration = (AST*) assign;
if(*stmtPrev) { if(*stmtPrev) {
(*stmtPrev)->statement.next = (AST*) assign; (*stmtPrev)->statement.next = (AST*) assign;
@@ -61,54 +62,29 @@ static void ast_segmented_dereference_visitor(AST **aptr, AST *stmt, AST *stmtPr
} }
AST *n = *aptr; AST *n = *aptr;
if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_DEREF && type_is_segmented_pointer(n->exprUnOp.operand->expression.type)) { if(n->nodeKind == AST_EXPR_BINARY_OP && n->exprBinOp.operator == BINOP_DEREF && type_is_segmented_pointer(n->exprBinOp.operands[0]->expression.type)) {
static size_t idx = 0; static size_t idx = 0;
AST *v; AST *v;
if(n->exprUnOp.operand->nodeKind == AST_EXPR_VAR) if(n->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR)
v = n->exprUnOp.operand; v = n->exprBinOp.operands[0];
else else
v = varify(tlc, chunk, &stmtPrev, stmt, n->exprUnOp.operand); v = varify(tlc, chunk, &stmtPrev, stmt, n->exprBinOp.operands[0]);
ScopeItem *si = calloc(1, sizeof(*si));
si->kind = SCOPEITEM_VAR;
si->type = primitive_parse("u16");
si->data.var.preclassed = true;
si->data.var.registerClass = REG_CLASS_DATASEGS;
si->data.var.precolored = true;
si->data.var.color = 0;
si->data.var.name = malp("$segtemp_%lu", idx++);
ast_tlc_add_var(tlc, si);
ASTExprVar *ev = calloc(1, sizeof(*ev));
ev->nodeKind = AST_EXPR_VAR;
ev->type = si->type;
ev->thing = si;
ASTExprDot *edseg = calloc(1, sizeof(*edseg)); ASTExprDot *edseg = calloc(1, sizeof(*edseg));
edseg->type = n->exprUnOp.operand->expression.type->record.fieldTypes[0]; edseg->type = n->exprBinOp.operands[0]->expression.type->record.fieldTypes[0];
edseg->nodeKind = AST_EXPR_DOT; edseg->nodeKind = AST_EXPR_DOT;
edseg->a = v; edseg->a = v;
edseg->b = strdup("segment"); edseg->b = strdup("segment");
ASTStmtAssign *ass = calloc(1, sizeof(*ass));
ass->nodeKind = AST_STMT_ASSIGN;
ass->what = (AST*) ev;
ass->to = (AST*) edseg;
ass->next = (AST*) stmt;
if(stmtPrev)
stmtPrev->statement.next = (AST*) ass;
else
chunk->chunk.statementFirst = (AST*) ass;
stmtPrev = (AST*) ass;
ASTExprDot *ed = calloc(1, sizeof(*ed)); ASTExprDot *ed = calloc(1, sizeof(*ed));
ed->type = n->exprUnOp.operand->expression.type->record.fieldTypes[1]; ed->type = n->exprBinOp.operands[0]->expression.type->record.fieldTypes[1];
ed->nodeKind = AST_EXPR_DOT; ed->nodeKind = AST_EXPR_DOT;
ed->a = ast_deep_copy(v); ed->a = ast_deep_copy(v);
ed->b = strdup("offset"); ed->b = strdup("offset");
n->exprUnOp.operand = (AST*) ed; n->exprBinOp.operands[0] = (AST*) ed;
n->exprBinOp.operands[1] = (AST*) edseg;
} }
} }

View File

@@ -65,9 +65,6 @@ static char *ast_dumpe(AST *tlc, AST *e) {
case UNOP_REF: case UNOP_REF:
op = "&"; op = "&";
break; break;
case UNOP_DEREF:
op = "*";
break;
case UNOP_BITWISE_NOT: case UNOP_BITWISE_NOT:
op = "~"; op = "~";
break; break;
@@ -84,6 +81,18 @@ static char *ast_dumpe(AST *tlc, AST *e) {
char *r = malp("%s%s", op, c); char *r = malp("%s%s", op, c);
free(c); free(c);
return r; return r;
} else if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_DEREF) {
char *a = ast_dumpe(tlc, e->exprBinOp.operands[0]);
char *r;
if(e->exprBinOp.operands[1]) {
char *b = ast_dumpe(tlc, e->exprBinOp.operands[1]);
r = malp("*[%s]%s", b, a);
free(b);
} else {
r = malp("*%s", a);
}
free(a);
return r;
} else if(e->nodeKind == AST_EXPR_BINARY_OP) { } else if(e->nodeKind == AST_EXPR_BINARY_OP) {
char *a = ast_dumpe(tlc, e->exprBinOp.operands[0]); char *a = ast_dumpe(tlc, e->exprBinOp.operands[0]);
char *b = ast_dumpe(tlc, e->exprBinOp.operands[1]); char *b = ast_dumpe(tlc, e->exprBinOp.operands[1]);

View File

@@ -51,6 +51,7 @@ static void ast_decompose_automatic_record(AST *tlc, ScopeItem *target) {
si->kind = SCOPEITEM_VAR; si->kind = SCOPEITEM_VAR;
si->type = target->type->record.fieldTypes[f]; si->type = target->type->record.fieldTypes[f];
si->data.var.name = malp("%s_sroa_%s", target->data.var.name, target->type->record.fieldNames[f]); si->data.var.name = malp("%s_sroa_%s", target->data.var.name, target->type->record.fieldNames[f]);
si->data.var.declaration = target->data.var.declaration;
state.replacements[f] = si; state.replacements[f] = si;
tlc->chunk.vars[tlc->chunk.varCount++] = si; tlc->chunk.vars[tlc->chunk.varCount++] = si;

View File

@@ -46,11 +46,11 @@ static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk
bop->operands[0] = (AST*) rsp; bop->operands[0] = (AST*) rsp;
bop->operands[1] = (AST*) offset; bop->operands[1] = (AST*) offset;
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref)); ASTExprBinaryOp *deref = calloc(1, sizeof(*deref));
deref->nodeKind = AST_EXPR_UNARY_OP; deref->nodeKind = AST_EXPR_BINARY_OP;
deref->type = a->expression.type; deref->type = a->expression.type;
deref->operator = UNOP_DEREF; deref->operator = BINOP_DEREF;
deref->operand = (AST*) bop; deref->operands[0] = (AST*) bop;
*aptr = (AST*) deref; *aptr = (AST*) deref;
} }

View File

@@ -204,6 +204,8 @@ void ast_usedef_reset(AST *chu) {
for(size_t sii = 0; sii < chu->chunk.varCount; sii++) { for(size_t sii = 0; sii < chu->chunk.varCount; sii++) {
ScopeItem *si = chu->chunk.vars[sii]; ScopeItem *si = chu->chunk.vars[sii];
assert(si->data.var.declaration != NULL && "All local vars must have defined declaration location");
if(ast_stmt_is_after(chu, si->data.var.liveRangeEnd, s) == 0 && ast_stmt_is_after(chu, target, si->data.var.liveRangeEnd) == 0 && ast_stmt_is_after(chu, si->data.var.declaration, target) == 0) { if(ast_stmt_is_after(chu, si->data.var.liveRangeEnd, s) == 0 && ast_stmt_is_after(chu, target, si->data.var.liveRangeEnd) == 0 && ast_stmt_is_after(chu, si->data.var.declaration, target) == 0) {
si->data.var.liveRangeEnd = s; si->data.var.liveRangeEnd = s;

View File

@@ -86,28 +86,30 @@ int main(int argc_, char **argv_) {
if(in) fclose(f); if(in) fclose(f);
AST *chunk = nct_parse(tokens); AST *sects = nct_parse(tokens);
free(tokens); free(tokens);
if(ntc_get_int("pdbg")) { if(ntc_get_int("pdbg")) {
char *astdump = ast_dump(chunk); char *astdump = ast_dump(sects);
fprintf(stderr, "### ORIGINAL ###\n%s\n", astdump); fprintf(stderr, "### ORIGINAL ###\n%s\n", astdump);
free(astdump); free(astdump);
} }
ast_segmented_dereference(chunk); ast_segmented_dereference(sects);
ast_secondclass_record(chunk); ast_secondclass_record(sects);
ast_sroa(chunk); ast_sroa(sects);
ast_linearize(chunk); ast_linearize(sects);
arch_normalize_pre(chunk); arch_normalize_pre(sects);
arch_normalize(chunk); arch_normalize(sects);
while(!cg_go(chunk)) { while(!cg_attempt_sections(sects)) {
arch_normalize(chunk); arch_normalize(sects);
} }
cg_go_sections(sects);
return 0; return 0;
} }

View File

@@ -18,6 +18,7 @@ bool arch_verify_target();
int arch_ptr_size(); int arch_ptr_size();
void arch_normalize_pre(union AST *tlc); void arch_normalize_pre(union AST *tlc);
void arch_normalize(union AST *tlc); void arch_normalize(union AST *tlc);
int cg_go(union AST *tlc); int cg_attempt_sections(union AST *tlc);
void cg_go_sections(union AST *tlc);
#endif #endif

View File

@@ -297,11 +297,11 @@ AST *nct_parse_expression(Parser *P, int lOP) {
if(op.type == TOKEN_DOT) { if(op.type == TOKEN_DOT) {
while(e->expression.type->type == TYPE_TYPE_POINTER) { while(e->expression.type->type == TYPE_TYPE_POINTER) {
AST *deref = alloc_node(P, sizeof(ASTExprUnaryOp)); AST *deref = alloc_node(P, sizeof(ASTExprBinaryOp));
deref->nodeKind = AST_EXPR_UNARY_OP; deref->nodeKind = AST_EXPR_BINARY_OP;
deref->exprUnOp.operator = UNOP_DEREF; deref->exprBinOp.operator = BINOP_DEREF;
deref->exprUnOp.operand = (AST*) e; deref->exprBinOp.operands[0] = (AST*) e;
deref->exprUnOp.type = type_dereference(e->expression.type); deref->exprBinOp.type = type_dereference(e->expression.type);
e = (AST*) deref; e = (AST*) deref;
} }
@@ -434,11 +434,11 @@ AST *nct_parse_expression(Parser *P, int lOP) {
child->operands[1] = (AST*) mul; child->operands[1] = (AST*) mul;
} }
ASTExprUnaryOp *unop = alloc_node(P, sizeof(*unop)); ASTExprBinaryOp *unop = alloc_node(P, sizeof(*unop));
unop->nodeKind = AST_EXPR_UNARY_OP; unop->nodeKind = AST_EXPR_BINARY_OP;
unop->type = e->expression.type->array.of; unop->type = e->expression.type->array.of;
unop->operator = UNOP_DEREF; unop->operator = BINOP_DEREF;
unop->operand = (AST*) child; unop->operands[0] = (AST*) child;
expect(P, TOKEN_SQUAREN_R); expect(P, TOKEN_SQUAREN_R);
@@ -452,16 +452,16 @@ AST *nct_parse_expression(Parser *P, int lOP) {
return e; return e;
} else if(lOP == 6) { } else if(lOP == 6) {
if(maybe(P, TOKEN_STAR)) { if(maybe(P, TOKEN_STAR)) {
ASTExprUnaryOp *astop = alloc_node(P, sizeof(*astop)); ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop));
astop->nodeKind = AST_EXPR_UNARY_OP; astop->nodeKind = AST_EXPR_BINARY_OP;
astop->operator = UNOP_DEREF; astop->operator = BINOP_DEREF;
astop->operand = nct_parse_expression(P, lOP); /* Not +1! */ astop->operands[0] = nct_parse_expression(P, lOP); /* Not +1! */
if(type_is_segmented_pointer(astop->operand->expression.type)) { if(type_is_segmented_pointer(astop->operands[0]->expression.type)) {
astop->type = astop->operand->expression.type->record.fieldTypes[1]->pointer.of; astop->type = astop->operands[0]->expression.type->record.fieldTypes[1]->pointer.of;
} else { } else {
assert(astop->operand->expression.type->type == TYPE_TYPE_POINTER); assert(astop->operands[0]->expression.type->type == TYPE_TYPE_POINTER);
astop->type = astop->operand->expression.type->pointer.of; astop->type = astop->operands[0]->expression.type->pointer.of;
} }
return (AST*) astop; return (AST*) astop;
@@ -1236,21 +1236,6 @@ static void nct_parse_statement(Parser *P) {
expect(P, TOKEN_SEMICOLON); expect(P, TOKEN_SEMICOLON);
pushstat(P, ret);
return;
} else if(!strcmp(peek(P, 0).content, "@section")) {
ASTStmtExtSection *ret = alloc_node(P, sizeof(*ret));
ret->nodeKind = AST_STMT_EXT_SECTION;
ret->next = NULL;
get(P);
expect(P, TOKEN_PAREN_L);
ret->name = expect(P, TOKEN_STRING);
expect(P, TOKEN_PAREN_R);
expect(P, TOKEN_SEMICOLON);
pushstat(P, ret); pushstat(P, ret);
return; return;
} else if(!strcmp(peek(P, 0).content, "@instantiate")) { } else if(!strcmp(peek(P, 0).content, "@instantiate")) {
@@ -1516,9 +1501,12 @@ Type *nct_parse_record_definition(Parser *P) {
return tr; return tr;
} }
static void skim_chunk(Parser *P, int isTopLevel) { /*
/* Find all symbol names and struct types ahead of time. Searches for colons as those can only mean symbol declarations */ * Find all symbol names and struct types ahead of time.
* Searches for colons as they can only mean symbol declarations.
* This function abuses Nectar's grammar to work, so malformed source
* code can fuck it up. */
static void skim_tokens(Parser *P, int isTopLevel) {
P->skimMode++; P->skimMode++;
{ {
intmax_t oldIdx = P->i; intmax_t oldIdx = P->i;
@@ -1606,7 +1594,7 @@ static void skim_chunk(Parser *P, int isTopLevel) {
free(path); free(path);
Parser subp = {.tokens = nct_lex(f), .scope = scope_new(NULL), .externalify = 1}; Parser subp = {.tokens = nct_lex(f), .scope = scope_new(NULL), .externalify = 1};
skim_chunk(&subp, 1); skim_tokens(&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++) {
@@ -1650,8 +1638,6 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *t
P->topLevel = &ret->chunk; P->topLevel = &ret->chunk;
} }
skim_chunk(P, isTopLevel);
/* Arguments */ /* Arguments */
if(ft && isTopLevel) { if(ft && isTopLevel) {
P->topLevel->functionType = ft; P->topLevel->functionType = ft;
@@ -1676,7 +1662,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *t
arch_add_hidden_variables(P->scope); arch_add_hidden_variables(P->scope);
while(peek(P, 0).type != TOKEN_EOF && peek(P, 0).type != TOKEN_SQUIGGLY_R) { while(peek(P, 0).type != TOKEN_EOF && peek(P, 0).type != TOKEN_SQUIGGLY_R && !(peek(P, 0).type == TOKEN_IDENTIFIER && !strcmp(peek(P, 0).content, "@section"))) {
nct_parse_statement(P); nct_parse_statement(P);
} }
@@ -1711,9 +1697,49 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *t
return &ret->chunk; return &ret->chunk;
} }
ASTSection *nct_parse_sections(Parser *P) {
ASTSection *start = alloc_node(P, sizeof(*start));
start->nodeKind = AST_SECTION;
ASTSection *current = start;
while(1) {
current->tlc = nct_parse_chunk(P, 1, 0, P->scope, NULL);
if(peek(P, 0).type == TOKEN_EOF) {
break;
}
if(!(peek(P, 0).type == TOKEN_IDENTIFIER && !strcmp(peek(P, 0).content, "@section"))) {
stahp_token(&P->tokens[P->i - 1], "Expected @section.");
}
ASTSection *next = alloc_node(P, sizeof(*next));
next->nodeKind = AST_SECTION;
get(P);
expect(P, TOKEN_PAREN_L);
next->name = expect(P, TOKEN_STRING);
expect(P, TOKEN_PAREN_R);
expect(P, TOKEN_SEMICOLON);
current->next = next;
current = next;
}
return start;
}
AST *nct_parse(Token *tokens) { AST *nct_parse(Token *tokens) {
Scope *scope = scope_new(NULL);
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); P.scope = scope;
skim_tokens(&P, 1);
return (AST*) nct_parse_sections(&P);
} }

View File

@@ -26,8 +26,12 @@ Type *primitive_parse(const char *src) {
if(!strcmp(src, "ugpr")) { if(!strcmp(src, "ugpr")) {
return type_u(8 * arch_gpr_size()); return type_u(8 * arch_gpr_size());
} else if(!strcmp(src, "sgpr")) {
return type_s(8 * arch_gpr_size());
} else if(!strcmp(src, "umem")) { } else if(!strcmp(src, "umem")) {
return type_u(arch_memory_width()); return type_u(arch_memory_width());
} else if(!strcmp(src, "smem")) {
return type_s(arch_memory_width());
} }
TypePrimitive *ret = calloc(1, sizeof(*ret)); TypePrimitive *ret = calloc(1, sizeof(*ret));

View File

@@ -133,12 +133,12 @@ static inline int is_xop(AST *e) {
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 == SCOPEITEM_VAR ? XOP_NOT_MEM : XOP_MEM;
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && is_xop(e->exprUnOp.operand->exprBinOp.operands[0]) == XOP_NOT_MEM && is_xop(e->exprUnOp.operand->exprBinOp.operands[1]) == XOP_NOT_MEM) { } else if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_DEREF && e->exprBinOp.operands[0]->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operands[0]->exprBinOp.operator == BINOP_ADD && is_xop(e->exprBinOp.operands[0]->exprBinOp.operands[0]) == XOP_NOT_MEM && is_xop(e->exprBinOp.operands[0]->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 == SCOPEITEM_SYMBOL) {
return XOP_NOT_MEM; return XOP_NOT_MEM;
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { } else if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_DEREF) {
AST *c = e->exprUnOp.operand; AST *c = e->exprBinOp.operands[0];
if(c->nodeKind == AST_EXPR_CAST && c->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && c->exprCast.to->type == TYPE_TYPE_POINTER) { if(c->nodeKind == AST_EXPR_CAST && c->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && c->exprCast.to->type == TYPE_TYPE_POINTER) {
c = c->exprCast.what; c = c->exprCast.what;

View File

@@ -115,11 +115,11 @@ static const char *xj(BinaryOp op) {
} }
static AST *is_field_access(AST *e) { static AST *is_field_access(AST *e) {
if(e->nodeKind != AST_EXPR_UNARY_OP || e->exprUnOp.operator != UNOP_DEREF) { if(e->nodeKind != AST_EXPR_BINARY_OP || e->exprUnOp.operator != BINOP_DEREF) {
return NULL; return NULL;
} }
e = e->exprUnOp.operand; e = e->exprBinOp.operands[0];
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) {
e = e->exprCast.what; e = e->exprCast.what;
@@ -136,6 +136,16 @@ static AST *is_field_access(AST *e) {
return NULL; return NULL;
} }
static const char *segment_or_empty(AST *a) {
if(!a) {
return "ds";
}
assert(a->nodeKind == AST_EXPR_VAR);
assert(a->exprVar.thing->kind == SCOPEITEM_VAR);
assert(a->exprVar.thing->data.var.registerClass == REG_CLASS_DATASEGS);
return REG_CLASSES[REG_CLASS_DATASEGS].rsN[a->exprVar.thing->data.var.color];
}
/* /*
* Convert a XOP-able expression into an x86 operand. * Convert a XOP-able expression into an x86 operand.
* Result MUST be determinstic and always the same, for the same given expression. * Result MUST be determinstic and always the same, for the same given expression.
@@ -150,21 +160,24 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
int pr = 0; int pr = 0;
if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_DEREF) {
AST *p = e->exprUnOp.operand; AST *seg = e->exprBinOp.operands[1];
AST *p = e->exprBinOp.operands[0];
if(p->nodeKind == AST_EXPR_CAST && p->exprCast.to->type == TYPE_TYPE_POINTER) { if(p->nodeKind == AST_EXPR_CAST && p->exprCast.to->type == TYPE_TYPE_POINTER) {
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 == SCOPEITEM_VAR && p->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_VAR) {
pr = snprintf(ret, XOPBUFSZ, "%s [%s + %s]", pr = snprintf(ret, XOPBUFSZ, "%s %s:[%s + %s]",
spec(sz), spec(sz),
segment_or_empty(seg),
xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 0), xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 0),
xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 0)); xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 0));
} 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 == SCOPEITEM_SYMBOL && p->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_VAR) {
pr = snprintf(ret, XOPBUFSZ, "%s [%s + %s]", pr = snprintf(ret, XOPBUFSZ, "%s %s:[%s + %s]",
spec(sz), spec(sz),
segment_or_empty(seg),
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 0)); xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 0));
} else if(is_field_access(e)) { } else if(is_field_access(e)) {
@@ -173,8 +186,9 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
if(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP) { if(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP) {
assert(e->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF); assert(e->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF);
pr = snprintf(ret, XOPBUFSZ, "%s [%s + %i]", pr = snprintf(ret, XOPBUFSZ, "%s %s:[%s + %i]",
spec(sz), spec(sz),
segment_or_empty(seg),
e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
e->exprBinOp.operands[1]->exprPrim.val); e->exprBinOp.operands[1]->exprPrim.val);
} else { } else {
@@ -182,19 +196,21 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
ScopeItem *vte = e->exprBinOp.operands[0]->exprVar.thing; ScopeItem *vte = e->exprBinOp.operands[0]->exprVar.thing;
pr = snprintf(ret, XOPBUFSZ, "%s [%s + %i]", pr = snprintf(ret, XOPBUFSZ, "%s %s:[%s + %i]",
spec(sz), spec(sz),
segment_or_empty(seg),
REG_CLASSES[vte->data.var.registerClass].rsN[vte->data.var.color], REG_CLASSES[vte->data.var.registerClass].rsN[vte->data.var.color],
e->exprBinOp.operands[1]->exprPrim.val); e->exprBinOp.operands[1]->exprPrim.val);
} }
} else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && p->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == 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 == 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) {
pr = snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]", pr = snprintf(ret, XOPBUFSZ, "%s %s:[%s + %i * %s]",
spec(sz), spec(sz),
segment_or_empty(seg),
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, 0)); xv_sz(p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 0));
} else if(p->nodeKind == AST_EXPR_VAR && p->exprVar.thing->kind == SCOPEITEM_VAR) { } else if(p->nodeKind == AST_EXPR_VAR && p->exprVar.thing->kind == SCOPEITEM_VAR) {
pr = snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(p->exprVar.thing, 0)); pr = snprintf(ret, XOPBUFSZ, "%s %s:[%s]", spec(sz), segment_or_empty(seg), xv_sz(p->exprVar.thing, 0));
} else if(p->nodeKind == AST_EXPR_STACK_POINTER) { } else if(p->nodeKind == AST_EXPR_STACK_POINTER) {
if(x86_ia16()) { if(x86_ia16()) {
pr = snprintf(ret, XOPBUFSZ, "[bp + %li]", 0 - tlc->chunk.stackReservation); pr = snprintf(ret, XOPBUFSZ, "[bp + %li]", 0 - tlc->chunk.stackReservation);
@@ -260,6 +276,27 @@ static int lr_empty(ScopeItem *a) {
return !a->data.var.liveRangeStart; return !a->data.var.liveRangeStart;
} }
static bool is_resource_in_use_right_now_at_this_current_point_in_time_and_also_not_created_right_now(AST *tlc, AST *statement, size_t resource) {
for(size_t vi = 0; vi < tlc->chunk.varCount; vi++) {
ScopeItem *si = tlc->chunk.vars[vi];
if((REG_CLASSES[si->data.var.registerClass].rs[si->data.var.color] & resource) == 0) {
continue;
}
if(ast_stmt_is_after(tlc, statement, si->data.var.liveRangeEnd) == 1 || statement == si->data.var.liveRangeEnd) {
continue;
}
if(si->data.var.usedefFirst == NULL) {
// Even if the resource is in use, the variable itself isn't so we don't care
continue;
}
if(!lr_empty(si) && (ast_stmt_is_after(tlc, statement, si->data.var.liveRangeStart) == 1
&& ast_stmt_is_after(tlc, si->data.var.liveRangeEnd, statement) == 1)) {
return true;
}
}
return false;
}
void cg_chunk(CGState *cg, AST *a) { void cg_chunk(CGState *cg, AST *a) {
AST *s = a->chunk.statementFirst; AST *s = a->chunk.statementFirst;
@@ -300,15 +337,6 @@ void cg_chunk(CGState *cg, AST *a) {
printf("jmp .%s\n", s->stmtJump.label); printf("jmp .%s\n", s->stmtJump.label);
} }
} else if(s->nodeKind == AST_STMT_EXT_SECTION) {
Token t = s->stmtExtSection.name;
printf("section %.*s\n", (int) t.length, t.content);
} else if(s->nodeKind == AST_STMT_EXT_ORG) {
printf("org %lu\n", s->stmtExtOrg.val);
} else if(s->nodeKind == AST_STMT_EXT_ALIGN) { } else if(s->nodeKind == AST_STMT_EXT_ALIGN) {
uint32_t val = s->stmtExtAlign.val; uint32_t val = s->stmtExtAlign.val;
@@ -364,13 +392,13 @@ void cg_chunk(CGState *cg, AST *a) {
ast_linearize(s->stmtDecl.expression->exprFunc.chunk); ast_linearize(s->stmtDecl.expression->exprFunc.chunk);
arch_normalize_pre(s->stmtDecl.expression->exprFunc.chunk);
arch_normalize(s->stmtDecl.expression->exprFunc.chunk); arch_normalize(s->stmtDecl.expression->exprFunc.chunk);
while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) { while(!cg_attempt_sections(s->stmtDecl.expression->exprFunc.chunk)) {
arch_normalize(s->stmtDecl.expression->exprFunc.chunk); arch_normalize(s->stmtDecl.expression->exprFunc.chunk);
} }
cg_go_sections(s->stmtDecl.expression->exprFunc.chunk);
} }
} else abort(); } else abort();
@@ -390,12 +418,14 @@ void cg_chunk(CGState *cg, AST *a) {
AST *e = s->stmtAssign.to; AST *e = s->stmtAssign.to;
if(x86_ia16()) { if(is_resource_in_use_right_now_at_this_current_point_in_time_and_also_not_created_right_now(a, s, HWR_ECX)) {
puts("push cx"); puts(x86_ia16() ? "push cx" : "push ecx");
puts("push dx"); }
} else { if(is_resource_in_use_right_now_at_this_current_point_in_time_and_also_not_created_right_now(a, s, HWR_EDX)) {
puts("push ecx"); puts(x86_ia16() ? "push dx" : "push edx");
puts("push edx"); }
if(is_resource_in_use_right_now_at_this_current_point_in_time_and_also_not_created_right_now(a, s, HWR_EAX)) {
puts(x86_ia16() ? "push ax" : "push eax");
} }
int argCount = e->exprCall.what->expression.type->pointer.of->function.argCount; int argCount = e->exprCall.what->expression.type->pointer.of->function.argCount;
@@ -422,12 +452,14 @@ void cg_chunk(CGState *cg, AST *a) {
} }
} }
if(x86_ia16()) { if(is_resource_in_use_right_now_at_this_current_point_in_time_and_also_not_created_right_now(a, s, HWR_EAX)) {
puts("pop dx"); puts(x86_ia16() ? "pop ax" : "pop eax");
puts("pop cx"); }
} else { if(is_resource_in_use_right_now_at_this_current_point_in_time_and_also_not_created_right_now(a, s, HWR_EDX)) {
puts("pop edx"); puts(x86_ia16() ? "pop dx" : "pop edx");
puts("pop ecx"); }
if(is_resource_in_use_right_now_at_this_current_point_in_time_and_also_not_created_right_now(a, s, HWR_ECX)) {
puts(x86_ia16() ? "pop cx" : "pop ecx");
} }
} else if(s->nodeKind == AST_STMT_ASSIGN) { } else if(s->nodeKind == AST_STMT_ASSIGN) {
@@ -583,9 +615,9 @@ void cg_chunk(CGState *cg, AST *a) {
if(a->chunk.stackReservation) { if(a->chunk.stackReservation) {
for(int i = 0; i < MAX_REGS_PER_CLASS && cg->calleeSaved.reg[i]; i++) { for(int i = 0; i < MAX_REGS_PER_CLASS && cg->calleeSaved.reg[i]; i++) {
if(x86_ia16()) { if(x86_ia16()) {
printf("mov [bp + %li], %s\n", cg->calleeSaved.stackOffset[i] - a->chunk.stackReservation, cg->calleeSaved.reg[i]); printf("mov %s, [bp + %li]\n", cg->calleeSaved.reg[i], cg->calleeSaved.stackOffset[i] - a->chunk.stackReservation);
} else { } else {
printf("mov [esp + %li], %s\n", cg->calleeSaved.stackOffset[i], cg->calleeSaved.reg[i]); printf("mov %s, [esp + %li]\n", cg->calleeSaved.reg[i], cg->calleeSaved.stackOffset[i]);
} }
} }
@@ -607,14 +639,6 @@ void cg_chunk(CGState *cg, AST *a) {
printf("ret\n"); printf("ret\n");
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_VAR) {
/* Loop guard, probably. */
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_UNARY_OP && s->stmtExpr.expr->exprUnOp.operator == UNOP_DEREF && s->stmtExpr.expr->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
/* Loop guard for a spilled variable, probably. */
} else { } else {
stahp_node(s, "Unknown statement %s caught by code generator.", AST_KIND_STR[s->nodeKind]); stahp_node(s, "Unknown statement %s caught by code generator.", AST_KIND_STR[s->nodeKind]);
@@ -643,7 +667,7 @@ static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) {
} }
static void callee_saved(AST *tlc, struct CalleeSavedState *state) { static void callee_saved(AST *tlc, struct CalleeSavedState *state) {
bool ebxused = false, ediused = false, esiused = false; bool ebxused = false, ediused = false, esiused = false, ebpused = false;
for(size_t v = 0; v < tlc->chunk.varCount; v++) { for(size_t v = 0; v < tlc->chunk.varCount; v++) {
size_t resource = REG_CLASSES[tlc->chunk.vars[v]->data.var.registerClass].rs[tlc->chunk.vars[v]->data.var.color]; size_t resource = REG_CLASSES[tlc->chunk.vars[v]->data.var.registerClass].rs[tlc->chunk.vars[v]->data.var.color];
@@ -657,6 +681,9 @@ static void callee_saved(AST *tlc, struct CalleeSavedState *state) {
if(resource & HWR_ESI) { if(resource & HWR_ESI) {
esiused = true; esiused = true;
} }
if(resource & HWR_EBP) {
ebpused = true;
}
} }
size_t nextUser = 0; size_t nextUser = 0;
@@ -675,6 +702,11 @@ static void callee_saved(AST *tlc, struct CalleeSavedState *state) {
state->reg[nextUser] = x86_ia16() ? "di" : "edi"; state->reg[nextUser] = x86_ia16() ? "di" : "edi";
nextUser++; nextUser++;
} }
if(ebpused) {
state->stackOffset[nextUser] = nextUser * x86_max_gpr_size();
state->reg[nextUser] = x86_ia16() ? "bp" : "ebp";
nextUser++;
}
ast_grow_stack_frame(tlc, nextUser * x86_max_gpr_size()); ast_grow_stack_frame(tlc, nextUser * x86_max_gpr_size());
} }
@@ -759,7 +791,7 @@ nextColor:;
return mustSpillRegisterClass; return mustSpillRegisterClass;
} }
int cg_go(AST *a) { int cg_tlc(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++) {
@@ -769,6 +801,23 @@ int cg_go(AST *a) {
printf("extern %s\n", a->chunk.externs[e]->data.symbol.name); printf("extern %s\n", a->chunk.externs[e]->data.symbol.name);
} }
struct CalleeSavedState calleeSaved = {};
if(a->chunk.functionType) {
callee_saved(a, &calleeSaved);
}
CGState cg;
memset(&cg, 0, sizeof(cg));
cg.tlc = a;
cg.isFunction = !!a->chunk.functionType;
cg.calleeSaved = calleeSaved;
cg_chunk(&cg, a);
return 1;
}
static int cg_attempt(AST *a) {
ast_usedef_reset(a); ast_usedef_reset(a);
size_t adjCount = 0; size_t adjCount = 0;
@@ -858,19 +907,36 @@ cont:;
return 0; return 0;
} }
struct CalleeSavedState calleeSaved = {}; return 1;
if(a->chunk.functionType) { }
callee_saved(a, &calleeSaved);
int cg_attempt_sections(AST *a) {
assert(a->nodeKind == AST_SECTION);
ASTSection *current = &a->section;
while(current) {
if(!cg_attempt(current->tlc)) {
return 0;
} }
CGState cg; current = current->next;
memset(&cg, 0, sizeof(cg)); }
cg.tlc = a;
cg.isFunction = !!a->chunk.functionType;
cg.calleeSaved = calleeSaved;
cg_chunk(&cg, a);
return 1; return 1;
} }
void cg_go_sections(AST *a) {
assert(a->nodeKind == AST_SECTION);
ASTSection *current = &a->section;
while(current) {
if(current->name.content) {
printf("section %s\n", current->name.content);
}
cg_tlc(current->tlc);
current = current->next;
}
}

View File

@@ -35,6 +35,7 @@ static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
assign->nodeKind = AST_STMT_ASSIGN; assign->nodeKind = AST_STMT_ASSIGN;
assign->what = (AST*) ev[0]; assign->what = (AST*) ev[0];
assign->to = e; assign->to = e;
vte->data.var.declaration = (AST*) assign;
if(stmtPrev) { if(stmtPrev) {
stmtPrev->statement.next = (AST*) assign; stmtPrev->statement.next = (AST*) assign;
@@ -106,8 +107,6 @@ struct NormState {
static void normalize_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud) { static void normalize_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud) {
struct NormState *this = ud; struct NormState *this = ud;
if(this->targetTLC != tlc) return;
AST *s = *nptr; AST *s = *nptr;
if(s->nodeKind == AST_STMT_JUMP && s->stmtJump.condition) { if(s->nodeKind == AST_STMT_JUMP && s->stmtJump.condition) {
@@ -297,6 +296,7 @@ static void normalize_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AS
assign2->nodeKind = AST_STMT_ASSIGN; assign2->nodeKind = AST_STMT_ASSIGN;
assign2->what = (AST*) s->stmtAssign.what; assign2->what = (AST*) s->stmtAssign.what;
assign2->to = (AST*) ev[0]; assign2->to = (AST*) ev[0];
tmp->data.var.declaration = (AST*) s;
s->stmtAssign.what = (AST*) ev[1]; s->stmtAssign.what = (AST*) ev[1];
@@ -305,18 +305,18 @@ static void normalize_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AS
this->effective = 1; this->effective = 1;
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF } else if(s->stmtAssign.what->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.what->exprBinOp.operator == BINOP_DEREF
&& s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) { && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_DEREF) {
s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to); s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to);
this->effective = 1; this->effective = 1;
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF && !is_xop(s->stmtAssign.what)) { } else if(s->stmtAssign.what->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.what->exprBinOp.operator == BINOP_DEREF && !is_xop(s->stmtAssign.what)) {
s->stmtAssign.what->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what->exprUnOp.operand); s->stmtAssign.what->exprBinOp.operands[0] = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what->exprBinOp.operands[0]);
mark_ptr(s->stmtAssign.what->exprUnOp.operand); mark_ptr(s->stmtAssign.what->exprBinOp.operands[0]);
this->effective = 1; this->effective = 1;
@@ -369,10 +369,10 @@ static void normalize_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AS
this->effective = 1; this->effective = 1;
} else if(is_xop(s->stmtAssign.to) == XOP_NOT_XOP) { } else if(is_xop(s->stmtAssign.to) == XOP_NOT_XOP) {
if(s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) { if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprUnOp.operator == BINOP_DEREF) {
s->stmtAssign.to->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprUnOp.operand); s->stmtAssign.to->exprBinOp.operands[0] = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[0]);
mark_ptr(s->stmtAssign.to->exprUnOp.operand); mark_ptr(s->stmtAssign.to->exprBinOp.operands[0]);
this->effective = 1; this->effective = 1;
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) { } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) {
@@ -475,8 +475,8 @@ static void normalize_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AS
static void pre_norm_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { static void pre_norm_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
AST *n = *nptr; AST *n = *nptr;
if(n == ud) { if(n->nodeKind == AST_CHUNK) {
if(tlc->chunk.functionType) { if(n->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
@@ -500,11 +500,11 @@ static void pre_norm_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A
sum->operands[1] = (AST*) offset; sum->operands[1] = (AST*) offset;
sum->operator = BINOP_ADD; sum->operator = BINOP_ADD;
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref)); ASTExprBinaryOp *deref = calloc(1, sizeof(*deref));
deref->nodeKind = AST_EXPR_UNARY_OP; deref->nodeKind = AST_EXPR_BINARY_OP;
deref->type = vte->type; deref->type = vte->type;
deref->operand = (AST*) sum; deref->operands[0] = (AST*) sum;
deref->operator = UNOP_DEREF; deref->operator = BINOP_DEREF;
ASTExprVar *evar = calloc(1, sizeof(*evar)); ASTExprVar *evar = calloc(1, sizeof(*evar));
evar->nodeKind = AST_EXPR_VAR; evar->nodeKind = AST_EXPR_VAR;
@@ -517,6 +517,7 @@ static void pre_norm_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A
ass->what = (AST*) evar; ass->what = (AST*) evar;
ass->to = ast_cast_expr((AST*) deref, vte->type); // Must cast because of "convention correctness" ass->to = ast_cast_expr((AST*) deref, vte->type); // Must cast because of "convention correctness"
ass->next = n->chunk.statementFirst; ass->next = n->chunk.statementFirst;
vte->data.var.declaration = (AST*) ass;
if(n->chunk.statementFirst) { if(n->chunk.statementFirst) {
n->chunk.statementFirst = ass; n->chunk.statementFirst = ass;
@@ -530,8 +531,6 @@ static void pre_norm_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A
} }
static void decompose_symbol_record_field_access(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { static void decompose_symbol_record_field_access(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
if(tlc != (AST*) ud) return;
AST *n = *nptr; AST *n = *nptr;
if(n->nodeKind == AST_EXPR_DOT) { if(n->nodeKind == AST_EXPR_DOT) {
@@ -564,11 +563,11 @@ static void decompose_symbol_record_field_access(AST **nptr, AST *stmt, AST *stm
AST *cast = ast_cast_expr((AST*) sum, type_pointer_wrap(n->exprDot.a->expression.type->record.fieldTypes[f])); AST *cast = ast_cast_expr((AST*) sum, type_pointer_wrap(n->exprDot.a->expression.type->record.fieldTypes[f]));
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref)); ASTExprBinaryOp *deref = calloc(1, sizeof(*deref));
deref->nodeKind = AST_EXPR_UNARY_OP; deref->nodeKind = AST_EXPR_BINARY_OP;
deref->type = cast->expression.type->pointer.of; deref->type = cast->expression.type->pointer.of;
deref->operator = UNOP_DEREF; deref->operator = BINOP_DEREF;
deref->operand = cast; deref->operands[0] = cast;
*nptr = (AST*) deref; *nptr = (AST*) deref;
} }
@@ -590,8 +589,6 @@ struct DenoopState {
static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
struct DenoopState *state = ud; struct DenoopState *state = ud;
if(state->targetTLC != tlc) return;
AST *n = *nptr; AST *n = *nptr;
bool *success = &state->success; bool *success = &state->success;
@@ -605,13 +602,13 @@ static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST
prim->val = ntc_get_int_default("null", 0); prim->val = ntc_get_int_default("null", 0);
*nptr = (AST*) prim; *nptr = (AST*) prim;
} else if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_REF && n->exprUnOp.operand->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operand->exprUnOp.operator == UNOP_DEREF) { } else if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_REF && n->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && n->exprUnOp.operand->exprBinOp.operator == BINOP_DEREF) {
// Turn `&*a` into `a` // Turn `&*a` into `a`
// Artificially change type of casted expression to keep types valid for subsequent passes // Artificially change type of casted expression to keep types valid for subsequent passes
n->exprUnOp.operand->exprUnOp.operand->expression.type = n->expression.type; n->exprUnOp.operand->exprBinOp.operands[0]->expression.type = n->expression.type;
*nptr = n->exprUnOp.operand->exprUnOp.operand; *nptr = n->exprUnOp.operand->exprBinOp.operands[0];
*success = true; *success = true;
} else if(is_double_field_access(n)) { } else if(is_double_field_access(n)) {
@@ -752,10 +749,6 @@ void ast_denoop(AST *tlc, AST **node) {
* TODO: convert records to proper form also. * TODO: convert records to proper form also.
*/ */
static void convention_correctness_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { static void convention_correctness_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
if(tlc != ud) {
return;
}
AST *n = *nptr; AST *n = *nptr;
if(n->nodeKind == AST_EXPR_CALL) { if(n->nodeKind == AST_EXPR_CALL) {
@@ -775,10 +768,23 @@ static void convention_correctness_visitor(AST **nptr, AST *stmt, AST *stmtPrev,
} }
} }
static void decompose_segmented_dereferences(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
AST *n = *nptr;
if(n->nodeKind == AST_EXPR_BINARY_OP && n->exprBinOp.operator == BINOP_DEREF && n->exprBinOp.operands[1]) {
AST *seg = n->exprBinOp.operands[1];
if(seg->nodeKind != AST_EXPR_VAR || seg->exprVar.thing->kind != SCOPEITEM_VAR || seg->exprVar.thing->data.var.registerClass != REG_CLASS_DATASEGS) {
seg = n->exprBinOp.operands[1] = varify(tlc, chunk, stmtPrev, stmt, seg);
seg->exprVar.thing->data.var.preclassed = true;
seg->exprVar.thing->data.var.registerClass = REG_CLASS_DATASEGS;
}
}
}
void arch_normalize_pre(AST *tlc) { void arch_normalize_pre(AST *tlc) {
generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, convention_correctness_visitor, NULL); generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, convention_correctness_visitor, NULL);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, pre_norm_visitor, NULL); generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, pre_norm_visitor, NULL);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, decompose_symbol_record_field_access, NULL); generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, decompose_symbol_record_field_access, NULL);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, decompose_segmented_dereferences, NULL);
for(size_t t = 0; t < tlc->chunk.varCount;) { for(size_t t = 0; t < tlc->chunk.varCount;) {
if(ast_is_scopeitem_referenced(tlc, tlc->chunk.vars[t]) || tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) { if(ast_is_scopeitem_referenced(tlc, tlc->chunk.vars[t]) || tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) {