diff --git a/src/cg.c b/src/cg.c index 3659817..83c91bc 100644 --- a/src/cg.c +++ b/src/cg.c @@ -5,6 +5,8 @@ #include #include +#include"x86.h" + #define REGS 4 static const char *regs[REGS][3] = {{"al", "ax", "eax"}, {"bl", "bx", "ebx"}, {"cl", "cx", "ecx"}, {"dl", "dx", "edx"}}; @@ -51,7 +53,7 @@ static const char *specexpr(AST *e) { return spec(type_size(e->expression.type)); } -static const char *xv(VarTableEntry *v) { +static const char *xv_sz(VarTableEntry *v, int sz) { assert(v->kind == VARTABLEENTRY_VAR); #define XVBUFS 8 @@ -64,7 +66,7 @@ static const char *xv(VarTableEntry *v) { #ifdef DEBUG snprintf(ret, XVBUFSZ, "@%i", v->data.var.color); #else - snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(type_size(v->type))]); + snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(sz)]); #endif bufidx = (bufidx + 1) % XVBUFS; @@ -72,6 +74,10 @@ static const char *xv(VarTableEntry *v) { return ret; } +static const char *xv(VarTableEntry *v) { + return xv_sz(v, type_size(v->type)); +} + static const char *xj(BinaryOp op) { switch(op) { case BINOP_EQUAL: return "e"; @@ -80,7 +86,7 @@ static const char *xj(BinaryOp op) { } } -static const char *xop(AST *e) { +static const char *xop_sz(AST *e, int sz) { #define XOPBUFS 16 #define XOPBUFSZ 24 static char bufs[XOPBUFS][XOPBUFSZ]; @@ -92,25 +98,32 @@ static const char *xop(AST *e) { VarTableEntry *v = e->exprVar.thing; if(v->kind == VARTABLEENTRY_VAR) { - return xv(v); + return xv_sz(v, sz); } else if(v->kind == VARTABLEENTRY_SYMBOL) { snprintf(ret, XOPBUFSZ, "[%s]", v->data.symbol.name); } else abort(); } else if(e->nodeKind == AST_EXPR_PRIMITIVE) { snprintf(ret, XOPBUFSZ, "%i", e->exprPrim.val); + } 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 && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { + snprintf(ret, XOPBUFSZ, "%s [%s + %s]", + spec(sz), + xv_sz(e->exprUnOp.operand->exprBinOp.operands[0]->exprVar.thing, 4), + xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing, 4)); } 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 && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { - snprintf(ret, XOPBUFSZ, "[%s + %s]", + snprintf(ret, XOPBUFSZ, "%s [%s + %s]", + spec(sz), e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, - xv(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing)); + xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing, 4)); } 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 && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { - snprintf(ret, XOPBUFSZ, "[%s + %i * %s]", + snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]", + spec(sz), e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val, - xv(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing)); + xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 4)); } 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); } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_VAR) { - snprintf(ret, XOPBUFSZ, "[%s]", xv(e->exprUnOp.operand->exprVar.thing)); + snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(e->exprUnOp.operand->exprVar.thing, 4)); } else { return NULL; } @@ -120,6 +133,10 @@ static const char *xop(AST *e) { return ret; } +static const char *xop(AST *e) { + return xop_sz(e, type_size(e->expression.type)); +} + void cg_chunk(AST *a) { AST *s = a->chunk.statementFirst; @@ -201,9 +218,24 @@ void cg_chunk(AST *a) { s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing)); + } else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR) { + + printf("lea %s, [%s + %i]\n", + xv_sz(s->stmtAssign.what->exprVar.thing, 4), + xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 4), + s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val); + + } else if(is_xop(s->stmtAssign.what) != NULL && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprUnOp.operand)) { + + printf("neg %s\n", xop(s->stmtAssign.what)); + } else { - printf("mov %s, %s\n", xop(s->stmtAssign.what), xop(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(s->stmtAssign.what, 4), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); + } else { + printf("mov %s, %s\n", xop(s->stmtAssign.what), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); + } } } @@ -241,7 +273,7 @@ void cg_chunk(AST *a) { size_t lbl = nextLocalLabel++; - printf("cmp %s %s, %s\n", specexpr(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[1])); + printf("cmp %s, %s\n", xop(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[1])); printf("j%s .L%lu\n", xj(binop_comp_opposite(s->stmtIf.expression->exprBinOp.operator)), lbl); cg_chunk(s->stmtIf.then); @@ -363,4 +395,4 @@ nextColor:; cg_chunk(a); free(vars); -} \ No newline at end of file +} diff --git a/src/dumberdowner.c b/src/dumberdowner.c index deee75a..924ebc9 100644 --- a/src/dumberdowner.c +++ b/src/dumberdowner.c @@ -11,37 +11,7 @@ // This pass, along with CG is strictly dependent on x86 and will fail for // any other architecture. -// Can expression be expressed as a single x86 operand? -#define XOP_NOT_XOP 0 -#define XOP_NOT_MEM 1 -#define XOP_MEM 2 -static int is_xop(AST *e) { - if(e->nodeKind == AST_EXPR_PRIMITIVE) { - return XOP_NOT_MEM; - } else if(e->nodeKind == AST_EXPR_VAR) { - return e->exprVar.thing->kind == VARTABLEENTRY_VAR ? XOP_NOT_MEM : XOP_MEM; - } 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; - } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { - AST *c = e->exprUnOp.operand; - - if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_VAR) { - return XOP_MEM; - } else if(c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && c->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && c->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR) { - if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { - return XOP_MEM; - } else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && c->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && c->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { - int scale = c->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val; - - if(scale == 1 || scale == 2 || scale == 4 || scale == 8) { - return XOP_MEM; - } - } - } - } - - return XOP_NOT_XOP; -} +#include"x86.h" static void varify_change_usedefs(AST *e, AST *oldStmt, AST *newStmt) { if(e->nodeKind == AST_EXPR_VAR) { @@ -185,6 +155,28 @@ static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) { return varify(tlc, chunk, stmtPrev, stmt, e); } +static UseDef *get_last_usedef_before_stmt(AST *tlc, VarTableEntry *v, AST *stmt) { + assert(v->kind == VARTABLEENTRY_VAR); + + UseDef *ud = v->data.var.usedefFirst; + + if(!ud) { + return NULL; + } + + UseDef *udPrev = NULL; + + while(ud) { + if(ast_stmt_is_after(tlc, ud->stmt, stmt)) { + break; + } + udPrev = ud; + ud = ud->next; + } + + return udPrev; +} + static int dumben_chunk(AST *tlc, AST *chu) { AST *sPrev = NULL; AST *s = chu->chunk.statementFirst; @@ -238,6 +230,59 @@ static int dumben_chunk(AST *tlc, AST *chu) { effective = 1; } + if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && (s->stmtAssign.to->exprUnOp.operand->nodeKind != AST_EXPR_VAR || s->stmtAssign.what->exprVar.thing != s->stmtAssign.to->exprUnOp.operand->exprVar.thing)) { + // Turn this: + // a = -b + // into + // a = b + // a = -a + // While keeping UD-chain valid. + + // Currently only for variables. While this could work for any XOP, it requires the ability to deep-copy `a`, which is not trivial when taking into account UD-chains. + // TODO: Scrap incremental UD-chain modifications. Simply rebuild them after each pass. + + ASTExprVar *ev[2]; + for(int i = 0; i < 2; i++) { + ev[i] = malloc(sizeof(ASTExprVar)); + ev[i]->nodeKind = AST_EXPR_VAR; + ev[i]->type = s->stmtAssign.what->expression.type; + ev[i]->thing = s->stmtAssign.what->exprVar.thing; + } + + AST *negation = s->stmtAssign.to; + + s->stmtAssign.to = negation->exprUnOp.operand; + negation->exprUnOp.operand = ev[0]; + + AST *assign2 = malloc(sizeof(ASTStmtAssign)); + assign2->nodeKind = AST_STMT_ASSIGN; + assign2->stmtAssign.what = ev[1]; + assign2->stmtAssign.to = negation; + + assign2->statement.next = s->statement.next; + s->statement.next = assign2; + + UseDef *link = get_last_usedef_before_stmt(tlc, ev[0]->thing, assign2->statement.next); + + UseDef *ud[2]; + ud[0] = malloc(sizeof(UseDef)); + ud[1] = malloc(sizeof(UseDef)); + + ud[0]->stmt = assign2; + ud[0]->use = (AST*) ev[1]; + ud[0]->def = s; + ud[0]->next = ud[1]; + + ud[1]->stmt = assign2; + ud[1]->use = (AST*) ev[0]; + ud[1]->def = s; + ud[1]->next = link->next; + + link->next = ud[0]; + + effective = 1; + } + } else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) { int argCount = s->stmtExpr.expr->exprCall.what->expression.type->function.argCount; @@ -260,4 +305,4 @@ static int dumben_chunk(AST *tlc, AST *chu) { void dumben_go(AST* tlc) { while(dumben_chunk(tlc, tlc)); -} \ No newline at end of file +} diff --git a/src/parse.c b/src/parse.c index fa1f175..18e97eb 100644 --- a/src/parse.c +++ b/src/parse.c @@ -285,6 +285,10 @@ AST *nct_parse_expression(Parser *P, int lOP) { ret->length = tok.length; return (AST*) ret; + } else if(maybe(P, TOKEN_PAREN_L)) { + AST *e = nct_parse_expression(P, 0); + expect(P, TOKEN_PAREN_R); + return e; } } else if(lOP == 4) { if(maybe(P, TOKEN_STAR)) { diff --git a/tests/bit-rounding.nct b/tests/bit-rounding.nct index f90f904..dae6e2d 100644 --- a/tests/bit-rounding.nct +++ b/tests/bit-rounding.nct @@ -1,2 +1,6 @@ u32 x: 123; -u33 y: 5; \ No newline at end of file +u33 y: 5; + +u3 *o = 5000; +u3 z = *o; +u3 p = *(o + z); diff --git a/tests/if.nct b/tests/if.nct index e588179..2999068 100644 --- a/tests/if.nct +++ b/tests/if.nct @@ -2,10 +2,11 @@ u16 x: 5; loop { u16* y = 257; u9 w = -4; - u4 z = 3 + *y; + u16 p = *y; + u4 z = p + 3; u2 o = -w; if(x != 0) { break; } -} \ No newline at end of file +} diff --git a/tests/loopregalloc.nct b/tests/loopregalloc.nct index 332c793..02c685d 100644 --- a/tests/loopregalloc.nct +++ b/tests/loopregalloc.nct @@ -4,4 +4,6 @@ loop { a = 3; u8 b = 1; + + u8 c = 2; } \ No newline at end of file diff --git a/tests/scoping.nct b/tests/scoping.nct index df82ea2..06cd85b 100644 --- a/tests/scoping.nct +++ b/tests/scoping.nct @@ -1,5 +1,5 @@ u8 a = 5; -if(a) { +if(a != 0) { u8 a = 10; /* Should not cause scoping errors. */ } -u8 b = 15; /* `a` in the if statement scope should be free'd. */ \ No newline at end of file +u8 b = 15; /* `a` in the if statement scope should be free'd. */