Support negation, parentheses. Always zero-extend registers for bugless memory operand usage
This commit is contained in:
parent
fa40a78546
commit
012320569e
56
src/cg.c
56
src/cg.c
@ -5,6 +5,8 @@
|
||||
#include<string.h>
|
||||
#include<assert.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -1,2 +1,6 @@
|
||||
u32 x: 123;
|
||||
u33 y: 5;
|
||||
u33 y: 5;
|
||||
|
||||
u3 *o = 5000;
|
||||
u3 z = *o;
|
||||
u3 p = *(o + z);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,4 +4,6 @@ loop {
|
||||
a = 3;
|
||||
|
||||
u8 b = 1;
|
||||
|
||||
u8 c = 2;
|
||||
}
|
@ -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. */
|
||||
u8 b = 15; /* `a` in the if statement scope should be free'd. */
|
||||
|
Loading…
Reference in New Issue
Block a user