update
This commit is contained in:
parent
390c4c954d
commit
17a0c9d902
114
src/ast.c
114
src/ast.c
@ -10,6 +10,74 @@ const char *AST_KIND_STR[] = {
|
|||||||
AST_KINDS(GEN_STRI)
|
AST_KINDS(GEN_STRI)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, void(*handler)(AST**, AST*, AST*, AST*, AST*, void*)) {
|
||||||
|
handler(nptr, stmt, stmtPrev, chu, tlc, ud);
|
||||||
|
|
||||||
|
AST *n = *nptr;
|
||||||
|
|
||||||
|
if(n->nodeKind == AST_CHUNK) {
|
||||||
|
AST *sPrev = NULL;
|
||||||
|
AST **s = &n->chunk.statementFirst;
|
||||||
|
while(*s) {
|
||||||
|
generic_visitor(s, *s, sPrev, n, tlc, ud, handler);
|
||||||
|
|
||||||
|
sPrev = *s;
|
||||||
|
s = &sPrev->statement.next;
|
||||||
|
}
|
||||||
|
} else if(n->nodeKind == AST_STMT_ASSIGN) {
|
||||||
|
generic_visitor(&n->stmtAssign.what, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
generic_visitor(&n->stmtAssign.to, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
} else if(n->nodeKind == AST_STMT_IF) {
|
||||||
|
generic_visitor(&n->stmtIf.expression, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
generic_visitor(&n->stmtIf.then, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
} else if(n->nodeKind == AST_STMT_LOOP) {
|
||||||
|
generic_visitor(&n->stmtLoop.body, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
} else if(n->nodeKind == AST_STMT_BREAK) {
|
||||||
|
} else if(n->nodeKind == AST_STMT_CONTINUE) {
|
||||||
|
} else if(n->nodeKind == AST_STMT_EXT_ALIGN) {
|
||||||
|
} else if(n->nodeKind == AST_STMT_DECL) {
|
||||||
|
if(n->stmtDecl.expression) {
|
||||||
|
generic_visitor(&n->stmtDecl.expression, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
}
|
||||||
|
} else if(n->nodeKind == AST_STMT_EXPR) {
|
||||||
|
generic_visitor(&n->stmtExpr.expr, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
} else if(n->nodeKind == AST_STMT_EXT_ORG) {
|
||||||
|
} else if(n->nodeKind == AST_STMT_EXT_SECTION) {
|
||||||
|
} else if(n->nodeKind == AST_STMT_RETURN) {
|
||||||
|
if(n->stmtReturn.val) {
|
||||||
|
generic_visitor(&n->stmtReturn.val, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
}
|
||||||
|
} else if(n->nodeKind == AST_EXPR_BINARY_OP) {
|
||||||
|
generic_visitor(&n->exprBinOp.operands[0], stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
generic_visitor(&n->exprBinOp.operands[1], stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
} else if(n->nodeKind == AST_EXPR_CALL) {
|
||||||
|
generic_visitor(&n->exprCall.what, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < n->exprCall.what->expression.type->function.argCount; i++) {
|
||||||
|
generic_visitor(&n->exprCall.args[i], stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
}
|
||||||
|
} else if(n->nodeKind == AST_EXPR_CAST) {
|
||||||
|
generic_visitor(&n->exprCast.what, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
} else if(n->nodeKind == AST_EXPR_FUNC) {
|
||||||
|
generic_visitor(&n->exprFunc.chunk, NULL, NULL, n->exprFunc.chunk, n->exprFunc.chunk, ud, handler);
|
||||||
|
} else if(n->nodeKind == AST_EXPR_UNARY_OP) {
|
||||||
|
generic_visitor(&n->exprUnOp.operand, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
} else if(n->nodeKind == AST_EXPR_VAR) {
|
||||||
|
} else if(n->nodeKind == AST_EXPR_STACK_POINTER) {
|
||||||
|
} else if(n->nodeKind == AST_EXPR_PRIMITIVE) {
|
||||||
|
} else if(n->nodeKind == AST_EXPR_STRING_LITERAL) {
|
||||||
|
} else if(n->nodeKind == AST_EXPR_ARRAY) {
|
||||||
|
assert(n->expression.type->type == TYPE_TYPE_ARRAY);
|
||||||
|
assert(n->expression.type->array.length != 0);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < n->expression.type->array.length; i++) {
|
||||||
|
generic_visitor(&n->exprArray.items[i], stmt, stmtPrev, chu, tlc, ud, handler);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AST *ast_expression_optimize(AST *ast) {
|
AST *ast_expression_optimize(AST *ast) {
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
@ -344,7 +412,7 @@ static char *cat(char *a, const char *b) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((format(printf, 1, 2))) static 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);
|
||||||
va_copy(v2, v1);
|
va_copy(v2, v1);
|
||||||
@ -442,6 +510,18 @@ static char *ast_dumpe(AST *e) {
|
|||||||
case BINOP_NEQUAL:
|
case BINOP_NEQUAL:
|
||||||
op = "!=";
|
op = "!=";
|
||||||
break;
|
break;
|
||||||
|
case BINOP_LESS:
|
||||||
|
op = "<";
|
||||||
|
break;
|
||||||
|
case BINOP_GREATER:
|
||||||
|
op = ">";
|
||||||
|
break;
|
||||||
|
case BINOP_LEQUAL:
|
||||||
|
op = "<=";
|
||||||
|
break;
|
||||||
|
case BINOP_GEQUAL:
|
||||||
|
op = ">=";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -476,6 +556,19 @@ static char *ast_dumpe(AST *e) {
|
|||||||
out = out2;
|
out = out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
} else if(e->nodeKind == AST_EXPR_CALL) {
|
||||||
|
char *w = ast_dumpe(e->exprCall.what);
|
||||||
|
char *out = malp("%s(", w);
|
||||||
|
free(w);
|
||||||
|
size_t argCount = e->exprCall.what->expression.type->function.argCount;
|
||||||
|
for(size_t i = 0; i < argCount; i++) {
|
||||||
|
char *a = ast_dumpe(e->exprCall.args[i]);
|
||||||
|
char *out2 = malp(i == argCount - 1 ? "%s%s)" : "%s%s, ", out, a);
|
||||||
|
free(a);
|
||||||
|
free(out);
|
||||||
|
out = out2;
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,12 +590,19 @@ static char *ast_dumps(AST *s) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
||||||
char *a = ast_dumpe(s->stmtAssign.what);
|
if(s->stmtAssign.to) {
|
||||||
char *b = ast_dumpe(s->stmtAssign.to);
|
char *a = ast_dumpe(s->stmtAssign.what);
|
||||||
char *r = malp("%s = %s;\n", a, b);
|
char *b = ast_dumpe(s->stmtAssign.to);
|
||||||
free(a);
|
char *r = malp("%s = %s;\n", a, b);
|
||||||
free(b);
|
free(a);
|
||||||
return r;
|
free(b);
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
char *a = ast_dumpe(s->stmtAssign.what);
|
||||||
|
char *r = malp("%s = ; /* fake def */\n", a);
|
||||||
|
free(a);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
} else if(s->nodeKind == AST_STMT_LOOP) {
|
} else if(s->nodeKind == AST_STMT_LOOP) {
|
||||||
char *inner = ast_dump(s->stmtLoop.body);
|
char *inner = ast_dump(s->stmtLoop.body);
|
||||||
char *c = malp("loop {\n%s}\n", inner);
|
char *c = malp("loop {\n%s}\n", inner);
|
||||||
|
22
src/ast.h
22
src/ast.h
@ -57,17 +57,22 @@ typedef enum ENUMPAK {
|
|||||||
BINOP_BITWISE_OR = 3,
|
BINOP_BITWISE_OR = 3,
|
||||||
BINOP_BITWISE_XOR = 4,
|
BINOP_BITWISE_XOR = 4,
|
||||||
BINOP_SIMPLES = 5,
|
BINOP_SIMPLES = 5,
|
||||||
|
|
||||||
BINOP_MUL = 5,
|
BINOP_MUL = 5,
|
||||||
BINOP_DIV = 6,
|
BINOP_DIV = 6,
|
||||||
|
|
||||||
BINOP_EQUAL = 7,
|
BINOP_EQUAL = 7,
|
||||||
BINOP_NEQUAL = 8,
|
BINOP_NEQUAL = 8,
|
||||||
|
BINOP_LESS = 9,
|
||||||
|
BINOP_GREATER = 10,
|
||||||
|
BINOP_LEQUAL = 11,
|
||||||
|
BINOP_GEQUAL = 12,
|
||||||
|
|
||||||
BINOP_WTF = 999,
|
BINOP_WTF = 999,
|
||||||
} BinaryOp;
|
} BinaryOp;
|
||||||
|
|
||||||
static inline int binop_is_comparison(BinaryOp op) {
|
static inline int binop_is_comparison(BinaryOp op) {
|
||||||
return op == BINOP_EQUAL || op == BINOP_NEQUAL;
|
return op == BINOP_EQUAL || op == BINOP_NEQUAL || op == BINOP_LESS || op == BINOP_GREATER || op == BINOP_LEQUAL || op == BINOP_GEQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline BinaryOp binop_comp_opposite(BinaryOp op) {
|
static inline BinaryOp binop_comp_opposite(BinaryOp op) {
|
||||||
@ -75,6 +80,14 @@ static inline BinaryOp binop_comp_opposite(BinaryOp op) {
|
|||||||
return BINOP_NEQUAL;
|
return BINOP_NEQUAL;
|
||||||
} else if(op == BINOP_NEQUAL) {
|
} else if(op == BINOP_NEQUAL) {
|
||||||
return BINOP_EQUAL;
|
return BINOP_EQUAL;
|
||||||
|
} else if(op == BINOP_LESS) {
|
||||||
|
return BINOP_GEQUAL;
|
||||||
|
} else if(op == BINOP_GREATER) {
|
||||||
|
return BINOP_LEQUAL;
|
||||||
|
} else if(op == BINOP_LEQUAL) {
|
||||||
|
return BINOP_GREATER;
|
||||||
|
} else if(op == BINOP_GEQUAL) {
|
||||||
|
return BINOP_LESS;
|
||||||
}
|
}
|
||||||
return BINOP_WTF;
|
return BINOP_WTF;
|
||||||
}
|
}
|
||||||
@ -187,6 +200,9 @@ typedef struct {
|
|||||||
union AST *statementLast;
|
union AST *statementLast;
|
||||||
|
|
||||||
size_t stackReservation;
|
size_t stackReservation;
|
||||||
|
|
||||||
|
/* NULL unless this is a top-level chunk belonging to a function */
|
||||||
|
Type *functionType;
|
||||||
} ASTChunk;
|
} ASTChunk;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -293,6 +309,8 @@ typedef union AST {
|
|||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, void(*handler)(AST**, AST*, AST*, AST*, AST*, void*));
|
||||||
|
|
||||||
AST *ast_expression_optimize(AST*);
|
AST *ast_expression_optimize(AST*);
|
||||||
int ast_expression_equal(AST*, AST*);
|
int ast_expression_equal(AST*, AST*);
|
||||||
|
|
||||||
@ -304,4 +322,6 @@ char *ast_dump(AST *tlc);
|
|||||||
|
|
||||||
AST *ast_deep_copy(AST*);
|
AST *ast_deep_copy(AST*);
|
||||||
|
|
||||||
|
__attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
471
src/cg.c
471
src/cg.c
@ -10,9 +10,9 @@
|
|||||||
#define REGS 4
|
#define REGS 4
|
||||||
static const char *regs[][3] = {
|
static const char *regs[][3] = {
|
||||||
[COLOR_EAX] = {"al", "ax", "eax"},
|
[COLOR_EAX] = {"al", "ax", "eax"},
|
||||||
[COLOR_EBX] = {"bl", "bx", "ebx"},
|
|
||||||
[COLOR_ECX] = {"cl", "cx", "ecx"},
|
[COLOR_ECX] = {"cl", "cx", "ecx"},
|
||||||
[COLOR_EDX] = {"dl", "dx", "edx"},
|
[COLOR_EDX] = {"dl", "dx", "edx"},
|
||||||
|
[COLOR_EBX] = {"bl", "bx", "ebx"},
|
||||||
{"fu", "fk", "fck"}
|
{"fu", "fk", "fck"}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -25,6 +25,10 @@ typedef struct {
|
|||||||
size_t loopStackStart[LOOPSTACKSIZE];
|
size_t loopStackStart[LOOPSTACKSIZE];
|
||||||
size_t loopStackEnd[LOOPSTACKSIZE];
|
size_t loopStackEnd[LOOPSTACKSIZE];
|
||||||
size_t loopStackIdx;
|
size_t loopStackIdx;
|
||||||
|
|
||||||
|
int isFunction;
|
||||||
|
|
||||||
|
AST *tlc;
|
||||||
} CGState;
|
} CGState;
|
||||||
|
|
||||||
static const char *direct(int size) {
|
static const char *direct(int size) {
|
||||||
@ -93,11 +97,15 @@ static const char *xj(BinaryOp op) {
|
|||||||
switch(op) {
|
switch(op) {
|
||||||
case BINOP_EQUAL: return "e";
|
case BINOP_EQUAL: return "e";
|
||||||
case BINOP_NEQUAL: return "ne";
|
case BINOP_NEQUAL: return "ne";
|
||||||
|
case BINOP_LESS: return "b";
|
||||||
|
case BINOP_GREATER: return "a";
|
||||||
|
case BINOP_LEQUAL: return "be";
|
||||||
|
case BINOP_GEQUAL: return "ae";
|
||||||
default: return "wtf";
|
default: return "wtf";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *xop_sz(AST *e, int sz) {
|
static const char *xop_sz(AST *tlc, AST *e, int sz) {
|
||||||
#define XOPBUFS 16
|
#define XOPBUFS 16
|
||||||
#define XOPBUFSZ 24
|
#define XOPBUFSZ 24
|
||||||
static char bufs[XOPBUFS][XOPBUFSZ];
|
static char bufs[XOPBUFS][XOPBUFSZ];
|
||||||
@ -106,7 +114,7 @@ static const char *xop_sz(AST *e, int sz) {
|
|||||||
char *ret = bufs[bufidx];
|
char *ret = bufs[bufidx];
|
||||||
|
|
||||||
if(e->nodeKind == AST_EXPR_STACK_POINTER) {
|
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) {
|
||||||
VarTableEntry *v = e->exprVar.thing;
|
VarTableEntry *v = e->exprVar.thing;
|
||||||
|
|
||||||
@ -127,6 +135,11 @@ static const char *xop_sz(AST *e, int sz) {
|
|||||||
spec(sz),
|
spec(sz),
|
||||||
e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||||
xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->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_PRIMITIVE && 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) {
|
||||||
|
snprintf(ret, XOPBUFSZ, "%s [%s + %i]",
|
||||||
|
spec(sz),
|
||||||
|
e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||||
|
e->exprUnOp.operand->exprBinOp.operands[1]->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_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) {
|
} 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 [%s + %i * %s]",
|
snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]",
|
||||||
spec(sz),
|
spec(sz),
|
||||||
@ -138,7 +151,7 @@ static const char *xop_sz(AST *e, int sz) {
|
|||||||
} 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) {
|
} 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 [%s]", spec(sz), xv_sz(e->exprUnOp.operand->exprVar.thing, 4));
|
snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(e->exprUnOp.operand->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 == UNOP_DEREF && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
|
} 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 == UNOP_DEREF && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
|
||||||
snprintf(ret, XOPBUFSZ, "[esp + %i]", e->exprUnOp.operand->exprBinOp.operands[1]->exprPrim.val);
|
snprintf(ret, XOPBUFSZ, "[esp + %i]", e->exprUnOp.operand->exprBinOp.operands[1]->exprPrim.val + tlc->chunk.stackReservation);
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -148,8 +161,8 @@ static const char *xop_sz(AST *e, int sz) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *xop(AST *e) {
|
static const char *xop(AST *tlc, AST *e) {
|
||||||
return xop_sz(e, type_size(e->expression.type));
|
return xop_sz(tlc, e, type_size(e->expression.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
void cg_chunk(CGState *cg, AST *a) {
|
void cg_chunk(CGState *cg, AST *a) {
|
||||||
@ -211,7 +224,10 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
|
|
||||||
assert(s->stmtDecl.expression->nodeKind == AST_EXPR_FUNC);
|
assert(s->stmtDecl.expression->nodeKind == AST_EXPR_FUNC);
|
||||||
|
|
||||||
cg_go(s->stmtDecl.expression->exprFunc.chunk);
|
dumben_go(s->stmtDecl.expression->exprFunc.chunk);
|
||||||
|
while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) {
|
||||||
|
dumben_go(s->stmtDecl.expression->exprFunc.chunk);
|
||||||
|
}
|
||||||
|
|
||||||
} else abort();
|
} else abort();
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
@ -221,7 +237,7 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
} else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.to && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
||||||
|
|
||||||
AST *e = s->stmtAssign.to;
|
AST *e = s->stmtAssign.to;
|
||||||
|
|
||||||
@ -233,7 +249,7 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
size_t argSize = 0;
|
size_t argSize = 0;
|
||||||
|
|
||||||
for(int i = argCount - 1; i >= 0; i--) {
|
for(int i = argCount - 1; i >= 0; i--) {
|
||||||
printf("push %s\n", xop_sz(e->exprCall.args[i], 4));
|
printf("push %s\n", xop_sz(cg->tlc, e->exprCall.args[i], 4));
|
||||||
|
|
||||||
argSize += (type_size(e->exprCall.args[i]->expression.type) + 3) & ~3;
|
argSize += (type_size(e->exprCall.args[i]->expression.type) + 3) & ~3;
|
||||||
}
|
}
|
||||||
@ -249,7 +265,7 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
|
|
||||||
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
||||||
|
|
||||||
if(is_xop(s->stmtAssign.what) == XOP_NOT_MEM && is_xop(s->stmtAssign.to) == XOP_NOT_MEM && !strcmp(xop(s->stmtAssign.what), xop(s->stmtAssign.to))) {
|
if(s->stmtAssign.to && is_xop(s->stmtAssign.what) == XOP_NOT_MEM && is_xop(s->stmtAssign.to) == XOP_NOT_MEM && !strcmp(xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to))) {
|
||||||
// It's a noop
|
// It's a noop
|
||||||
} else if(s->stmtAssign.to) {
|
} else if(s->stmtAssign.to) {
|
||||||
if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && (s->stmtAssign.to->exprBinOp.operator == BINOP_ADD || s->stmtAssign.to->exprBinOp.operator == BINOP_SUB) && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val == 1) {
|
if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && (s->stmtAssign.to->exprBinOp.operator == BINOP_ADD || s->stmtAssign.to->exprBinOp.operator == BINOP_SUB) && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val == 1) {
|
||||||
@ -257,11 +273,11 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
// inc or dec
|
// inc or dec
|
||||||
|
|
||||||
static const char *instrs[] = {"inc", "dec"};
|
static const char *instrs[] = {"inc", "dec"};
|
||||||
printf("%s %s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], specexpr(s->stmtAssign.what), xop(s->stmtAssign.what));
|
printf("%s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], xop(cg->tlc, s->stmtAssign.what));
|
||||||
|
|
||||||
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && s->stmtAssign.to->exprBinOp.operator < BINOP_SIMPLES) {
|
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && s->stmtAssign.to->exprBinOp.operator < BINOP_SIMPLES) {
|
||||||
|
|
||||||
printf("%s %s, %s\n", BINOP_SIMPLE_INSTRS[s->stmtAssign.to->exprBinOp.operator], xop(s->stmtAssign.what), xop(s->stmtAssign.to->exprBinOp.operands[1]));
|
printf("%s %s, %s\n", BINOP_SIMPLE_INSTRS[s->stmtAssign.to->exprBinOp.operator], xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to->exprBinOp.operands[1]));
|
||||||
|
|
||||||
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||||
|
|
||||||
@ -286,18 +302,18 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
|
|
||||||
} else if(is_xop(s->stmtAssign.what) != NULL && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprUnOp.operand)) {
|
} else if(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));
|
printf("neg %s\n", xop(cg->tlc, s->stmtAssign.what));
|
||||||
|
|
||||||
} else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST) {
|
} else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST) {
|
||||||
|
|
||||||
printf("movzx %s, %s\n", xop(s->stmtAssign.what), xop(s->stmtAssign.to->exprCast.what));
|
printf("movzx %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to->exprCast.what));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if(is_xop(s->stmtAssign.to) == XOP_MEM && type_size(s->stmtAssign.what->expression.type) != type_size(s->stmtAssign.to->expression.type)) {
|
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)));
|
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 {
|
} else {
|
||||||
printf("mov %s, %s\n", xop(s->stmtAssign.what), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type)));
|
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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -336,7 +352,7 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
|
|
||||||
size_t lbl = nextLocalLabel++;
|
size_t lbl = nextLocalLabel++;
|
||||||
|
|
||||||
printf("cmp %s, %s\n", xop(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[1]));
|
printf("cmp %s, %s\n", xop(cg->tlc, s->stmtIf.expression->exprBinOp.operands[0]), xop(cg->tlc, s->stmtIf.expression->exprBinOp.operands[1]));
|
||||||
printf("j%s .L%lu\n", xj(binop_comp_opposite(s->stmtIf.expression->exprBinOp.operator)), lbl);
|
printf("j%s .L%lu\n", xj(binop_comp_opposite(s->stmtIf.expression->exprBinOp.operator)), lbl);
|
||||||
|
|
||||||
cg_chunk(cg, s->stmtIf.then);
|
cg_chunk(cg, s->stmtIf.then);
|
||||||
@ -351,45 +367,131 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
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) {
|
||||||
|
printf("add esp, %lu\n", a->chunk.stackReservation);
|
||||||
|
}
|
||||||
|
|
||||||
printf("ret\n");
|
printf("ret\n");
|
||||||
|
|
||||||
|
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_VAR) {
|
||||||
|
|
||||||
|
/* Loop guard, probably. */
|
||||||
|
|
||||||
} else abort();
|
} else abort();
|
||||||
|
|
||||||
s = s->statement.next;
|
s = s->statement.next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Spill2StackState {
|
||||||
|
AST *targetTLC;
|
||||||
|
VarTableEntry *target;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Spill2VarState {
|
||||||
|
VarTableEntry *target;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
|
static size_t vidx = 0;
|
||||||
|
|
||||||
if(a->chunk.stackReservation) {
|
struct Spill2VarState *this = ud;
|
||||||
printf("add esp, %lu\n", a->chunk.stackReservation);
|
|
||||||
|
AST *a = *aptr;
|
||||||
|
|
||||||
|
if(a->nodeKind == AST_STMT_ASSIGN && a->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
||||||
|
assert(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
|
if(a->stmtAssign.what->exprVar.thing == this->target) {
|
||||||
|
|
||||||
|
VarTableEntry *new = calloc(1, sizeof(*new));
|
||||||
|
new->kind = VARTABLEENTRY_VAR;
|
||||||
|
new->type = a->stmtAssign.what->exprVar.thing->type;
|
||||||
|
new->data.var.name = malp("$s2v_%lu", vidx++);
|
||||||
|
|
||||||
|
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
|
||||||
|
tlc->chunk.vars[tlc->chunk.varCount - 1] = new;
|
||||||
|
|
||||||
|
ASTExprVar *ev0 = calloc(1, sizeof(*ev0));
|
||||||
|
ev0->nodeKind = AST_EXPR_VAR;
|
||||||
|
ev0->type = new->type;
|
||||||
|
ev0->thing = a->stmtAssign.what->exprVar.thing;
|
||||||
|
|
||||||
|
ASTExprVar *ev1 = calloc(1, sizeof(*ev1));
|
||||||
|
ev1->nodeKind = AST_EXPR_VAR;
|
||||||
|
ev1->type = new->type;
|
||||||
|
ev1->thing = new;
|
||||||
|
|
||||||
|
ASTStmtAssign *ass = calloc(1, sizeof(*ass));
|
||||||
|
ass->nodeKind = AST_STMT_ASSIGN;
|
||||||
|
ass->what = (AST*) ev0;
|
||||||
|
ass->to = (AST*) ev1;
|
||||||
|
|
||||||
|
a->stmtAssign.what->exprVar.thing = new;
|
||||||
|
|
||||||
|
ass->next = a->statement.next;
|
||||||
|
a->statement.next = (AST*) ass;
|
||||||
|
|
||||||
|
if(!ass->next) {
|
||||||
|
chunk->chunk.statementLast = (AST*) ass;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(a->nodeKind == AST_STMT_RETURN && a->stmtReturn.val && a->stmtReturn.val->nodeKind == AST_EXPR_VAR && a->stmtReturn.val->exprVar.thing == this->target) {
|
||||||
|
|
||||||
|
VarTableEntry *new = calloc(1, sizeof(*new));
|
||||||
|
new->kind = VARTABLEENTRY_VAR;
|
||||||
|
new->type = a->stmtReturn.val->exprVar.thing->type;
|
||||||
|
new->data.var.name = malp("$s2v_%lu", vidx++);
|
||||||
|
|
||||||
|
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
|
||||||
|
tlc->chunk.vars[tlc->chunk.varCount - 1] = new;
|
||||||
|
|
||||||
|
ASTExprVar *ev0 = calloc(1, sizeof(*ev0));
|
||||||
|
ev0->nodeKind = AST_EXPR_VAR;
|
||||||
|
ev0->type = new->type;
|
||||||
|
ev0->thing = a->stmtReturn.val->exprVar.thing;
|
||||||
|
|
||||||
|
ASTExprVar *ev1 = calloc(1, sizeof(*ev1));
|
||||||
|
ev1->nodeKind = AST_EXPR_VAR;
|
||||||
|
ev1->type = new->type;
|
||||||
|
ev1->thing = new;
|
||||||
|
|
||||||
|
ASTStmtAssign *ass = calloc(1, sizeof(*ass));
|
||||||
|
ass->nodeKind = AST_STMT_ASSIGN;
|
||||||
|
ass->what = (AST*) ev1;
|
||||||
|
ass->to = (AST*) ev0;
|
||||||
|
|
||||||
|
stmt->stmtReturn.val->exprVar.thing = new;
|
||||||
|
|
||||||
|
ass->next = stmt;
|
||||||
|
|
||||||
|
if(stmtPrev) {
|
||||||
|
stmtPrev->statement.next = (AST*) ass;
|
||||||
|
} else {
|
||||||
|
chunk->chunk.statementFirst = (AST*) ass;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MUST FIRST CALL with *aptr == tlc SO stackReservation IS UPDATED!!
|
static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
static void spill_pass(AST *tlc, AST **aptr, VarTableEntry *vte) {
|
struct Spill2StackState *this = ud;
|
||||||
|
|
||||||
|
if(tlc != this->targetTLC) {
|
||||||
|
// Don't do anything.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AST *a = *aptr;
|
AST *a = *aptr;
|
||||||
|
|
||||||
if(a->nodeKind == AST_CHUNK) {
|
if(a == tlc) {
|
||||||
for(AST **s = &a->chunk.statementFirst; *s; s = &((*s)->statement.next)) {
|
a->chunk.stackReservation += 4;
|
||||||
spill_pass(tlc, s, vte);
|
|
||||||
}
|
|
||||||
|
|
||||||
tlc->chunk.stackReservation += 4;
|
|
||||||
} else if(a->nodeKind == AST_STMT_IF) {
|
|
||||||
spill_pass(tlc, &a->stmtIf.expression, vte);
|
|
||||||
spill_pass(tlc, &a->stmtIf.then, vte);
|
|
||||||
} else if(a->nodeKind == AST_STMT_LOOP) {
|
|
||||||
spill_pass(tlc, &a->stmtLoop.body, vte);
|
|
||||||
} else if(a->nodeKind == AST_STMT_ASSIGN) {
|
|
||||||
spill_pass(tlc, &a->stmtAssign.what, vte);
|
|
||||||
|
|
||||||
if(a->stmtAssign.to) {
|
|
||||||
spill_pass(tlc, &a->stmtAssign.to, vte);
|
|
||||||
}
|
|
||||||
} else if(a->nodeKind == AST_STMT_EXPR) {
|
|
||||||
spill_pass(tlc, &a->stmtExpr.expr, vte);
|
|
||||||
} else if(a->nodeKind == AST_EXPR_VAR) {
|
} else if(a->nodeKind == AST_EXPR_VAR) {
|
||||||
|
|
||||||
if(a->exprVar.thing == vte) {
|
if(a->exprVar.thing == this->target) {
|
||||||
// FINALLY SPILL
|
// DO THE SPILL
|
||||||
|
|
||||||
ASTExprStackPointer *rsp = malloc(sizeof(*rsp));
|
ASTExprStackPointer *rsp = malloc(sizeof(*rsp));
|
||||||
rsp->nodeKind = AST_EXPR_STACK_POINTER;
|
rsp->nodeKind = AST_EXPR_STACK_POINTER;
|
||||||
@ -416,31 +518,6 @@ static void spill_pass(AST *tlc, AST **aptr, VarTableEntry *vte) {
|
|||||||
*aptr = (AST*) deref;
|
*aptr = (AST*) deref;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(a->nodeKind == AST_EXPR_BINARY_OP) {
|
|
||||||
spill_pass(tlc, &a->exprBinOp.operands[0], vte);
|
|
||||||
spill_pass(tlc, &a->exprBinOp.operands[1], vte);
|
|
||||||
} else if(a->nodeKind == AST_EXPR_UNARY_OP) {
|
|
||||||
spill_pass(tlc, &a->exprUnOp.operand, vte);
|
|
||||||
} else if(a->nodeKind == AST_EXPR_CALL) {
|
|
||||||
spill_pass(tlc, &a->exprCall.what, vte);
|
|
||||||
|
|
||||||
for(size_t p = 0; p < a->exprCall.what->expression.type->function.argCount; p++) {
|
|
||||||
spill_pass(tlc, &a->exprCall.args[p], vte);
|
|
||||||
}
|
|
||||||
} else if(a->nodeKind == AST_EXPR_PRIMITIVE) {
|
|
||||||
} else if(a->nodeKind == AST_EXPR_STRING_LITERAL) {
|
|
||||||
} else if(a->nodeKind == AST_EXPR_CAST) {
|
|
||||||
spill_pass(tlc, &a->exprCast.what, vte);
|
|
||||||
} else if(a->nodeKind == AST_EXPR_STACK_POINTER) {
|
|
||||||
} else if(a->nodeKind == AST_STMT_BREAK) {
|
|
||||||
} else if(a->nodeKind == AST_STMT_CONTINUE) {
|
|
||||||
} else if(a->nodeKind == AST_STMT_EXT_ALIGN) {
|
|
||||||
} else if(a->nodeKind == AST_STMT_EXT_ORG) {
|
|
||||||
} else if(a->nodeKind == AST_STMT_EXT_SECTION) {
|
|
||||||
} else if(a->nodeKind == AST_STMT_DECL) {
|
|
||||||
assert(a->stmtDecl.thing->kind != VARTABLEENTRY_VAR || a->stmtDecl.expression);
|
|
||||||
} else {
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,6 +528,223 @@ static int ud_empty(VarTableEntry *a) {
|
|||||||
return !a->data.var.usedefFirst;
|
return !a->data.var.usedefFirst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
|
AST *n = *nptr;
|
||||||
|
|
||||||
|
if(n == tlc) {
|
||||||
|
for(size_t i = 0; i < n->chunk.varCount; i++) {
|
||||||
|
n->chunk.vars[i]->data.var.color = -1;
|
||||||
|
n->chunk.vars[i]->data.var.precolored = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n->nodeKind == AST_STMT_RETURN) {
|
||||||
|
if(n->stmtReturn.val) {
|
||||||
|
assert(n->stmtReturn.val->nodeKind == AST_EXPR_VAR && n->stmtReturn.val->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
|
VarTableEntry *vte = n->stmtReturn.val->exprVar.thing;
|
||||||
|
|
||||||
|
assert(!vte->data.var.precolored);
|
||||||
|
|
||||||
|
vte->data.var.color = COLOR_EAX;
|
||||||
|
vte->data.var.precolored = true;
|
||||||
|
}
|
||||||
|
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
||||||
|
assert(n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
|
VarTableEntry *vte = n->stmtAssign.what->exprVar.thing;
|
||||||
|
|
||||||
|
assert(!vte->data.var.precolored);
|
||||||
|
|
||||||
|
vte->data.var.color = COLOR_EAX;
|
||||||
|
vte->data.var.precolored = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef VarTableEntry *Adjacency[2];
|
||||||
|
|
||||||
|
static bool var_collision(AST *tlc, VarTableEntry *v1, VarTableEntry *v2) {
|
||||||
|
/* 1D intersection test */
|
||||||
|
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, 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, v2->data.var.usedefLast->stmt, v1->data.var.usedefLast->stmt) == 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VarTableEntry *get_precolor_spill_candidate(AST *tlc) {
|
||||||
|
Adjacency *adjs = NULL;
|
||||||
|
size_t adjCount = 0;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < tlc->chunk.varCount; i++) {
|
||||||
|
tlc->chunk.vars[i]->data.var.degree = 0;
|
||||||
|
|
||||||
|
for(size_t j = 0; j < tlc->chunk.varCount; j++) {
|
||||||
|
|
||||||
|
if( tlc->chunk.vars[i]->data.var.precolored
|
||||||
|
&& tlc->chunk.vars[j]->data.var.precolored
|
||||||
|
&& tlc->chunk.vars[i]->data.var.color == tlc->chunk.vars[j]->data.var.color
|
||||||
|
&& var_collision(tlc, tlc->chunk.vars[i], tlc->chunk.vars[j])) {
|
||||||
|
|
||||||
|
adjs = realloc(adjs, sizeof(*adjs) * ++adjCount);
|
||||||
|
|
||||||
|
adjs[adjCount - 1][0] = tlc->chunk.vars[i];
|
||||||
|
adjs[adjCount - 1][1] = tlc->chunk.vars[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(adjCount == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t a = 0; a < adjCount; a++) {
|
||||||
|
adjs[a][0]->data.var.degree++;
|
||||||
|
adjs[a][1]->data.var.degree++;
|
||||||
|
}
|
||||||
|
|
||||||
|
VarTableEntry *maxdeg = tlc->chunk.vars[0];
|
||||||
|
|
||||||
|
for(size_t v = 1; v < tlc->chunk.varCount; v++) {
|
||||||
|
if(maxdeg->data.var.degree < tlc->chunk.vars[v]->data.var.degree) {
|
||||||
|
maxdeg = tlc->chunk.vars[v];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(adjs);
|
||||||
|
|
||||||
|
return maxdeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CalleeSavedState {
|
||||||
|
AST *targetTLC;
|
||||||
|
VarTableEntry *ebxuser;
|
||||||
|
|
||||||
|
// To make sure we don't process the same return statement to infinity
|
||||||
|
AST *lastProcessedReturn;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void callee_saved_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
|
struct CalleeSavedState *this = ud;
|
||||||
|
|
||||||
|
AST *n = *nptr;
|
||||||
|
|
||||||
|
if(tlc != this->targetTLC) {
|
||||||
|
// Don't do anything.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n == tlc) {
|
||||||
|
// Function entry
|
||||||
|
|
||||||
|
ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
|
||||||
|
stk->nodeKind = AST_EXPR_STACK_POINTER;
|
||||||
|
stk->type = primitive_parse("u32");
|
||||||
|
|
||||||
|
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
||||||
|
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
||||||
|
offset->type = primitive_parse("u32");
|
||||||
|
offset->val = tlc->chunk.stackReservation;
|
||||||
|
|
||||||
|
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
||||||
|
sum->nodeKind = AST_EXPR_BINARY_OP;
|
||||||
|
sum->type = offset->type;
|
||||||
|
sum->operator = BINOP_ADD;
|
||||||
|
sum->operands[0] = (AST*) stk;
|
||||||
|
sum->operands[1] = (AST*) offset;
|
||||||
|
|
||||||
|
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
||||||
|
deref->nodeKind = AST_EXPR_UNARY_OP;
|
||||||
|
deref->type = offset->type;
|
||||||
|
deref->operator = UNOP_DEREF;
|
||||||
|
deref->operand = (AST*) sum;
|
||||||
|
|
||||||
|
ASTExprVar *ev = calloc(1, sizeof(*ev));
|
||||||
|
ev->nodeKind = AST_EXPR_VAR;
|
||||||
|
ev->type = this->ebxuser->type;
|
||||||
|
ev->thing = this->ebxuser;
|
||||||
|
|
||||||
|
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
|
||||||
|
assign->nodeKind = AST_STMT_ASSIGN;
|
||||||
|
assign->what = (AST*) deref;
|
||||||
|
assign->to = (AST*) ev;
|
||||||
|
|
||||||
|
assign->next = tlc->chunk.statementFirst;
|
||||||
|
tlc->chunk.statementFirst = (AST*) assign;
|
||||||
|
|
||||||
|
assert(tlc->chunk.statementLast != NULL);
|
||||||
|
|
||||||
|
tlc->chunk.stackReservation += 4;
|
||||||
|
|
||||||
|
} else if(n->nodeKind == AST_STMT_RETURN && n != this->lastProcessedReturn) {
|
||||||
|
// Function exit
|
||||||
|
|
||||||
|
this->lastProcessedReturn = n;
|
||||||
|
|
||||||
|
ASTExprStackPointer *stk = calloc(1, sizeof(*stk));
|
||||||
|
stk->nodeKind = AST_EXPR_STACK_POINTER;
|
||||||
|
stk->type = primitive_parse("u32");
|
||||||
|
|
||||||
|
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
||||||
|
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
||||||
|
offset->type = primitive_parse("u32");
|
||||||
|
offset->val = tlc->chunk.stackReservation;
|
||||||
|
|
||||||
|
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
||||||
|
sum->nodeKind = AST_EXPR_BINARY_OP;
|
||||||
|
sum->type = offset->type;
|
||||||
|
sum->operator = BINOP_ADD;
|
||||||
|
sum->operands[0] = (AST*) stk;
|
||||||
|
sum->operands[1] = (AST*) offset;
|
||||||
|
|
||||||
|
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
||||||
|
deref->nodeKind = AST_EXPR_UNARY_OP;
|
||||||
|
deref->type = offset->type;
|
||||||
|
deref->operator = UNOP_DEREF;
|
||||||
|
deref->operand = (AST*) sum;
|
||||||
|
|
||||||
|
ASTExprVar *ev = calloc(1, sizeof(*ev));
|
||||||
|
ev->nodeKind = AST_EXPR_VAR;
|
||||||
|
ev->type = this->ebxuser->type;
|
||||||
|
ev->thing = this->ebxuser;
|
||||||
|
|
||||||
|
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
|
||||||
|
assign->nodeKind = AST_STMT_ASSIGN;
|
||||||
|
assign->what = (AST*) ev;
|
||||||
|
assign->to = (AST*) deref;
|
||||||
|
assign->next = stmt;
|
||||||
|
|
||||||
|
if(stmtPrev) {
|
||||||
|
stmtPrev->statement.next = (AST*) assign;
|
||||||
|
} else {
|
||||||
|
tlc->chunk.statementFirst = (AST*) assign;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callee_saved(AST *tlc) {
|
||||||
|
VarTableEntry *ebxuser = NULL;
|
||||||
|
|
||||||
|
for(size_t v = 0; v < tlc->chunk.varCount; v++) {
|
||||||
|
if(tlc->chunk.vars[v]->data.var.color == COLOR_EBX) {
|
||||||
|
ebxuser = tlc->chunk.vars[v];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ebxuser) {
|
||||||
|
struct CalleeSavedState state;
|
||||||
|
state.targetTLC = tlc;
|
||||||
|
state.ebxuser = ebxuser;
|
||||||
|
|
||||||
|
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, callee_saved_visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Welsh-Powell graph coloring */
|
/* Welsh-Powell graph coloring */
|
||||||
static int comparator(const void *A, const void *B) {
|
static int comparator(const void *A, const void *B) {
|
||||||
VarTableEntry *const *a = A;
|
VarTableEntry *const *a = A;
|
||||||
@ -458,9 +752,20 @@ static int comparator(const void *A, const void *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) {
|
||||||
typedef VarTableEntry *Adjacency[2];
|
do {
|
||||||
|
generic_visitor(&a, NULL, NULL, a, a, NULL, precolor_visitor);
|
||||||
ast_usedef_reset(a);
|
|
||||||
|
ast_usedef_reset(a);
|
||||||
|
|
||||||
|
VarTableEntry *vte = get_precolor_spill_candidate(a);
|
||||||
|
if(vte) {
|
||||||
|
struct Spill2VarState state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
state.target = vte;
|
||||||
|
|
||||||
|
generic_visitor(&a, NULL, NULL, a, a, &state, spill2var_visitor);
|
||||||
|
} else break;
|
||||||
|
} while(true);
|
||||||
|
|
||||||
size_t adjCount = 0;
|
size_t adjCount = 0;
|
||||||
Adjacency *adjs = calloc(adjCount, sizeof(*adjs));
|
Adjacency *adjs = calloc(adjCount, sizeof(*adjs));
|
||||||
@ -469,8 +774,11 @@ int cg_go(AST *a) {
|
|||||||
|
|
||||||
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.color = 0;
|
|
||||||
vars[vi]->data.var.degree = 0;
|
vars[vi]->data.var.degree = 0;
|
||||||
|
|
||||||
|
if(!vars[vi]->data.var.precolored) {
|
||||||
|
vars[vi]->data.var.color = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t v1i = 0; v1i < a->chunk.varCount; v1i++) {
|
for(size_t v1i = 0; v1i < a->chunk.varCount; v1i++) {
|
||||||
@ -480,14 +788,7 @@ int cg_go(AST *a) {
|
|||||||
VarTableEntry *v1 = vars[v1i];
|
VarTableEntry *v1 = vars[v1i];
|
||||||
VarTableEntry *v2 = vars[v2i];
|
VarTableEntry *v2 = vars[v2i];
|
||||||
|
|
||||||
/* 1D intersection test */
|
if(var_collision(a, v1, v2)) {
|
||||||
if(!ud_empty(v1) && !ud_empty(v2) && (
|
|
||||||
(ast_stmt_is_after(a, v1->data.var.usedefFirst->stmt, v2->data.var.usedefFirst->stmt) == 1
|
|
||||||
&& ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefFirst->stmt) == 1)
|
|
||||||
||
|
|
||||||
(ast_stmt_is_after(a, v1->data.var.usedefLast->stmt, v2->data.var.usedefFirst->stmt) == 1
|
|
||||||
&& ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefLast->stmt) == 1)
|
|
||||||
)) {
|
|
||||||
VarTableEntry *min = v1 < v2 ? v1 : v2;
|
VarTableEntry *min = v1 < v2 ? v1 : v2;
|
||||||
VarTableEntry *max = v1 < v2 ? v2 : v1;
|
VarTableEntry *max = v1 < v2 ? v2 : v1;
|
||||||
|
|
||||||
@ -546,13 +847,23 @@ nextColor:;
|
|||||||
if(lastColor >= 4) {
|
if(lastColor >= 4) {
|
||||||
// Spill node with highest degree
|
// Spill node with highest degree
|
||||||
|
|
||||||
spill_pass(a, &a, vars[a->chunk.varCount - 1]);
|
struct Spill2StackState state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
state.target = vars[a->chunk.varCount - 1];
|
||||||
|
|
||||||
|
generic_visitor(&a, NULL, NULL, a, a, &state, spill2stack_visitor);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(a->chunk.functionType) {
|
||||||
|
callee_saved(a);
|
||||||
|
}
|
||||||
|
|
||||||
CGState cg;
|
CGState cg;
|
||||||
memset(&cg, 0, sizeof(cg));
|
memset(&cg, 0, sizeof(cg));
|
||||||
|
cg.tlc = a;
|
||||||
|
cg.isFunction = !!a->chunk.functionType;
|
||||||
|
|
||||||
cg_chunk(&cg, a);
|
cg_chunk(&cg, a);
|
||||||
|
|
||||||
|
@ -12,17 +12,21 @@
|
|||||||
// architecture.
|
// architecture.
|
||||||
|
|
||||||
#include"x86.h"
|
#include"x86.h"
|
||||||
|
#include<string.h>
|
||||||
|
|
||||||
/* Split away complex expression into a new local variable */
|
/* Split away complex expression into a new local variable */
|
||||||
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
||||||
VarTableEntry *vte = malloc(sizeof(*vte));
|
static size_t vidx = 0;
|
||||||
|
|
||||||
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||||
vte->kind = VARTABLEENTRY_VAR;
|
vte->kind = VARTABLEENTRY_VAR;
|
||||||
vte->type = e->expression.type;
|
vte->type = e->expression.type;
|
||||||
vte->data.var.color = 0;
|
vte->data.var.color = -1;
|
||||||
|
vte->data.var.precolored = false;
|
||||||
vte->data.var.degree = 0;
|
vte->data.var.degree = 0;
|
||||||
vte->data.var.priority = 0;
|
vte->data.var.priority = 0;
|
||||||
vte->data.var.reachingDefs = NULL;
|
vte->data.var.reachingDefs = NULL;
|
||||||
vte->data.var.name = strdup("googoo");
|
vte->data.var.name = malp("$dumb%lu", vidx++);
|
||||||
|
|
||||||
// Add to var array
|
// Add to var array
|
||||||
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
|
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
|
||||||
@ -62,149 +66,268 @@ static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
|||||||
return varify(tlc, chunk, stmtPrev, stmt, e);
|
return varify(tlc, chunk, stmtPrev, stmt, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dumben_chunk(AST *tlc, AST *chu) {
|
static bool is_incomplete_mul(AST *stmt) {
|
||||||
AST *sPrev = NULL;
|
if(stmt->nodeKind != AST_STMT_ASSIGN) {
|
||||||
AST *s = chu->chunk.statementFirst;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int effective = 0;
|
if(stmt->stmtAssign.what->nodeKind != AST_EXPR_VAR) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
while(s) {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DumbenState {
|
||||||
|
int effective;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud) {
|
||||||
|
struct DumbenState *this = ud;
|
||||||
|
|
||||||
if(s->nodeKind == AST_STMT_IF) {
|
AST *s = *nptr;
|
||||||
|
|
||||||
AST *e = s->stmtIf.expression;
|
if(s->nodeKind == AST_STMT_IF) {
|
||||||
|
|
||||||
if(e->nodeKind == AST_EXPR_BINARY_OP && binop_is_comparison(e->exprBinOp.operator)) {
|
AST *e = s->stmtIf.expression;
|
||||||
|
|
||||||
if(is_xop(e->exprBinOp.operands[0]) == XOP_NOT_XOP) {
|
if(e->nodeKind == AST_EXPR_BINARY_OP && binop_is_comparison(e->exprBinOp.operator)) {
|
||||||
e->exprBinOp.operands[0] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[0]);
|
|
||||||
effective = 1;
|
if(is_xop(e->exprBinOp.operands[0]) == XOP_NOT_XOP) {
|
||||||
}
|
e->exprBinOp.operands[0] = xopify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[0]);
|
||||||
|
this->effective = 1;
|
||||||
if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) {
|
|
||||||
e->exprBinOp.operands[1] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]);
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_xop(e->exprBinOp.operands[0]) == XOP_MEM && is_xop(e->exprBinOp.operands[1]) == XOP_MEM) {
|
|
||||||
// Can't have two mems; put one in var
|
|
||||||
|
|
||||||
e->exprBinOp.operands[1] = varify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]);
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
s->stmtIf.expression = varify(tlc, chu, sPrev, s, e);
|
|
||||||
effective = 1;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
effective |= dumben_chunk(tlc, s->stmtIf.then);
|
if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) {
|
||||||
|
e->exprBinOp.operands[1] = xopify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]);
|
||||||
} else if(s->nodeKind == AST_STMT_LOOP) {
|
this->effective = 1;
|
||||||
|
|
||||||
effective |= dumben_chunk(tlc, s->stmtLoop.body);
|
|
||||||
|
|
||||||
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
|
||||||
|
|
||||||
if(ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to) && sPrev) {
|
|
||||||
// Remove this statement from AST
|
|
||||||
sPrev->statement.next = s->statement.next;
|
|
||||||
effective = 1;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF
|
|
||||||
&& s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) {
|
|
||||||
|
|
||||||
s->stmtAssign.to = varify(tlc, chu, sPrev, s, s->stmtAssign.to);
|
|
||||||
effective = 1;
|
|
||||||
} else if(s->stmtAssign.what && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
|
||||||
ASTExprCall *call = &s->stmtAssign.to->exprCall;
|
|
||||||
|
|
||||||
int argCount = call->what->expression.type->function.argCount;
|
|
||||||
|
|
||||||
for(int i = 0; i < argCount; i++) {
|
|
||||||
if(is_xop(call->args[i]) == XOP_NOT_XOP) {
|
|
||||||
call->args[i] = xopify(tlc, chu, sPrev, s, call->args[i]);
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(s->stmtAssign.to && 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)) {
|
|
||||||
// Turn this:
|
|
||||||
// a = -b
|
|
||||||
// into
|
|
||||||
// a = b
|
|
||||||
// a = -a
|
|
||||||
|
|
||||||
AST *ev[2] = {
|
|
||||||
ast_deep_copy(s->stmtAssign.what),
|
|
||||||
ast_deep_copy(s->stmtAssign.what)
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
effective = 1;
|
|
||||||
} 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) {
|
|
||||||
s->stmtAssign.to->exprUnOp.operand = varify(tlc, chu, sPrev, s, s->stmtAssign.to->exprUnOp.operand);
|
|
||||||
|
|
||||||
effective = 1;
|
|
||||||
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator < BINOP_SIMPLES && !ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0])) {
|
|
||||||
// Turn this:
|
|
||||||
// a = b op c
|
|
||||||
// into
|
|
||||||
// a = b
|
|
||||||
// a = a op c
|
|
||||||
|
|
||||||
AST *assign2 = malloc(sizeof(ASTStmtAssign));
|
|
||||||
assign2->nodeKind = AST_STMT_ASSIGN;
|
|
||||||
assign2->stmtAssign.what = ast_deep_copy(s->stmtAssign.what);
|
|
||||||
assign2->stmtAssign.to = s->stmtAssign.to->exprBinOp.operands[0];
|
|
||||||
|
|
||||||
sPrev->statement.next = assign2;
|
|
||||||
assign2->statement.next = s;
|
|
||||||
|
|
||||||
s->stmtAssign.to->exprBinOp.operands[0] = ast_deep_copy(s->stmtAssign.what);
|
|
||||||
|
|
||||||
effective = 1;
|
|
||||||
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && !is_xop(s->stmtAssign.to->exprBinOp.operands[0])) {
|
|
||||||
s->stmtAssign.to->exprBinOp.operands[0] = xopify(tlc, chu, sPrev, s, s->stmtAssign.to->exprBinOp.operands[0]);
|
|
||||||
effective = 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, sPrev, s, s->stmtAssign.to->exprBinOp.operands[1]);
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(is_xop(e->exprBinOp.operands[0]) == XOP_MEM && is_xop(e->exprBinOp.operands[1]) == XOP_MEM) {
|
||||||
|
// Can't have two mems; put one in var
|
||||||
|
|
||||||
|
e->exprBinOp.operands[1] = varify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]);
|
||||||
|
this->effective = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
s->stmtIf.expression = varify(tlc, chu, stmtPrev, s, e);
|
||||||
|
this->effective = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(s->nodeKind == AST_STMT_LOOP) {
|
||||||
|
|
||||||
|
} else if(s->nodeKind == AST_STMT_RETURN) {
|
||||||
|
|
||||||
|
// ret specifically returns in eax always, so it needs to be in a var
|
||||||
|
if(s->stmtReturn.val && (!is_xop(s->stmtReturn.val) || s->stmtReturn.val->nodeKind == AST_EXPR_PRIMITIVE)) {
|
||||||
|
|
||||||
|
s->stmtReturn.val = varify(tlc, chu, stmtPrev, s, s->stmtReturn.val);
|
||||||
|
this->effective = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) {
|
||||||
|
|
||||||
|
// Turn this:
|
||||||
|
// f(x);
|
||||||
|
// into:
|
||||||
|
// a = f(x);
|
||||||
|
|
||||||
|
// So `a` would be colored as `eax`
|
||||||
|
|
||||||
|
s->stmtExpr.expr = varify(tlc, chu, stmtPrev, s, s->stmtExpr.expr);
|
||||||
|
|
||||||
|
// Purge this statement entirely, otherwise it'd be
|
||||||
|
// a = f(x);
|
||||||
|
// a;
|
||||||
|
if(stmtPrev) {
|
||||||
|
assert(stmtPrev->statement.next->statement.next == s);
|
||||||
|
stmtPrev->statement.next->statement.next = s->statement.next;
|
||||||
|
} else {
|
||||||
|
assert(chu->chunk.statementFirst->statement.next = s);
|
||||||
|
chu->chunk.statementFirst->statement.next = s->statement.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
||||||
|
|
||||||
|
if(ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to) && stmtPrev) {
|
||||||
|
// NOP; remove this statement from AST
|
||||||
|
stmtPrev->statement.next = s->statement.next;
|
||||||
|
this->effective = 1;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF
|
||||||
|
&& s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) {
|
||||||
|
|
||||||
|
s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to);
|
||||||
|
this->effective = 1;
|
||||||
|
} else if(s->stmtAssign.what && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) {
|
||||||
|
ASTExprCall *call = &s->stmtAssign.to->exprCall;
|
||||||
|
|
||||||
|
int argCount = call->what->expression.type->function.argCount;
|
||||||
|
|
||||||
|
for(int i = 0; i < argCount; i++) {
|
||||||
|
if(is_xop(call->args[i]) == XOP_NOT_XOP) {
|
||||||
|
call->args[i] = xopify(tlc, chu, stmtPrev, s, call->args[i]);
|
||||||
|
this->effective = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(s->stmtAssign.to && 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)) {
|
||||||
|
// Turn this:
|
||||||
|
// a = -b
|
||||||
|
// into
|
||||||
|
// a = b
|
||||||
|
// a = -a
|
||||||
|
|
||||||
|
AST *ev[2] = {
|
||||||
|
ast_deep_copy(s->stmtAssign.what),
|
||||||
|
ast_deep_copy(s->stmtAssign.what)
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
this->effective = 1;
|
||||||
|
} 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) {
|
||||||
|
s->stmtAssign.to->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprUnOp.operand);
|
||||||
|
|
||||||
|
this->effective = 1;
|
||||||
|
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) {
|
||||||
|
|
||||||
|
if(s->stmtAssign.what->nodeKind != AST_EXPR_VAR) {
|
||||||
|
s->stmtAssign.what = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what);
|
||||||
|
this->effective = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if(!(s->statement.next && s->statement.next->nodeKind == AST_STMT_ASSIGN && s->statement.next->stmtAssign.)) {
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// TODO: implement multiplication
|
||||||
|
|
||||||
|
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator < BINOP_SIMPLES && !ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0])) {
|
||||||
|
// Turn this:
|
||||||
|
// a = b op c
|
||||||
|
// into
|
||||||
|
// a = b
|
||||||
|
// a = a op c
|
||||||
|
|
||||||
|
AST *assign2 = malloc(sizeof(ASTStmtAssign));
|
||||||
|
assign2->nodeKind = AST_STMT_ASSIGN;
|
||||||
|
assign2->stmtAssign.what = ast_deep_copy(s->stmtAssign.what);
|
||||||
|
assign2->stmtAssign.to = s->stmtAssign.to->exprBinOp.operands[0];
|
||||||
|
|
||||||
|
if(stmtPrev) {
|
||||||
|
stmtPrev->statement.next = assign2;
|
||||||
|
} else {
|
||||||
|
chu->chunk.statementFirst = assign2;
|
||||||
|
}
|
||||||
|
assign2->statement.next = s;
|
||||||
|
|
||||||
|
s->stmtAssign.to->exprBinOp.operands[0] = ast_deep_copy(s->stmtAssign.what);
|
||||||
|
|
||||||
|
this->effective = 1;
|
||||||
|
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && !is_xop(s->stmtAssign.to->exprBinOp.operands[0])) {
|
||||||
|
s->stmtAssign.to->exprBinOp.operands[0] = xopify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[0]);
|
||||||
|
this->effective = 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]);
|
||||||
|
this->effective = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sPrev = s;
|
|
||||||
s = s->statement.next;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
|
AST *n = *nptr;
|
||||||
|
|
||||||
return effective;
|
if(n == tlc) {
|
||||||
|
if(tlc->chunk.functionType) {
|
||||||
|
size_t argCount = n->chunk.functionType->function.argCount;
|
||||||
|
|
||||||
|
// First argCount vtes in list are the arguments
|
||||||
|
for(size_t i = 0; i < argCount; i++) {
|
||||||
|
VarTableEntry *vte = n->chunk.vars[i];
|
||||||
|
|
||||||
|
ASTExprStackPointer *stck = calloc(1, sizeof(*stck));
|
||||||
|
stck->nodeKind = AST_EXPR_STACK_POINTER;
|
||||||
|
stck->type = type_pointer_wrap(vte->type);
|
||||||
|
|
||||||
|
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
||||||
|
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
||||||
|
offset->type = primitive_parse("u32");
|
||||||
|
offset->val = 4 + i * 4;
|
||||||
|
|
||||||
|
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
||||||
|
sum->nodeKind = AST_EXPR_BINARY_OP;
|
||||||
|
sum->type = stck->type;
|
||||||
|
sum->operands[0] = (AST*) stck;
|
||||||
|
sum->operands[1] = (AST*) offset;
|
||||||
|
sum->operator = BINOP_ADD;
|
||||||
|
|
||||||
|
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
||||||
|
deref->nodeKind = AST_EXPR_UNARY_OP;
|
||||||
|
deref->type = vte->type;
|
||||||
|
deref->operand = (AST*) sum;
|
||||||
|
deref->operator = UNOP_DEREF;
|
||||||
|
|
||||||
|
ASTExprVar *evar = calloc(1, sizeof(*evar));
|
||||||
|
evar->nodeKind = AST_EXPR_VAR;
|
||||||
|
evar->type = vte->type;
|
||||||
|
evar->thing = vte;
|
||||||
|
|
||||||
|
ASTStmtAssign *ass = calloc(1, sizeof(*ass));
|
||||||
|
ass->nodeKind = AST_STMT_ASSIGN;
|
||||||
|
ass->next = NULL;
|
||||||
|
ass->what = (AST*) evar;
|
||||||
|
ass->to = (AST*) deref;
|
||||||
|
ass->next = n->chunk.statementFirst;
|
||||||
|
|
||||||
|
if(n->chunk.statementFirst) {
|
||||||
|
n->chunk.statementFirst = ass;
|
||||||
|
} else {
|
||||||
|
assert(!n->chunk.statementLast);
|
||||||
|
n->chunk.statementFirst = n->chunk.statementLast = ass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumben_pre(AST *tlc) {
|
||||||
|
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumben_go(AST* tlc) {
|
void dumben_go(AST* tlc) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while(1) {
|
while(1) {
|
||||||
fprintf(stderr, "// Dumbing down %lu...\n", i++);
|
fprintf(stderr, "; Dumbing down %lu...\n", i++);
|
||||||
|
|
||||||
int successful = dumben_chunk(tlc, tlc);
|
struct DumbenState state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
if(!successful) break;
|
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, dumben_visitor);
|
||||||
|
|
||||||
|
int successful = state.effective;
|
||||||
|
|
||||||
|
if(!successful) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
#include"ast.h"
|
#include"ast.h"
|
||||||
|
|
||||||
void dumben_go(AST* a);
|
void dumben_pre(AST *tlc);
|
||||||
|
void dumben_go(AST* tlc);
|
||||||
|
23
src/lexer.c
23
src/lexer.c
@ -39,6 +39,11 @@ char *TOKEN_NAMES[] = {
|
|||||||
"'!'",
|
"'!'",
|
||||||
"'continue'",
|
"'continue'",
|
||||||
"'return'",
|
"'return'",
|
||||||
|
"'->'",
|
||||||
|
"'<='",
|
||||||
|
"'>='",
|
||||||
|
"'<'",
|
||||||
|
"'>'",
|
||||||
};
|
};
|
||||||
|
|
||||||
static int isAlpha(int c) {
|
static int isAlpha(int c) {
|
||||||
@ -118,6 +123,10 @@ Token nct_tokenize(FILE *f) {
|
|||||||
return tok;
|
return tok;
|
||||||
} else if(c == '-') {
|
} else if(c == '-') {
|
||||||
tok.type = TOKEN_MINUS;
|
tok.type = TOKEN_MINUS;
|
||||||
|
int c = nextc(f);
|
||||||
|
if(c == '>') {
|
||||||
|
tok.type = TOKEN_ARROW;
|
||||||
|
} else ungetc(c, f);
|
||||||
return tok;
|
return tok;
|
||||||
} else if(c == '*') {
|
} else if(c == '*') {
|
||||||
tok.type = TOKEN_STAR;
|
tok.type = TOKEN_STAR;
|
||||||
@ -150,6 +159,20 @@ Token nct_tokenize(FILE *f) {
|
|||||||
tok.type = TOKEN_EXCLAMATION_EQUALS;
|
tok.type = TOKEN_EXCLAMATION_EQUALS;
|
||||||
} else ungetc(c, f);
|
} else ungetc(c, f);
|
||||||
return tok;
|
return tok;
|
||||||
|
} else if(c == '<') {
|
||||||
|
tok.type = TOKEN_LESS;
|
||||||
|
int c = nextc(f);
|
||||||
|
if(c == '=') {
|
||||||
|
tok.type = TOKEN_LEQUAL;
|
||||||
|
} else ungetc(c, f);
|
||||||
|
return tok;
|
||||||
|
} else if(c == '>') {
|
||||||
|
tok.type = TOKEN_GREATER;
|
||||||
|
int c = nextc(f);
|
||||||
|
if(c == '=') {
|
||||||
|
tok.type = TOKEN_GEQUAL;
|
||||||
|
} else ungetc(c, f);
|
||||||
|
return tok;
|
||||||
} else if(c == '/') {
|
} else if(c == '/') {
|
||||||
int c = nextc(f);
|
int c = nextc(f);
|
||||||
if(c == '*') { /* This is a comment; skip. */
|
if(c == '*') { /* This is a comment; skip. */
|
||||||
|
@ -38,7 +38,12 @@ typedef enum {
|
|||||||
TOKEN_EXCLAMATION_EQUALS,
|
TOKEN_EXCLAMATION_EQUALS,
|
||||||
TOKEN_EXCLAMATION,
|
TOKEN_EXCLAMATION,
|
||||||
TOKEN_CONTINUE,
|
TOKEN_CONTINUE,
|
||||||
TOKEN_RETURN
|
TOKEN_RETURN,
|
||||||
|
TOKEN_ARROW,
|
||||||
|
TOKEN_LEQUAL,
|
||||||
|
TOKEN_GEQUAL,
|
||||||
|
TOKEN_LESS,
|
||||||
|
TOKEN_GREATER,
|
||||||
} TokenKind;
|
} TokenKind;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -37,17 +37,20 @@ int main(int argc_, char **argv_) {
|
|||||||
|
|
||||||
free(tokens);
|
free(tokens);
|
||||||
|
|
||||||
fputs("/* === Original AST === */\n", stderr);
|
fputs("; === Original AST ===\n", stderr);
|
||||||
fputs(ast_dump(chunk), stderr);
|
fputs(ast_dump(chunk), stderr);
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
|
|
||||||
|
dumben_pre(chunk);
|
||||||
dumben_go(chunk);
|
dumben_go(chunk);
|
||||||
|
|
||||||
fputs("\n/* === Dumbified === */\n", stderr);
|
fputs("\n; === Dumbified ===\n", stderr);
|
||||||
fputs(ast_dump(chunk), stderr);
|
fputs(ast_dump(chunk), stderr);
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
|
|
||||||
while(!cg_go(chunk));
|
while(!cg_go(chunk)) {
|
||||||
|
dumben_go(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
169
src/parse.c
169
src/parse.c
@ -41,6 +41,13 @@ typedef struct {
|
|||||||
VarTable *loopScope;
|
VarTable *loopScope;
|
||||||
size_t guardedVarCount;
|
size_t guardedVarCount;
|
||||||
ASTExprVar **guardedVars;
|
ASTExprVar **guardedVars;
|
||||||
|
|
||||||
|
// Used for generating statements that load & store arguments
|
||||||
|
int isInFunction;
|
||||||
|
|
||||||
|
// Skim mode disables parsing function definitions
|
||||||
|
// This is needed to automatically forward-declare symbols
|
||||||
|
int skimMode;
|
||||||
} Parser;
|
} Parser;
|
||||||
|
|
||||||
static Token get(Parser *P) {
|
static Token get(Parser *P) {
|
||||||
@ -111,27 +118,6 @@ static ASTExprPrimitive *parse_prim(Parser *P) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static void newusedef(Parser *P, VarTableEntry *v, AST *expr) {
|
|
||||||
ReachingDefs *defs = v->data.var.reachingDefs;
|
|
||||||
|
|
||||||
while(defs) {
|
|
||||||
for(size_t i = 0; i < defs->defCount; i++) {
|
|
||||||
P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount));
|
|
||||||
P->udsToAdd[P->udsToAddCount - 1].ud.def = defs->defs[i];
|
|
||||||
P->udsToAdd[P->udsToAddCount - 1].ud.use = expr;
|
|
||||||
P->udsToAdd[P->udsToAddCount - 1].ud.stmt = NULL; // set by pushstmt
|
|
||||||
P->udsToAdd[P->udsToAddCount - 1].ud.next = NULL;
|
|
||||||
P->udsToAdd[P->udsToAddCount - 1].to = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(defs->excludeParent) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
defs = defs->parent;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
static AST *exprvar(Parser *P, VarTableEntry *v) {
|
static AST *exprvar(Parser *P, VarTableEntry *v) {
|
||||||
AST *a = malloc(sizeof(ASTExprVar));
|
AST *a = malloc(sizeof(ASTExprVar));
|
||||||
a->nodeKind = AST_EXPR_VAR;
|
a->nodeKind = AST_EXPR_VAR;
|
||||||
@ -237,12 +223,12 @@ AST *nct_cast_expr(AST *what, Type *to) {
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTChunk *nct_parse_chunk(Parser*, int, int);
|
ASTChunk *nct_parse_chunk(Parser*, int, int, VarTable*, Type *ft);
|
||||||
Type *nct_parse_typename(Parser *P);
|
Type *nct_parse_typename(Parser *P);
|
||||||
|
|
||||||
AST *nct_parse_expression(Parser *P, int lOP) {
|
AST *nct_parse_expression(Parser *P, int lOP) {
|
||||||
if(lOP == 0) {
|
if(lOP == 0) {
|
||||||
// Test if this is an anonymous function
|
// Test if this is an anonymous function
|
||||||
Type *ft = nct_parse_typename(P);
|
Type *ft = nct_parse_typename(P);
|
||||||
if(ft) {
|
if(ft) {
|
||||||
assert(ft->type == TYPE_TYPE_FUNCTION);
|
assert(ft->type == TYPE_TYPE_FUNCTION);
|
||||||
@ -251,11 +237,23 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
e->nodeKind = AST_EXPR_FUNC;
|
e->nodeKind = AST_EXPR_FUNC;
|
||||||
e->type = ft;
|
e->type = ft;
|
||||||
|
|
||||||
maybe(P, TOKEN_SQUIGGLY_L);
|
if(P->skimMode) {
|
||||||
|
// In skim mode, it won't be parsed normally anyway
|
||||||
|
} else {
|
||||||
|
expect(P, TOKEN_ARROW);
|
||||||
|
|
||||||
|
expect(P, TOKEN_SQUIGGLY_L);
|
||||||
|
|
||||||
|
P->isInFunction++;
|
||||||
|
|
||||||
|
e->chunk = (AST*) nct_parse_chunk(P, 1, 0, vartable_new(P->scope), ft);
|
||||||
|
e->chunk->chunk.functionType = ft;
|
||||||
|
|
||||||
|
P->isInFunction--;
|
||||||
|
|
||||||
|
expect(P, TOKEN_SQUIGGLY_R);
|
||||||
|
}
|
||||||
|
|
||||||
e->chunk = (AST*) nct_parse_chunk(P, 1, 0);
|
|
||||||
|
|
||||||
maybe(P, TOKEN_SQUIGGLY_R);
|
|
||||||
|
|
||||||
return (AST*) e;
|
return (AST*) e;
|
||||||
}
|
}
|
||||||
@ -274,7 +272,15 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
return (AST*) ret;
|
return (AST*) ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exprvar(P, vartable_find(P->scope, get(P).content));
|
Token varname = get(P);
|
||||||
|
|
||||||
|
VarTableEntry *vte = vartable_find(P->scope, varname.content);
|
||||||
|
|
||||||
|
if(!vte) {
|
||||||
|
stahp(varname.row, varname.column, "Unknown variable %s", varname.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
return exprvar(P, vte);
|
||||||
} else if(peek(P, 0).type == TOKEN_STRING) {
|
} else if(peek(P, 0).type == TOKEN_STRING) {
|
||||||
ASTExprStringLiteral *ret = malloc(sizeof(*ret));
|
ASTExprStringLiteral *ret = malloc(sizeof(*ret));
|
||||||
ret->nodeKind = AST_EXPR_STRING_LITERAL;
|
ret->nodeKind = AST_EXPR_STRING_LITERAL;
|
||||||
@ -348,15 +354,6 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Only function types may be called.");
|
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Only function types may be called.");
|
||||||
}
|
}
|
||||||
|
|
||||||
VarTableEntry *tempo = calloc(1, sizeof(*tempo));
|
|
||||||
tempo->kind = VARTABLEENTRY_VAR;
|
|
||||||
tempo->type = ret->expression.type->function.ret;
|
|
||||||
tempo->data.var.name = "$temp";
|
|
||||||
tempo->data.var.color = COLOR_EAX;
|
|
||||||
|
|
||||||
P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (++P->topLevel->varCount));
|
|
||||||
P->topLevel->vars[P->topLevel->varCount - 1] = tempo;
|
|
||||||
|
|
||||||
ASTExprCall *call = malloc(sizeof(*call));
|
ASTExprCall *call = malloc(sizeof(*call));
|
||||||
call->nodeKind = AST_EXPR_CALL;
|
call->nodeKind = AST_EXPR_CALL;
|
||||||
call->type = ret->expression.type->function.ret;
|
call->type = ret->expression.type->function.ret;
|
||||||
@ -378,15 +375,11 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
|
if(argCount != call->what->expression.type->function.argCount) {
|
||||||
assign->nodeKind = AST_STMT_ASSIGN;
|
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Mismatched number of arguments");
|
||||||
assign->what = exprvar(P, tempo);
|
}
|
||||||
assign->to = call;
|
|
||||||
|
|
||||||
pushstat(P, assign);
|
ret = (AST*) call;
|
||||||
|
|
||||||
ret = exprvar(P, tempo);
|
|
||||||
/* TODO: Check argument count. */
|
|
||||||
} else if(maybe(P, TOKEN_SQUAREN_L)) {
|
} else if(maybe(P, TOKEN_SQUAREN_L)) {
|
||||||
ASTExprUnaryOp *ref = malloc(sizeof(*ref));
|
ASTExprUnaryOp *ref = malloc(sizeof(*ref));
|
||||||
ref->nodeKind = AST_EXPR_UNARY_OP;
|
ref->nodeKind = AST_EXPR_UNARY_OP;
|
||||||
@ -524,11 +517,15 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
} else if(lOP == 0) {
|
} else if(lOP == 0) {
|
||||||
AST *ret = nct_parse_expression(P, lOP + 1);
|
AST *ret = nct_parse_expression(P, lOP + 1);
|
||||||
|
|
||||||
if(peek(P, 0).type == TOKEN_DOUBLE_EQUALS || peek(P, 0).type == TOKEN_EXCLAMATION_EQUALS) {
|
if(peek(P, 0).type == TOKEN_DOUBLE_EQUALS || peek(P, 0).type == TOKEN_EXCLAMATION_EQUALS || peek(P, 0).type == TOKEN_LESS || peek(P, 0).type == TOKEN_GREATER || peek(P, 0).type == TOKEN_LEQUAL || peek(P, 0).type == TOKEN_GEQUAL) {
|
||||||
while(1) {
|
while(1) {
|
||||||
BinaryOp op;
|
BinaryOp op;
|
||||||
if(maybe(P, TOKEN_DOUBLE_EQUALS)) op = BINOP_EQUAL;
|
if(maybe(P, TOKEN_DOUBLE_EQUALS)) op = BINOP_EQUAL;
|
||||||
else if(maybe(P, TOKEN_EXCLAMATION_EQUALS)) op = BINOP_NEQUAL;
|
else if(maybe(P, TOKEN_EXCLAMATION_EQUALS)) op = BINOP_NEQUAL;
|
||||||
|
else if(maybe(P, TOKEN_LESS)) op = BINOP_LESS;
|
||||||
|
else if(maybe(P, TOKEN_GREATER)) op = BINOP_GREATER;
|
||||||
|
else if(maybe(P, TOKEN_LEQUAL)) op = BINOP_LEQUAL;
|
||||||
|
else if(maybe(P, TOKEN_GEQUAL)) op = BINOP_GEQUAL;
|
||||||
else break;
|
else break;
|
||||||
|
|
||||||
ASTExprBinaryOp *astop = malloc(sizeof(*astop));
|
ASTExprBinaryOp *astop = malloc(sizeof(*astop));
|
||||||
@ -588,7 +585,7 @@ Type *nct_parse_typename(Parser *P) {
|
|||||||
|
|
||||||
ret = (Type*) ptr;
|
ret = (Type*) ptr;
|
||||||
} else if(maybe(P, TOKEN_PAREN_L)) {
|
} else if(maybe(P, TOKEN_PAREN_L)) {
|
||||||
TypeFunction *fun = malloc(sizeof(*fun));
|
TypeFunction *fun = calloc(1, sizeof(*fun));
|
||||||
fun->type = TYPE_TYPE_FUNCTION;
|
fun->type = TYPE_TYPE_FUNCTION;
|
||||||
fun->ret = ret;
|
fun->ret = ret;
|
||||||
fun->argCount = 0;
|
fun->argCount = 0;
|
||||||
@ -597,12 +594,18 @@ Type *nct_parse_typename(Parser *P) {
|
|||||||
if(!maybe(P, TOKEN_PAREN_R)) {
|
if(!maybe(P, TOKEN_PAREN_R)) {
|
||||||
while(1) {
|
while(1) {
|
||||||
fun->argCount++;
|
fun->argCount++;
|
||||||
fun->args = realloc(fun->args, sizeof(Type*) * fun->argCount);
|
fun->args = realloc(fun->args, sizeof(*fun->args) * fun->argCount);
|
||||||
|
fun->argNames = realloc(fun->argNames, sizeof(*fun->argNames) * fun->argCount);
|
||||||
|
|
||||||
if((fun->args[fun->argCount - 1] = nct_parse_typename(P)) == NULL) {
|
if((fun->args[fun->argCount - 1] = nct_parse_typename(P)) == NULL) {
|
||||||
free(fun);
|
free(fun);
|
||||||
goto backtrack;
|
goto backtrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(peek(P, 0).type == TOKEN_IDENTIFIER) {
|
||||||
|
fun->argNames[fun->argCount - 1] = get(P).content;
|
||||||
|
}
|
||||||
|
|
||||||
if(maybe(P, TOKEN_PAREN_R)) {
|
if(maybe(P, TOKEN_PAREN_R)) {
|
||||||
break;
|
break;
|
||||||
} else expect(P, TOKEN_COMMA);
|
} else expect(P, TOKEN_COMMA);
|
||||||
@ -669,11 +672,10 @@ static AST *parse_declaration(Parser *P) {
|
|||||||
AST *ret = NULL;
|
AST *ret = NULL;
|
||||||
|
|
||||||
if(maybe(P, TOKEN_EQUALS) || (peek(P, 0).type == TOKEN_SEMICOLON && !isExternal && !isLocal)) {
|
if(maybe(P, TOKEN_EQUALS) || (peek(P, 0).type == TOKEN_SEMICOLON && !isExternal && !isLocal)) {
|
||||||
/*if(isExternal || isLocal) {
|
if(isExternal || isLocal) {
|
||||||
fputs("'local' and 'extern' keywords are to be used for symbol declaration only.\n", stderr);
|
stahp(name.row, name.column, "'local' and 'extern' keywords are to be used for symbol declaration only.");
|
||||||
abort();
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
entry->kind = VARTABLEENTRY_VAR;
|
entry->kind = VARTABLEENTRY_VAR;
|
||||||
entry->data.var.priority = 1;
|
entry->data.var.priority = 1;
|
||||||
@ -736,7 +738,11 @@ static AST *parse_declaration(Parser *P) {
|
|||||||
|
|
||||||
vartable_set(P->scope, name.content, entry);
|
vartable_set(P->scope, name.content, entry);
|
||||||
|
|
||||||
expect(P, TOKEN_SEMICOLON);
|
if(P->skimMode) {
|
||||||
|
// In skim mode parsing is not done normally
|
||||||
|
} else {
|
||||||
|
expect(P, TOKEN_SEMICOLON);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
backtrack:
|
backtrack:
|
||||||
@ -759,7 +765,7 @@ void nct_parse_statement(Parser *P) {
|
|||||||
pushstat(P, ret);
|
pushstat(P, ret);
|
||||||
|
|
||||||
expect(P, TOKEN_SQUIGGLY_L);
|
expect(P, TOKEN_SQUIGGLY_L);
|
||||||
ret->then = (AST*) nct_parse_chunk(P, 0, 0);
|
ret->then = (AST*) nct_parse_chunk(P, 0, 0, NULL, NULL);
|
||||||
expect(P, TOKEN_SQUIGGLY_R);
|
expect(P, TOKEN_SQUIGGLY_R);
|
||||||
return;
|
return;
|
||||||
} else if(maybe(P, TOKEN_LOOP)) {
|
} else if(maybe(P, TOKEN_LOOP)) {
|
||||||
@ -774,7 +780,7 @@ void nct_parse_statement(Parser *P) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect(P, TOKEN_SQUIGGLY_L);
|
expect(P, TOKEN_SQUIGGLY_L);
|
||||||
ret->body = (AST*) nct_parse_chunk(P, 0, 1);
|
ret->body = (AST*) nct_parse_chunk(P, 0, 1, NULL, NULL);
|
||||||
expect(P, TOKEN_SQUIGGLY_R);
|
expect(P, TOKEN_SQUIGGLY_R);
|
||||||
|
|
||||||
pushstat(P, ret);
|
pushstat(P, ret);
|
||||||
@ -824,25 +830,7 @@ void nct_parse_statement(Parser *P) {
|
|||||||
ret->next = NULL;
|
ret->next = NULL;
|
||||||
|
|
||||||
if(!maybe(P, TOKEN_SEMICOLON)) {
|
if(!maybe(P, TOKEN_SEMICOLON)) {
|
||||||
AST *expr = nct_parse_expression(P, 0);
|
ret->val = nct_parse_expression(P, 0);
|
||||||
|
|
||||||
VarTableEntry *tempo = calloc(1, sizeof(*tempo));
|
|
||||||
tempo->kind = VARTABLEENTRY_VAR;
|
|
||||||
tempo->type = expr->expression.type;
|
|
||||||
tempo->data.var.name = "$temp";
|
|
||||||
tempo->data.var.color = COLOR_EAX;
|
|
||||||
|
|
||||||
P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (++P->topLevel->varCount));
|
|
||||||
P->topLevel->vars[P->topLevel->varCount - 1] = tempo;
|
|
||||||
|
|
||||||
ASTStmtAssign *assign = malloc(sizeof(*assign));
|
|
||||||
assign->nodeKind = AST_STMT_ASSIGN;
|
|
||||||
assign->what = exprvar(P, tempo);
|
|
||||||
assign->to = expr;
|
|
||||||
|
|
||||||
ret->val = exprvar(P, tempo);
|
|
||||||
|
|
||||||
pushstat(P, assign);
|
|
||||||
|
|
||||||
expect(P, TOKEN_SEMICOLON);
|
expect(P, TOKEN_SEMICOLON);
|
||||||
}
|
}
|
||||||
@ -941,7 +929,7 @@ void nct_parse_statement(Parser *P) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
|
ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable *toplevelParent, Type *ft) {
|
||||||
AST *ret = calloc(1, sizeof(ASTChunk));
|
AST *ret = calloc(1, sizeof(ASTChunk));
|
||||||
ret->nodeKind = AST_CHUNK;
|
ret->nodeKind = AST_CHUNK;
|
||||||
ret->chunk.statementFirst = ret->chunk.statementLast = NULL;
|
ret->chunk.statementFirst = ret->chunk.statementLast = NULL;
|
||||||
@ -952,7 +940,9 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
|
|||||||
AST *oldChunk = (AST*) P->currentChunk;
|
AST *oldChunk = (AST*) P->currentChunk;
|
||||||
P->currentChunk = &ret->chunk;
|
P->currentChunk = &ret->chunk;
|
||||||
|
|
||||||
P->scope = vartable_new(P->scope);
|
VarTable *oldScope = P->scope;
|
||||||
|
|
||||||
|
P->scope = isTopLevel ? toplevelParent : vartable_new(oldScope);
|
||||||
|
|
||||||
ASTChunk *oldTopLevel = P->topLevel;
|
ASTChunk *oldTopLevel = P->topLevel;
|
||||||
if(isTopLevel) {
|
if(isTopLevel) {
|
||||||
@ -963,8 +953,9 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
|
|||||||
|
|
||||||
/* 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 those can only mean symbol declarations */
|
||||||
|
|
||||||
|
P->skimMode++;
|
||||||
{
|
{
|
||||||
size_t oldIdx = P->i;
|
intmax_t oldIdx = P->i;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
TokenKind k = get(P).type;
|
TokenKind k = get(P).type;
|
||||||
@ -985,7 +976,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
|
|||||||
/* Move back to beginning of declaration. */
|
/* Move back to beginning of declaration. */
|
||||||
do {
|
do {
|
||||||
P->i--;
|
P->i--;
|
||||||
} while(P->i >= 0 && P->tokens[P->i].type != TOKEN_SEMICOLON && P->tokens[P->i].type != TOKEN_SQUIGGLY_R);
|
} 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++;
|
P->i++;
|
||||||
|
|
||||||
AST *d = parse_declaration(P);
|
AST *d = parse_declaration(P);
|
||||||
@ -996,6 +987,24 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
|
|||||||
}
|
}
|
||||||
P->i = oldIdx;
|
P->i = oldIdx;
|
||||||
}
|
}
|
||||||
|
P->skimMode--;
|
||||||
|
|
||||||
|
/* Arguments */
|
||||||
|
if(ft && isTopLevel) {
|
||||||
|
VarTableEntry **vtes = alloca(sizeof(*vtes) * ft->function.argCount);
|
||||||
|
|
||||||
|
for(int i = ft->function.argCount - 1; i >= 0; i--) {
|
||||||
|
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||||
|
vte->kind = VARTABLEENTRY_VAR;
|
||||||
|
vte->type = ft->function.args[i];
|
||||||
|
vte->data.var.name = ft->function.argNames[i];
|
||||||
|
vte->data.var.color = -1;
|
||||||
|
|
||||||
|
vartable_set(toplevelParent, vte->data.var.name, vte);
|
||||||
|
|
||||||
|
vtes[i] = vte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Now actual parsing. */
|
/* Now actual parsing. */
|
||||||
|
|
||||||
@ -1023,7 +1032,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
P->scope = P->scope->parent;
|
P->scope = oldScope;
|
||||||
|
|
||||||
P->currentChunk = oldChunk;
|
P->currentChunk = oldChunk;
|
||||||
|
|
||||||
@ -1038,5 +1047,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);
|
return (AST*) nct_parse_chunk(&P, 1, 0, vartable_new(NULL), NULL);
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,8 @@ int type_equal(Type *O, Type *T) {
|
|||||||
if(!type_equal(O->function.args[i], T->function.args[i])) {
|
if(!type_equal(O->function.args[i], T->function.args[i])) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't compare argument names
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -39,6 +39,7 @@ typedef struct TypeFunction {
|
|||||||
|
|
||||||
union Type *ret;
|
union Type *ret;
|
||||||
|
|
||||||
|
char **argNames;
|
||||||
union Type **args;
|
union Type **args;
|
||||||
size_t argCount;
|
size_t argCount;
|
||||||
} TypeFunction;
|
} TypeFunction;
|
||||||
|
@ -53,6 +53,7 @@ typedef struct VarTableEntry {
|
|||||||
// a more advanced approach would be to use weights for different colors (e.g. multipliers "should" be in eax)
|
// a more advanced approach would be to use weights for different colors (e.g. multipliers "should" be in eax)
|
||||||
uint8_t priority;
|
uint8_t priority;
|
||||||
int16_t color, degree;
|
int16_t color, degree;
|
||||||
|
bool precolored;
|
||||||
|
|
||||||
// Used during parsing
|
// Used during parsing
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define COLOR_EAX 0
|
#define COLOR_EAX 0
|
||||||
#define COLOR_EBX 1
|
#define COLOR_ECX 1
|
||||||
#define COLOR_ECX 2
|
#define COLOR_EDX 2
|
||||||
#define COLOR_EDX 3
|
#define COLOR_EBX 3
|
||||||
|
|
||||||
// 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
|
||||||
|
Loading…
Reference in New Issue
Block a user