gingus
This commit is contained in:
parent
f349fc1d56
commit
2c6033e501
175
src/ast.c
175
src/ast.c
@ -26,7 +26,9 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v
|
||||
}
|
||||
} 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);
|
||||
if(n->stmtAssign.to) {
|
||||
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);
|
||||
@ -73,6 +75,9 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v
|
||||
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 if(n->nodeKind == AST_EXPR_EXT_SALLOC) {
|
||||
} else if(n->nodeKind == AST_EXPR_DOT) {
|
||||
generic_visitor(&n->exprDot.a, stmt, stmtPrev, chu, tlc, ud, handler);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
@ -219,9 +224,15 @@ static void adduse(VarTableEntry *vte, AST *use, AST *whole) {
|
||||
|
||||
assert(vte->data.var.reachingDefs != NULL);
|
||||
|
||||
for(size_t d = 0; d < vte->data.var.reachingDefs->defCount; d++) {
|
||||
ReachingDefs *rd = vte->data.var.reachingDefs;
|
||||
|
||||
while(rd && rd->defCount == 0) rd = rd->parent;
|
||||
|
||||
if(!rd) return;
|
||||
|
||||
for(size_t d = 0; d < rd->defCount; d++) {
|
||||
UseDef *ud = malloc(sizeof(*ud));
|
||||
ud->def = vte->data.var.reachingDefs->defs[d];
|
||||
ud->def = rd->defs[d];
|
||||
ud->use = use;
|
||||
ud->stmt = whole;
|
||||
ud->next = NULL;
|
||||
@ -371,6 +382,7 @@ static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) {
|
||||
} else if(a->nodeKind == AST_EXPR_CAST) {
|
||||
ast_usedef_pass(tlc, a->exprCast.what, wholestmt);
|
||||
} else if(a->nodeKind == AST_EXPR_STACK_POINTER) {
|
||||
} else if(a->nodeKind == AST_EXPR_EXT_SALLOC) {
|
||||
} else if(a->nodeKind == AST_STMT_BREAK) {
|
||||
} else if(a->nodeKind == AST_STMT_CONTINUE) {
|
||||
} else if(a->nodeKind == AST_STMT_EXT_ALIGN) {
|
||||
@ -441,6 +453,8 @@ char *type_to_string(Type *t) {
|
||||
char *r = malp("%s*", c);
|
||||
free(c);
|
||||
return r;
|
||||
} else if(t->type == TYPE_TYPE_RECORD) {
|
||||
return malp("%s", t->record.name);
|
||||
}
|
||||
|
||||
return strdup("@unimp");
|
||||
@ -523,6 +537,9 @@ static char *ast_dumpe(AST *e) {
|
||||
case BINOP_GEQUAL:
|
||||
op = ">=";
|
||||
break;
|
||||
case BINOP_MULHI:
|
||||
op = "*^";
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@ -571,6 +588,23 @@ static char *ast_dumpe(AST *e) {
|
||||
out = out2;
|
||||
}
|
||||
return out;
|
||||
} else if(e->nodeKind == AST_EXPR_EXT_SALLOC) {
|
||||
char *w = type_to_string(e->exprExtSalloc.size);
|
||||
char *out = malp("@salloc(%s)", w);
|
||||
free(w);
|
||||
return out;
|
||||
} else if(e->nodeKind == AST_EXPR_CAST) {
|
||||
char *a = ast_dumpe(e->exprCast.what);
|
||||
char *b = type_to_string(e->exprCast.to);
|
||||
char *out = malp("(%s as %s)", a, b);
|
||||
free(a);
|
||||
free(b);
|
||||
return out;
|
||||
} else if(e->nodeKind == AST_EXPR_DOT) {
|
||||
char *a = ast_dumpe(e->exprDot.a);
|
||||
char *out = malp(e->nodeKind == AST_EXPR_BINARY_OP ? "(%s).%s" : "%s.%s", a, e->exprDot.b);
|
||||
free(a);
|
||||
return out;
|
||||
}
|
||||
|
||||
return malp("@unimp:%s", AST_KIND_STR[e->nodeKind]);
|
||||
@ -671,3 +705,138 @@ AST *ast_deep_copy(AST *src) {
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
AST *ast_cast_expr(AST *what, Type *to) {
|
||||
if(what == NULL) goto fail;
|
||||
|
||||
/* Only exists at parse-time, hence not part of type system and is handled separately */
|
||||
if(what->nodeKind == AST_EXPR_STRING_LITERAL) {
|
||||
if(to->type == TYPE_TYPE_ARRAY && type_equal(primitive_parse("u8"), to->array.of) && to->array.length == what->exprStrLit.length) {
|
||||
ASTExprArray *ret = malloc(sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_ARRAY;
|
||||
ret->items = malloc(sizeof(*ret->items) * to->array.length);
|
||||
ret->type = to;
|
||||
|
||||
for(int i = 0; i < to->array.length; i++) {
|
||||
uint8_t bajt = what->exprStrLit.data[i];
|
||||
|
||||
ASTExprPrimitive *item = malloc(sizeof(*item));
|
||||
item->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
item->type = to->array.of;
|
||||
item->val = bajt;
|
||||
|
||||
ret->items[i] = (AST*) item;
|
||||
}
|
||||
|
||||
return (AST*) ret;
|
||||
} else if(to->type == TYPE_TYPE_PRIMITIVE) {
|
||||
if(to->primitive.width != what->exprStrLit.length * 8) {
|
||||
stahp(0, 0, "Size mismatch between string literal and target type");
|
||||
}
|
||||
|
||||
ASTExprPrimitive *ret = malloc(sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
ret->type = to;
|
||||
memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val));
|
||||
return (AST*) ret;
|
||||
} else abort();
|
||||
}
|
||||
|
||||
if(type_equal(what->expression.type, to)) return what;
|
||||
|
||||
if(!type_is_castable(what->expression.type, to)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(what->nodeKind == AST_EXPR_PRIMITIVE && (to->type == TYPE_TYPE_PRIMITIVE || to->type == TYPE_TYPE_POINTER)) {
|
||||
ASTExprPrimitive *ret = malloc(sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
ret->type = to;
|
||||
|
||||
if(to->type == TYPE_TYPE_PRIMITIVE) {
|
||||
ret->val = what->exprPrim.val & ((1UL << to->primitive.width) - 1);
|
||||
} else {
|
||||
ret->val = what->exprPrim.val & ((1UL << (8 * type_size(to))) - 1);
|
||||
}
|
||||
|
||||
return (AST*) ret;
|
||||
} else {
|
||||
ASTExprCast *ret = malloc(sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_CAST;
|
||||
ret->type = to;
|
||||
ret->what = what;
|
||||
ret->to = to;
|
||||
return (AST*) ret;
|
||||
}
|
||||
|
||||
fail:
|
||||
stahp(0, 0, "Cannot cast type %s into %s", type_to_string(what->expression.type), type_to_string(to));
|
||||
}
|
||||
|
||||
struct Spill2StackState {
|
||||
AST *targetTLC;
|
||||
VarTableEntry *target;
|
||||
size_t stackGrowth;
|
||||
};
|
||||
static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||
struct Spill2StackState *this = ud;
|
||||
|
||||
if(tlc != this->targetTLC) {
|
||||
// Don't do anything.
|
||||
return;
|
||||
}
|
||||
|
||||
AST *a = *aptr;
|
||||
|
||||
if(a == tlc) {
|
||||
a->chunk.stackReservation += this->stackGrowth;
|
||||
} else if(a->nodeKind == AST_EXPR_VAR) {
|
||||
|
||||
if(a->exprVar.thing == this->target) {
|
||||
// DO THE SPILL
|
||||
|
||||
ASTExprStackPointer *rsp = malloc(sizeof(*rsp));
|
||||
rsp->nodeKind = AST_EXPR_STACK_POINTER;
|
||||
rsp->type = primitive_parse("u32");
|
||||
|
||||
ASTExprPrimitive *offset = malloc(sizeof(*offset));
|
||||
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
offset->type = rsp->type;
|
||||
offset->val = -this->stackGrowth; // This will be affected by the other part of this pass, so we must reverse
|
||||
|
||||
ASTExprBinaryOp *bop = malloc(sizeof(*bop));
|
||||
bop->nodeKind = AST_EXPR_BINARY_OP;
|
||||
bop->type = rsp->type;
|
||||
bop->operator = BINOP_ADD;
|
||||
bop->operands[0] = (AST*) rsp;
|
||||
bop->operands[1] = (AST*) offset;
|
||||
|
||||
ASTExprUnaryOp *deref = malloc(sizeof(*deref));
|
||||
deref->nodeKind = AST_EXPR_UNARY_OP;
|
||||
deref->type = a->expression.type;
|
||||
deref->operator = UNOP_DEREF;
|
||||
deref->operand = (AST*) bop;
|
||||
|
||||
*aptr = (AST*) deref;
|
||||
}
|
||||
|
||||
} else if(a->nodeKind == AST_EXPR_BINARY_OP && a->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && a->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
|
||||
|
||||
// Guaranteed to not require more dumbification
|
||||
a->exprBinOp.operands[1]->exprPrim.val += this->stackGrowth;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ast_spill_to_stack(AST *tlc, VarTableEntry *vte) {
|
||||
assert(vte != NULL);
|
||||
assert(tlc->nodeKind == AST_CHUNK);
|
||||
|
||||
struct Spill2StackState state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.target = vte;
|
||||
state.targetTLC = tlc;
|
||||
state.stackGrowth = (type_size(vte->type) + 7) & ~7;
|
||||
|
||||
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor);
|
||||
}
|
||||
|
41
src/ast.h
41
src/ast.h
@ -45,7 +45,9 @@
|
||||
K(AST_EXPR_FUNC) \
|
||||
K(AST_STMT_EXT_ORG) \
|
||||
K(AST_STMT_EXT_SECTION) \
|
||||
K(AST_STMT_RETURN)
|
||||
K(AST_STMT_RETURN) \
|
||||
K(AST_EXPR_EXT_SALLOC) \
|
||||
K(AST_EXPR_DOT)
|
||||
|
||||
typedef enum ENUMPAK { AST_KINDS(GEN_ENUM) } ASTKind;
|
||||
extern const char *AST_KIND_STR[];
|
||||
@ -56,17 +58,23 @@ typedef enum ENUMPAK {
|
||||
BINOP_BITWISE_AND = 2,
|
||||
BINOP_BITWISE_OR = 3,
|
||||
BINOP_BITWISE_XOR = 4,
|
||||
|
||||
BINOP_SIMPLES = 5,
|
||||
|
||||
BINOP_MUL = 5,
|
||||
BINOP_DIV = 6,
|
||||
|
||||
BINOP_EQUAL = 7,
|
||||
BINOP_NEQUAL = 8,
|
||||
BINOP_LESS = 9,
|
||||
BINOP_GREATER = 10,
|
||||
BINOP_LEQUAL = 11,
|
||||
BINOP_GEQUAL = 12,
|
||||
BINOP_2OPS = 7,
|
||||
|
||||
BINOP_MULHI = 7,
|
||||
BINOP_MOD = 8,
|
||||
|
||||
BINOP_EQUAL = 9,
|
||||
BINOP_NEQUAL = 10,
|
||||
BINOP_LESS = 11,
|
||||
BINOP_GREATER = 12,
|
||||
BINOP_LEQUAL = 13,
|
||||
BINOP_GEQUAL = 14,
|
||||
|
||||
BINOP_WTF = 999,
|
||||
} BinaryOp;
|
||||
@ -261,6 +269,19 @@ typedef struct {
|
||||
union AST **items;
|
||||
} ASTExprArray;
|
||||
|
||||
typedef struct {
|
||||
ASTExpr;
|
||||
|
||||
Type *size;
|
||||
} ASTExprExtSalloc;
|
||||
|
||||
typedef struct {
|
||||
ASTExpr;
|
||||
|
||||
union AST *a;
|
||||
const char *b;
|
||||
} ASTExprDot;
|
||||
|
||||
typedef struct {
|
||||
ASTStmt;
|
||||
|
||||
@ -303,6 +324,8 @@ typedef union AST {
|
||||
ASTExprCast exprCast;
|
||||
ASTExprArray exprArray;
|
||||
ASTExprFunc exprFunc;
|
||||
ASTExprDot exprDot;
|
||||
ASTExprExtSalloc exprExtSalloc;
|
||||
ASTStmtExtOrg stmtExtOrg;
|
||||
ASTStmtExtSection stmtExtSection;
|
||||
} AST;
|
||||
@ -322,6 +345,10 @@ char *ast_dump(AST *tlc);
|
||||
|
||||
AST *ast_deep_copy(AST*);
|
||||
|
||||
AST *ast_cast_expr(AST *what, Type *to);
|
||||
|
||||
void ast_spill_to_stack(AST *tlc, VarTableEntry *vte);
|
||||
|
||||
__attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
|
267
src/cg.c
267
src/cg.c
@ -101,10 +101,28 @@ static const char *xj(BinaryOp op) {
|
||||
case BINOP_GREATER: return "a";
|
||||
case BINOP_LEQUAL: return "be";
|
||||
case BINOP_GEQUAL: return "ae";
|
||||
default: return "wtf";
|
||||
default: abort(); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static AST *is_field_access(AST *e) {
|
||||
if(e->nodeKind != AST_EXPR_UNARY_OP || e->exprUnOp.operator != UNOP_DEREF) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
e = e->exprUnOp.operand;
|
||||
|
||||
if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) {
|
||||
e = e->exprCast.what;
|
||||
}
|
||||
|
||||
if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_ADD && e->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && e->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *xop_sz(AST *tlc, AST *e, int sz) {
|
||||
#define XOPBUFS 16
|
||||
#define XOPBUFSZ 24
|
||||
@ -113,7 +131,48 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
|
||||
|
||||
char *ret = bufs[bufidx];
|
||||
|
||||
if(e->nodeKind == AST_EXPR_STACK_POINTER) {
|
||||
if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) {
|
||||
e = e->exprCast.what;
|
||||
}
|
||||
|
||||
if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
|
||||
AST *p = e->exprUnOp.operand;
|
||||
|
||||
if(p->nodeKind == AST_EXPR_CAST && p->exprCast.to->type == TYPE_TYPE_POINTER) {
|
||||
p = p->exprCast.what;
|
||||
}
|
||||
|
||||
if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && p->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||
snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
|
||||
spec(sz),
|
||||
xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 4),
|
||||
xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 4));
|
||||
} else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && p->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && p->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||
snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
|
||||
spec(sz),
|
||||
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||
xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 4));
|
||||
} else if(is_field_access(e)) {
|
||||
e = is_field_access(e);
|
||||
snprintf(ret, XOPBUFSZ, "%s [%s + %i]",
|
||||
spec(sz),
|
||||
e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||
e->exprBinOp.operands[1]->exprPrim.val);
|
||||
} else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && p->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && p->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && p->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||
snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]",
|
||||
spec(sz),
|
||||
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||
p->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val,
|
||||
xv_sz(p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 4));
|
||||
} else if(p->nodeKind == AST_EXPR_VAR && p->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||
snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(p->exprVar.thing, 4));
|
||||
} else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
|
||||
snprintf(ret, XOPBUFSZ, "[esp + %i]", p->exprBinOp.operands[1]->exprPrim.val);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else if(e->nodeKind == AST_EXPR_STACK_POINTER) {
|
||||
snprintf(ret, XOPBUFSZ, "esp", tlc->chunk.stackReservation);
|
||||
} else if(e->nodeKind == AST_EXPR_VAR) {
|
||||
VarTableEntry *v = e->exprVar.thing;
|
||||
@ -124,34 +183,9 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
|
||||
snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), 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 + %s]",
|
||||
spec(sz),
|
||||
e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||
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) {
|
||||
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_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 4));
|
||||
snprintf(ret, XOPBUFSZ, "%s %i", spec(type_size(e->exprPrim.type)), e->exprPrim.val);
|
||||
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == 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 [%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) {
|
||||
snprintf(ret, XOPBUFSZ, "[esp + %i]", e->exprUnOp.operand->exprBinOp.operands[1]->exprPrim.val + tlc->chunk.stackReservation);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
@ -275,7 +309,37 @@ void cg_chunk(CGState *cg, AST *a) {
|
||||
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
|
||||
} 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(x86_imul_supported() && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) {
|
||||
assert(s->stmtAssign.what->nodeKind == AST_EXPR_VAR);
|
||||
assert(s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||
|
||||
if(!strcmp(xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[0]))) {
|
||||
printf("imul %s, %s\n", xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[1]));
|
||||
} else {
|
||||
printf("imul %s, %s, %s\n", xop(a, s->stmtAssign.what), xop(a, s->stmtAssign.to->exprBinOp.operands[0]), xop(a, s->stmtAssign.to->exprBinOp.operands[1]));
|
||||
}
|
||||
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MULHI) {
|
||||
assert(s->stmtAssign.what->nodeKind == AST_EXPR_VAR);
|
||||
assert(s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR);
|
||||
assert(s->stmtAssign.what->exprVar.thing->data.var.color == COLOR_EDX);
|
||||
|
||||
assert(s->statement.next->nodeKind == AST_STMT_ASSIGN);
|
||||
assert(s->statement.next->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP);
|
||||
assert(s->statement.next->stmtAssign.to->exprBinOp.operator == BINOP_MUL);
|
||||
|
||||
AST *otherop = NULL;
|
||||
if(ast_expression_equal(s->statement.next->stmtAssign.to->exprBinOp.operands[0], s->statement.next->stmtAssign.what)) {
|
||||
otherop = s->statement.next->stmtAssign.to->exprBinOp.operands[1];
|
||||
} else if(ast_expression_equal(s->statement.next->stmtAssign.to->exprBinOp.operands[1], s->statement.next->stmtAssign.what)) {
|
||||
otherop = s->statement.next->stmtAssign.to->exprBinOp.operands[0];
|
||||
} else abort();
|
||||
|
||||
printf("mul %s\n", xop(a, otherop));
|
||||
|
||||
// Skip next statement, because they come in a pair
|
||||
s = s->statement.next;
|
||||
|
||||
} 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_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) {
|
||||
|
||||
// inc or dec
|
||||
|
||||
@ -477,57 +541,8 @@ static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk,
|
||||
}
|
||||
}
|
||||
|
||||
struct Spill2StackState {
|
||||
AST *targetTLC;
|
||||
VarTableEntry *target;
|
||||
};
|
||||
static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||
struct Spill2StackState *this = ud;
|
||||
|
||||
if(tlc != this->targetTLC) {
|
||||
// Don't do anything.
|
||||
return;
|
||||
}
|
||||
|
||||
AST *a = *aptr;
|
||||
|
||||
if(a == tlc) {
|
||||
a->chunk.stackReservation += 4;
|
||||
} else if(a->nodeKind == AST_EXPR_VAR) {
|
||||
|
||||
if(a->exprVar.thing == this->target) {
|
||||
// DO THE SPILL
|
||||
|
||||
ASTExprStackPointer *rsp = malloc(sizeof(*rsp));
|
||||
rsp->nodeKind = AST_EXPR_STACK_POINTER;
|
||||
rsp->type = primitive_parse("u32");
|
||||
|
||||
ASTExprPrimitive *offset = malloc(sizeof(*offset));
|
||||
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
offset->type = rsp->type;
|
||||
offset->val = -tlc->chunk.stackReservation;
|
||||
|
||||
ASTExprBinaryOp *bop = malloc(sizeof(*bop));
|
||||
bop->nodeKind = AST_EXPR_BINARY_OP;
|
||||
bop->type = rsp->type;
|
||||
bop->operator = BINOP_ADD;
|
||||
bop->operands[0] = (AST*) rsp;
|
||||
bop->operands[1] = (AST*) offset;
|
||||
|
||||
ASTExprUnaryOp *deref = malloc(sizeof(*deref));
|
||||
deref->nodeKind = AST_EXPR_UNARY_OP;
|
||||
deref->type = a->expression.type;
|
||||
deref->operator = UNOP_DEREF;
|
||||
deref->operand = (AST*) bop;
|
||||
|
||||
*aptr = (AST*) deref;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct PrecolorState {
|
||||
ASTExprVar *mustBeSpilled;
|
||||
VarTableEntry *mustBeSpilled;
|
||||
};
|
||||
static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||
struct PrecolorState *this = ud;
|
||||
@ -546,23 +561,21 @@ static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const int requiredColor = COLOR_EAX;
|
||||
|
||||
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
||||
// Precoloring collision!
|
||||
this->mustBeSpilled = vte;
|
||||
return;
|
||||
}
|
||||
|
||||
vte->data.var.color = requiredColor;
|
||||
vte->data.var.precolored = true;
|
||||
if(n->nodeKind == AST_STMT_RETURN && 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;
|
||||
|
||||
const int requiredColor = COLOR_EAX;
|
||||
|
||||
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
||||
// Precoloring collision!
|
||||
this->mustBeSpilled = vte;
|
||||
return;
|
||||
}
|
||||
|
||||
vte->data.var.color = requiredColor;
|
||||
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);
|
||||
|
||||
@ -576,6 +589,34 @@ static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A
|
||||
return;
|
||||
}
|
||||
|
||||
vte->data.var.color = requiredColor;
|
||||
vte->data.var.precolored = true;
|
||||
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MUL) {
|
||||
|
||||
VarTableEntry *vte = n->stmtAssign.what->exprVar.thing;
|
||||
|
||||
const int requiredColor = COLOR_EAX;
|
||||
|
||||
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
||||
// Precoloring collision!
|
||||
this->mustBeSpilled = vte;
|
||||
return;
|
||||
}
|
||||
|
||||
vte->data.var.color = requiredColor;
|
||||
vte->data.var.precolored = true;
|
||||
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MULHI) {
|
||||
|
||||
VarTableEntry *vte = n->stmtAssign.what->exprVar.thing;
|
||||
|
||||
const int requiredColor = COLOR_EDX;
|
||||
|
||||
if(vte->data.var.precolored && vte->data.var.color != requiredColor) {
|
||||
// Precoloring collision!
|
||||
this->mustBeSpilled = vte;
|
||||
return;
|
||||
}
|
||||
|
||||
vte->data.var.color = requiredColor;
|
||||
vte->data.var.precolored = true;
|
||||
}
|
||||
@ -771,27 +812,7 @@ 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);
|
||||
}
|
||||
int cg_go(AST *a) {
|
||||
do {
|
||||
struct PrecolorState state = {};
|
||||
generic_visitor(&a, NULL, NULL, a, a, &state, precolor_visitor);
|
||||
|
||||
ast_usedef_reset(a);
|
||||
|
||||
// Spill?
|
||||
VarTableEntry *vte = state.mustBeSpilled; // set if precoloring demands DIFFERENT colors for the same variable
|
||||
if(!vte) {
|
||||
// Find variables with the same color
|
||||
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);
|
||||
ast_usedef_reset(a);
|
||||
|
||||
size_t adjCount = 0;
|
||||
Adjacency *adjs = calloc(adjCount, sizeof(*adjs));
|
||||
@ -873,11 +894,17 @@ nextColor:;
|
||||
if(lastColor >= 4) {
|
||||
// Spill node with highest degree
|
||||
|
||||
struct Spill2StackState state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.target = vars[a->chunk.varCount - 1];
|
||||
VarTableEntry *chosen = NULL;
|
||||
for(ssize_t i = a->chunk.varCount - 1; i >= 0; i--) {
|
||||
if(!vars[i]->data.var.precolored) {
|
||||
chosen = vars[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
generic_visitor(&a, NULL, NULL, a, a, &state, spill2stack_visitor);
|
||||
assert(chosen != NULL);
|
||||
|
||||
ast_spill_to_stack(a, chosen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -9,18 +9,17 @@
|
||||
// can be trivially translated to the target architecture.
|
||||
//
|
||||
// This file along with CG is strictly for IA-32 and will fail for other
|
||||
// architecture.
|
||||
// architectures.
|
||||
|
||||
#include"x86.h"
|
||||
#include<string.h>
|
||||
|
||||
/* Split away complex expression into a new local variable */
|
||||
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
||||
static VarTableEntry *create_dumbtemp(AST *tlc, Type *itstype) {
|
||||
static size_t vidx = 0;
|
||||
|
||||
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||
vte->kind = VARTABLEENTRY_VAR;
|
||||
vte->type = e->expression.type;
|
||||
vte->type = itstype;
|
||||
vte->data.var.color = -1;
|
||||
vte->data.var.precolored = false;
|
||||
vte->data.var.degree = 0;
|
||||
@ -32,6 +31,13 @@ static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
||||
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
|
||||
tlc->chunk.vars[tlc->chunk.varCount - 1] = vte;
|
||||
|
||||
return vte;
|
||||
}
|
||||
|
||||
/* Split away complex expression into a new local variable */
|
||||
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
||||
VarTableEntry *vte = create_dumbtemp(tlc, e->expression.type);
|
||||
|
||||
// Alter AST
|
||||
|
||||
ASTExprVar *ev[2];
|
||||
@ -66,18 +72,6 @@ static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
||||
return varify(tlc, chunk, stmtPrev, stmt, e);
|
||||
}
|
||||
|
||||
static bool is_incomplete_mul(AST *stmt) {
|
||||
if(stmt->nodeKind != AST_STMT_ASSIGN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(stmt->stmtAssign.what->nodeKind != AST_EXPR_VAR) {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct DumbenState {
|
||||
int effective;
|
||||
};
|
||||
@ -121,12 +115,16 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
|
||||
|
||||
} 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)) {
|
||||
// ret specifically returns in eax always, so it needs to be in a precolored var
|
||||
AST *retval = s->stmtReturn.val;
|
||||
|
||||
if(retval && (!is_xop(retval) || retval->nodeKind == AST_EXPR_PRIMITIVE || (retval->nodeKind == AST_EXPR_VAR && retval->exprVar.thing->kind == VARTABLEENTRY_VAR && retval->exprVar.thing->data.var.color != COLOR_EAX))) {
|
||||
|
||||
s->stmtReturn.val = varify(tlc, chu, stmtPrev, s, s->stmtReturn.val);
|
||||
retval = s->stmtReturn.val = varify(tlc, chu, stmtPrev, s, retval);
|
||||
this->effective = 1;
|
||||
|
||||
vte_precolor(retval->exprVar.thing, COLOR_EAX);
|
||||
|
||||
}
|
||||
|
||||
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) {
|
||||
@ -136,30 +134,55 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
|
||||
// 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
|
||||
vte_precolor(s->stmtExpr.expr->exprVar.thing, COLOR_EAX);
|
||||
|
||||
// Purge this statement entirely, otherwise we'd have
|
||||
// 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);
|
||||
assert(chu->chunk.statementFirst->statement.next == s);
|
||||
chu->chunk.statementFirst->statement.next = s->statement.next;
|
||||
}
|
||||
|
||||
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
||||
this->effective = 1;
|
||||
|
||||
} else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.to) {
|
||||
|
||||
if(ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to) && stmtPrev) {
|
||||
// NOP; remove this statement from AST
|
||||
// This is a NOP, remove it from the 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
|
||||
if(s->stmtAssign.to->nodeKind == AST_EXPR_CALL && (s->stmtAssign.what->nodeKind != AST_EXPR_VAR || s->stmtAssign.what->exprVar.thing->kind != VARTABLEENTRY_VAR)) {
|
||||
|
||||
VarTableEntry *tmp = create_dumbtemp(tlc, s->stmtAssign.what->expression.type);
|
||||
|
||||
ASTExprVar *ev[2] = {calloc(1, sizeof(**ev)), calloc(1, sizeof(**ev))};
|
||||
ev[0]->nodeKind = AST_EXPR_VAR;
|
||||
ev[0]->type = tmp->type;
|
||||
ev[0]->thing = tmp;
|
||||
memcpy(ev[1], ev[0], sizeof(**ev));
|
||||
|
||||
ASTStmtAssign *assign2 = calloc(1, sizeof(*assign2));
|
||||
assign2->nodeKind = AST_STMT_ASSIGN;
|
||||
assign2->what = (AST*) s->stmtAssign.what;
|
||||
assign2->to = (AST*) ev[0];
|
||||
|
||||
s->stmtAssign.what = (AST*) ev[1];
|
||||
|
||||
assign2->next = s->stmtAssign.next;
|
||||
s->stmtAssign.next = (AST*) assign2;
|
||||
|
||||
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);
|
||||
@ -208,16 +231,58 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
|
||||
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;
|
||||
}
|
||||
WhysItBad_Huh because = x86_test_mul(stmtPrev, s);
|
||||
|
||||
/*if(!(s->statement.next && s->statement.next->nodeKind == AST_STMT_ASSIGN && s->statement.next->stmtAssign.)) {
|
||||
if(because == SRC0_IS_BAD_XOP) {
|
||||
s->stmtAssign.to->exprBinOp.operands[0] = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[0]);
|
||||
|
||||
}*/
|
||||
|
||||
// TODO: implement multiplication
|
||||
this->effective = 1;
|
||||
} else if(because == SRC1_IS_BAD_XOP) {
|
||||
s->stmtAssign.to->exprBinOp.operands[1] = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[1]);
|
||||
|
||||
this->effective = 1;
|
||||
} else if(because == MISSING_MULHI_FOR_MUL || because == DEST_NOT_SRC0) {// !stmtPrev || stmtPrev->nodeKind != AST_STMT_ASSIGN || stmtPrev->stmtAssign.to->nodeKind != AST_EXPR_BINARY_OP || stmtPrev->stmtAssign.to->exprBinOp.operator != BINOP_MULHI) {
|
||||
// Turn this:
|
||||
// a = b * c
|
||||
// Into this:
|
||||
// d = b
|
||||
// e = d *^ c
|
||||
// d = d * c
|
||||
// a = d
|
||||
|
||||
ASTExprVar *originalDestination = s->stmtAssign.what;
|
||||
|
||||
s->stmtAssign.to->exprBinOp.operands[0] = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[0]);
|
||||
|
||||
assert(stmtPrev->statement.next->nodeKind == AST_STMT_ASSIGN && stmtPrev->statement.next->stmtAssign.what->nodeKind == AST_EXPR_VAR && ast_expression_equal(stmtPrev->statement.next->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]));
|
||||
|
||||
if(!x86_imul_supported()) {
|
||||
ASTExprBinaryOp *mulhi = calloc(1, sizeof(*mulhi));
|
||||
mulhi->nodeKind = AST_EXPR_BINARY_OP;
|
||||
mulhi->type = s->stmtAssign.to->expression.type;
|
||||
mulhi->operator = BINOP_MULHI;
|
||||
mulhi->operands[0] = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[0]);
|
||||
mulhi->operands[1] = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[1]);
|
||||
|
||||
AST *hihalf = varify(tlc, chu, stmtPrev->statement.next, s, mulhi);
|
||||
|
||||
vte_precolor(hihalf->exprVar.thing, COLOR_EDX);
|
||||
}
|
||||
|
||||
s->stmtAssign.what = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[0]);
|
||||
|
||||
ASTStmtAssign *redest = calloc(1, sizeof(*redest));
|
||||
redest->nodeKind = AST_STMT_ASSIGN;
|
||||
redest->what = originalDestination;
|
||||
redest->to = ast_deep_copy(s->stmtAssign.to->exprBinOp.operands[0]);
|
||||
redest->next = s->stmtAssign.next;
|
||||
|
||||
s->stmtAssign.next = (AST*) redest;
|
||||
|
||||
vte_precolor(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, COLOR_EAX);
|
||||
|
||||
this->effective = 1;
|
||||
} else assert(because == NOT_AT_ALL_IT || because == GUCCI);
|
||||
|
||||
} 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:
|
||||
@ -310,13 +375,118 @@ static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A
|
||||
}
|
||||
}
|
||||
|
||||
static void decompose_symbol_record_field_access(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||
AST *n = *nptr;
|
||||
|
||||
if(n->nodeKind == AST_EXPR_DOT) {
|
||||
ASTExprUnaryOp *ref = calloc(1, sizeof(*ref));
|
||||
ref->nodeKind = AST_EXPR_UNARY_OP;
|
||||
ref->type = type_pointer_wrap(n->exprDot.a->expression.type);
|
||||
ref->operator = UNOP_REF;
|
||||
ref->operand = n->exprDot.a;
|
||||
|
||||
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
|
||||
offset->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
offset->type = primitive_parse("u32");
|
||||
|
||||
size_t f;
|
||||
for(f = 0; f < n->exprDot.a->expression.type->record.fieldCount; f++) {
|
||||
if(!strcmp(n->exprDot.a->expression.type->record.fieldNames[f], n->exprDot.b)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(f < n->exprDot.a->expression.type->record.fieldCount);
|
||||
|
||||
offset->val = n->exprDot.a->expression.type->record.fieldOffsets[f];
|
||||
|
||||
ASTExprBinaryOp *sum = calloc(1, sizeof(*sum));
|
||||
sum->nodeKind = AST_EXPR_BINARY_OP;
|
||||
sum->type = ref->type;
|
||||
sum->operator = BINOP_ADD;
|
||||
sum->operands[0] = (AST*) ref;
|
||||
sum->operands[1] = (AST*) offset;
|
||||
|
||||
AST *cast = ast_cast_expr((AST*) sum, type_pointer_wrap(n->exprDot.a->expression.type->record.fieldTypes[f]));
|
||||
|
||||
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
|
||||
deref->nodeKind = AST_EXPR_UNARY_OP;
|
||||
deref->type = cast->expression.type->pointer.of;
|
||||
deref->operator = UNOP_DEREF;
|
||||
deref->operand = cast;
|
||||
|
||||
*nptr = (AST*) deref;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_pointer2pointer_cast(AST *e) {
|
||||
return e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER;
|
||||
}
|
||||
|
||||
static bool is_double_field_access(AST *e) {
|
||||
return e->nodeKind == AST_EXPR_BINARY_OP && is_pointer2pointer_cast(e->exprBinOp.operands[0]) && e->exprBinOp.operands[0]->exprCast.what->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operands[0]->exprCast.what->exprBinOp.operator == e->exprBinOp.operator && e->exprBinOp.operator == BINOP_ADD && e->exprBinOp.operands[0]->exprCast.what->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && e->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE;
|
||||
}
|
||||
|
||||
static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||
AST *n = *nptr;
|
||||
|
||||
bool *success = ud;
|
||||
|
||||
if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_REF && n->exprUnOp.operand->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operand->exprUnOp.operator == UNOP_DEREF) {
|
||||
// Turn `&*a` into `a`
|
||||
|
||||
*nptr = n->exprUnOp.operand->exprUnOp.operand;
|
||||
|
||||
*success = true;
|
||||
} else if(is_double_field_access(n)) {
|
||||
// Turn `(p + x) as C + y` into `(p + (x + y)) as C`
|
||||
|
||||
n->exprBinOp.operands[0]->exprCast.what->exprBinOp.operands[1]->exprPrim.val += n->exprBinOp.operands[1]->exprPrim.val;
|
||||
|
||||
*nptr = n->exprBinOp.operands[0];
|
||||
|
||||
*success = true;
|
||||
} else if(n->nodeKind == AST_EXPR_CAST && n->exprCast.what->nodeKind == AST_EXPR_CAST) {
|
||||
// Turn `(p as A) as B` to `p as B`
|
||||
|
||||
n->exprCast.what = n->exprCast.what->exprCast.what;
|
||||
|
||||
*success = true;
|
||||
} else if(n->nodeKind == AST_EXPR_BINARY_OP && n->exprBinOp.operands[0]->nodeKind == AST_EXPR_BINARY_OP && n->exprBinOp.operator == BINOP_ADD && n->exprBinOp.operands[0]->exprBinOp.operator == BINOP_ADD && n->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && n->exprBinOp.operands[0]->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
|
||||
// Turn `(x + a) + b` into `x + (a + b)`
|
||||
|
||||
n->exprBinOp.operands[0]->exprBinOp.operands[1]->exprPrim.val += n->exprBinOp.operands[1]->exprPrim.val;
|
||||
|
||||
*nptr = n->exprBinOp.operands[0];
|
||||
|
||||
*success = true;
|
||||
}
|
||||
}
|
||||
|
||||
void dumben_pre(AST *tlc) {
|
||||
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor);
|
||||
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, decompose_symbol_record_field_access);
|
||||
|
||||
for(size_t t = 0; t < tlc->chunk.varCount; t++) {
|
||||
if(tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) {
|
||||
ast_spill_to_stack(tlc, tlc->chunk.vars[t]);
|
||||
}
|
||||
}
|
||||
|
||||
bool success;
|
||||
do {
|
||||
success = false;
|
||||
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor);
|
||||
} while(success);
|
||||
}
|
||||
|
||||
void dumben_go(AST* tlc) {
|
||||
size_t i = 0;
|
||||
while(1) {
|
||||
if(i == 20000) {
|
||||
puts("TOO MANY DUMBS");
|
||||
abort();
|
||||
}
|
||||
|
||||
fprintf(stderr, "; Dumbing down %lu...\n", i++);
|
||||
|
||||
struct DumbenState state;
|
||||
@ -329,5 +499,7 @@ void dumben_go(AST* tlc) {
|
||||
if(!successful) {
|
||||
break;
|
||||
}
|
||||
|
||||
fputs(ast_dump(tlc), stderr);
|
||||
}
|
||||
}
|
||||
|
27
src/lexer.c
27
src/lexer.c
@ -34,7 +34,7 @@ char *TOKEN_NAMES[] = {
|
||||
"'['",
|
||||
"']'",
|
||||
"'?'",
|
||||
"string"
|
||||
"string",
|
||||
"'!='",
|
||||
"'!'",
|
||||
"'continue'",
|
||||
@ -44,6 +44,10 @@ char *TOKEN_NAMES[] = {
|
||||
"'>='",
|
||||
"'<'",
|
||||
"'>'",
|
||||
"'*^'",
|
||||
"'record'",
|
||||
"'.'",
|
||||
"'as'",
|
||||
};
|
||||
|
||||
static int isAlpha(int c) {
|
||||
@ -62,7 +66,7 @@ static int isWS(int c) {
|
||||
return c == ' ' || c == '\n' || c == '\r' || c == '\b' || c == '\t';
|
||||
}
|
||||
|
||||
static size_t currentRow = 0;
|
||||
static size_t currentRow = 1;
|
||||
static size_t currentColumn = 0;
|
||||
static int ungetted = EOF;
|
||||
|
||||
@ -130,6 +134,10 @@ Token nct_tokenize(FILE *f) {
|
||||
return tok;
|
||||
} else if(c == '*') {
|
||||
tok.type = TOKEN_STAR;
|
||||
int c = nextc(f);
|
||||
if(c == '^') {
|
||||
tok.type = TOKEN_STAR_CARET;
|
||||
} else ungetc(c, f);
|
||||
return tok;
|
||||
} else if(c == '&') {
|
||||
tok.type = TOKEN_AMPERSAND;
|
||||
@ -197,6 +205,9 @@ Token nct_tokenize(FILE *f) {
|
||||
} else if(c == ',') {
|
||||
tok.type = TOKEN_COMMA;
|
||||
return tok;
|
||||
} else if(c == '.') {
|
||||
tok.type = TOKEN_DOT;
|
||||
return tok;
|
||||
} else if(c == '"') {
|
||||
int capacity = 5;
|
||||
char *content = malloc(capacity);
|
||||
@ -225,14 +236,14 @@ Token nct_tokenize(FILE *f) {
|
||||
tok.content = content;
|
||||
tok.length = i;
|
||||
return tok;
|
||||
} else if(isAlpha(c) || c == '@') {
|
||||
} else if(isAlpha(c) || c == '@' || c == '_') {
|
||||
int capacity = 5;
|
||||
char *content = malloc(capacity);
|
||||
|
||||
size_t i = 0;
|
||||
content[i++] = c;
|
||||
|
||||
while(c = nextc(f), (isAlphanum(c) || c == '@')) {
|
||||
while(c = nextc(f), (isAlphanum(c) || c == '@' || c == '_')) {
|
||||
if(i == capacity - 1) {
|
||||
content = realloc(content, capacity += 4);
|
||||
}
|
||||
@ -271,6 +282,14 @@ Token nct_tokenize(FILE *f) {
|
||||
free(content);
|
||||
tok.type = TOKEN_RETURN;
|
||||
return tok;
|
||||
} else if(!strcmp(content, "record")) {
|
||||
free(content);
|
||||
tok.type = TOKEN_RECORD;
|
||||
return tok;
|
||||
} else if(!strcmp(content, "as")) {
|
||||
free(content);
|
||||
tok.type = TOKEN_AS;
|
||||
return tok;
|
||||
}
|
||||
|
||||
tok.type = TOKEN_IDENTIFIER;
|
||||
|
@ -44,6 +44,10 @@ typedef enum {
|
||||
TOKEN_GEQUAL,
|
||||
TOKEN_LESS,
|
||||
TOKEN_GREATER,
|
||||
TOKEN_STAR_CARET,
|
||||
TOKEN_RECORD,
|
||||
TOKEN_DOT,
|
||||
TOKEN_AS,
|
||||
} TokenKind;
|
||||
|
||||
typedef struct {
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include"reporting.h"
|
||||
#include"cg.h"
|
||||
#include"dumberdowner.h"
|
||||
#include"x86.h"
|
||||
|
||||
static int argc;
|
||||
static char **argv;
|
||||
@ -25,6 +26,10 @@ int main(int argc_, char **argv_) {
|
||||
argc = argc_;
|
||||
argv = argv_;
|
||||
|
||||
if(x86_target() == IUNKNOWN86) {
|
||||
stahp(0, 0, "Unknown architecture %s", ntc_get_arg("target"));
|
||||
}
|
||||
|
||||
const char *in = ntc_get_arg("in");
|
||||
|
||||
FILE *f = in ? fopen(in, "rb") : stdin;
|
||||
@ -50,6 +55,10 @@ int main(int argc_, char **argv_) {
|
||||
|
||||
while(!cg_go(chunk)) {
|
||||
dumben_go(chunk);
|
||||
|
||||
fputs("\n; === Spill ===\n", stderr);
|
||||
fputs(ast_dump(chunk), stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
316
src/parse.c
316
src/parse.c
@ -157,75 +157,23 @@ static AST *exprvar(Parser *P, VarTableEntry *v) {
|
||||
return a;
|
||||
}
|
||||
|
||||
AST *nct_cast_expr(AST *what, Type *to) {
|
||||
if(what == NULL) return NULL;
|
||||
|
||||
/* Only exists at parse-time, hence not part of type system and is handled separately */
|
||||
if(what->nodeKind == AST_EXPR_STRING_LITERAL) {
|
||||
if(to->type == TYPE_TYPE_ARRAY && type_equal(primitive_parse("u8"), to->array.of) && to->array.length == what->exprStrLit.length) {
|
||||
ASTExprArray *ret = malloc(sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_ARRAY;
|
||||
ret->items = malloc(sizeof(*ret->items) * to->array.length);
|
||||
ret->type = to;
|
||||
|
||||
for(int i = 0; i < to->array.length; i++) {
|
||||
uint8_t bajt = what->exprStrLit.data[i];
|
||||
|
||||
ASTExprPrimitive *item = malloc(sizeof(*item));
|
||||
item->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
item->type = to->array.of;
|
||||
item->val = bajt;
|
||||
|
||||
ret->items[i] = (AST*) item;
|
||||
}
|
||||
|
||||
return (AST*) ret;
|
||||
} else if(to->type == TYPE_TYPE_PRIMITIVE) {
|
||||
if(to->primitive.width != what->exprStrLit.length * 8) {
|
||||
stahp(0, 0, "Size mismatch between string literal and target type");
|
||||
}
|
||||
|
||||
ASTExprPrimitive *ret = malloc(sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
ret->type = to;
|
||||
memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val));
|
||||
return (AST*) ret;
|
||||
} else abort();
|
||||
}
|
||||
|
||||
if(type_equal(what->expression.type, to)) return what;
|
||||
|
||||
if(!type_is_castable(what->expression.type, to)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(what->nodeKind == AST_EXPR_PRIMITIVE && (to->type == TYPE_TYPE_PRIMITIVE || to->type == TYPE_TYPE_POINTER)) {
|
||||
ASTExprPrimitive *ret = malloc(sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
ret->type = to;
|
||||
|
||||
if(to->type == TYPE_TYPE_PRIMITIVE) {
|
||||
ret->val = what->exprPrim.val & ((1UL << to->primitive.width) - 1);
|
||||
} else {
|
||||
ret->val = what->exprPrim.val & ((1UL << (8 * type_size(to))) - 1);
|
||||
}
|
||||
|
||||
return (AST*) ret;
|
||||
} else {
|
||||
ASTExprCast *ret = malloc(sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_CAST;
|
||||
ret->type = to;
|
||||
ret->what = what;
|
||||
ret->to = to;
|
||||
return (AST*) ret;
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
ASTChunk *nct_parse_chunk(Parser*, int, int, VarTable*, Type *ft);
|
||||
Type *nct_parse_typename(Parser *P);
|
||||
|
||||
static void binop_implicit_cast(/*Parser *P, */ASTExprBinaryOp *binop) {
|
||||
if(type_size(binop->operands[0]->expression.type) < type_size(binop->operands[1]->expression.type)) {
|
||||
binop->operands[0] = ast_cast_expr(binop->operands[0], binop->operands[1]->expression.type);
|
||||
}
|
||||
|
||||
if(type_size(binop->operands[1]->expression.type) < type_size(binop->operands[0]->expression.type)) {
|
||||
binop->operands[1] = ast_cast_expr(binop->operands[1], binop->operands[0]->expression.type);
|
||||
}
|
||||
|
||||
if(!binop->type) {
|
||||
binop->type = binop->operands[0]->expression.type;
|
||||
}
|
||||
}
|
||||
|
||||
AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
if(lOP == 0) {
|
||||
// Test if this is an anonymous function
|
||||
@ -259,28 +207,44 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
}
|
||||
}
|
||||
|
||||
if(lOP == 5) {
|
||||
if(lOP == 6) {
|
||||
AST *e = NULL;
|
||||
|
||||
if(peek(P, 0).type == TOKEN_NUMBER) {
|
||||
return (AST*) parse_prim(P);
|
||||
e = (AST*) parse_prim(P);
|
||||
} else if(peek(P, 0).type == TOKEN_IDENTIFIER) {
|
||||
if(!strcmp(peek(P, 0).content, "@stack")) {
|
||||
get(P);
|
||||
|
||||
ASTExprStackPointer *ret = malloc(sizeof(*ret));
|
||||
ASTExprStackPointer *ret = calloc(1, sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_STACK_POINTER;
|
||||
ret->type = primitive_parse("u32");
|
||||
return (AST*) ret;
|
||||
|
||||
e = (AST*) ret;
|
||||
} else if(!strcmp(peek(P, 0).content, "@salloc")) {
|
||||
get(P);
|
||||
|
||||
expect(P, TOKEN_PAREN_L);
|
||||
|
||||
ASTExprExtSalloc *ret = calloc(1, sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_EXT_SALLOC;
|
||||
ret->size = nct_parse_typename(P);
|
||||
ret->type = type_pointer_wrap(ret->size);
|
||||
|
||||
expect(P, TOKEN_PAREN_R);
|
||||
|
||||
e = (AST*) ret;
|
||||
} else {
|
||||
Token varname = get(P);
|
||||
|
||||
VarTableEntry *vte = vartable_find(P->scope, varname.content);
|
||||
|
||||
if(!vte) {
|
||||
stahp(varname.row, varname.column, "Unknown variable %s", varname.content);
|
||||
}
|
||||
|
||||
e = (AST*) exprvar(P, vte);
|
||||
}
|
||||
|
||||
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) {
|
||||
ASTExprStringLiteral *ret = malloc(sizeof(*ret));
|
||||
ret->nodeKind = AST_EXPR_STRING_LITERAL;
|
||||
@ -291,13 +255,42 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
ret->data = tok.content;
|
||||
ret->length = tok.length;
|
||||
|
||||
return (AST*) ret;
|
||||
e = (AST*) ret;
|
||||
} else if(maybe(P, TOKEN_PAREN_L)) {
|
||||
AST *e = nct_parse_expression(P, 0);
|
||||
e = nct_parse_expression(P, 0);
|
||||
|
||||
expect(P, TOKEN_PAREN_R);
|
||||
return e;
|
||||
}
|
||||
} else if(lOP == 4) {
|
||||
|
||||
while(maybe(P, TOKEN_DOT)) {
|
||||
assert(e->expression.type->type == TYPE_TYPE_RECORD);
|
||||
|
||||
Token fieldTok = expect(P, TOKEN_IDENTIFIER);
|
||||
|
||||
ASTExprDot *d = calloc(1, sizeof(*d));
|
||||
d->nodeKind = AST_EXPR_DOT;
|
||||
d->a = (AST*) e;
|
||||
|
||||
bool foundField = false;
|
||||
|
||||
for(size_t f = 0; f < e->expression.type->record.fieldCount; f++) {
|
||||
char *fieldName = e->expression.type->record.fieldNames[f];
|
||||
if(!strcmp(fieldName, fieldTok.content)) {
|
||||
foundField = true;
|
||||
d->type = e->expression.type->record.fieldTypes[f];
|
||||
d->b = strdup(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundField) {
|
||||
stahp(fieldTok.row, fieldTok.column, "Field %s does not exist.", fieldTok.content);
|
||||
}
|
||||
|
||||
e = (AST*) d;
|
||||
}
|
||||
|
||||
return e;
|
||||
} else if(lOP == 5) {
|
||||
if(maybe(P, TOKEN_STAR)) {
|
||||
ASTExprUnaryOp *astop = malloc(sizeof(*astop));
|
||||
astop->nodeKind = AST_EXPR_UNARY_OP;
|
||||
@ -345,7 +338,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
return (AST *) astop;
|
||||
}
|
||||
} else return nct_parse_expression(P, lOP + 1);
|
||||
} else if(lOP == 3) {
|
||||
} else if(lOP == 4) {
|
||||
AST *ret = nct_parse_expression(P, lOP + 1);
|
||||
|
||||
while(peek(P, 0).type == TOKEN_PAREN_L || peek(P, 0).type == TOKEN_SQUAREN_L) {
|
||||
@ -365,7 +358,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
if(!maybe(P, TOKEN_PAREN_R)) {
|
||||
while(peek(P, 0).type != TOKEN_PAREN_R && peek(P, 0).type != TOKEN_COMMA) {
|
||||
call->args = realloc(call->args, (argCount + 1) * sizeof(AST*));
|
||||
call->args[argCount] = nct_parse_expression(P, 0);
|
||||
call->args[argCount] = ast_cast_expr(nct_parse_expression(P, 0), ret->expression.type->function.args[argCount]);
|
||||
|
||||
argCount++;
|
||||
|
||||
@ -423,13 +416,14 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else if(lOP == 2) {
|
||||
} else if(lOP == 3) {
|
||||
AST *ret = nct_parse_expression(P, lOP + 1);
|
||||
|
||||
if(peek(P, 0).type == TOKEN_STAR || peek(P, 0).type == TOKEN_SLASH) {
|
||||
if(peek(P, 0).type == TOKEN_STAR || peek(P, 0).type == TOKEN_SLASH || peek(P, 0).type == TOKEN_STAR_CARET) {
|
||||
while(1) {
|
||||
BinaryOp op;
|
||||
if(maybe(P, TOKEN_STAR)) op = BINOP_MUL;
|
||||
else if(maybe(P, TOKEN_STAR_CARET)) op = BINOP_MULHI;
|
||||
else if(maybe(P, TOKEN_SLASH)) op = BINOP_DIV;
|
||||
else break;
|
||||
|
||||
@ -455,12 +449,14 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
}
|
||||
}
|
||||
|
||||
binop_implicit_cast(astop);
|
||||
|
||||
ret = (AST*) astop;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else if(lOP == 1) {
|
||||
} else if(lOP == 2) {
|
||||
AST *ret = nct_parse_expression(P, lOP + 1);
|
||||
|
||||
if(
|
||||
@ -481,7 +477,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
|
||||
ASTExprBinaryOp *astop = malloc(sizeof(*astop));
|
||||
astop->nodeKind = AST_EXPR_BINARY_OP;
|
||||
astop->type = ret->expression.type;
|
||||
astop->type = NULL;
|
||||
astop->operator = op;
|
||||
astop->operands[0] = ret;
|
||||
|
||||
@ -493,26 +489,21 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Attempt to perform arithmetic on non-number types.");
|
||||
}
|
||||
|
||||
if(type_size(astop->operands[0]->expression.type) < type_size(astop->operands[1]->expression.type)) {
|
||||
astop->operands[0] = nct_cast_expr(astop->operands[0], astop->operands[1]->expression.type);
|
||||
}
|
||||
|
||||
if(type_size(astop->operands[1]->expression.type) < type_size(astop->operands[0]->expression.type)) {
|
||||
astop->operands[1] = nct_cast_expr(astop->operands[1], astop->operands[0]->expression.type);
|
||||
}
|
||||
|
||||
if(!astop->type) {
|
||||
astop->type = operand->type;
|
||||
} else {
|
||||
if(type_size(operand->type) > type_size(astop->type)) {
|
||||
astop->type = operand->type;
|
||||
}
|
||||
}
|
||||
binop_implicit_cast(astop);
|
||||
|
||||
ret = (AST*) astop;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else if(lOP == 1) {
|
||||
AST *ret = nct_parse_expression(P, lOP + 1);
|
||||
|
||||
while(maybe(P, TOKEN_AS)) {
|
||||
Type *castTo = nct_parse_typename(P);
|
||||
ret = ast_cast_expr(ret, castTo);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else if(lOP == 0) {
|
||||
AST *ret = nct_parse_expression(P, lOP + 1);
|
||||
@ -540,13 +531,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types.");
|
||||
}
|
||||
|
||||
if(!astop->type) {
|
||||
astop->type = operand->type;
|
||||
} else {
|
||||
if(type_size(operand->type) > type_size(astop->type)) {
|
||||
astop->type = operand->type;
|
||||
}
|
||||
}
|
||||
binop_implicit_cast(astop);
|
||||
|
||||
ret = (AST*) astop;
|
||||
}
|
||||
@ -571,7 +556,16 @@ Type *nct_parse_typename(Parser *P) {
|
||||
goto backtrack;
|
||||
}
|
||||
|
||||
Type *ret = (Type*) primitive_parse(expect(P, TOKEN_IDENTIFIER).content);
|
||||
Type *ret = NULL;
|
||||
|
||||
Token id = expect(P, TOKEN_IDENTIFIER);
|
||||
|
||||
VarTableEntry *potentialVTE = vartable_find(P->scope, id.content);
|
||||
if(potentialVTE && potentialVTE->kind == VARTABLEENTRY_TYPE) {
|
||||
ret = potentialVTE->data.type.ptr;
|
||||
} else {
|
||||
ret = (Type*) primitive_parse(id.content);
|
||||
}
|
||||
|
||||
if(!ret) {
|
||||
goto backtrack;
|
||||
@ -689,12 +683,12 @@ static AST *parse_declaration(Parser *P) {
|
||||
//reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign);
|
||||
|
||||
assign->what = exprvar(P, entry);
|
||||
assign->to = peek(P, 0).type == TOKEN_SEMICOLON ? NULL : nct_parse_expression(P, 0);
|
||||
assign->to = peek(P, 0).type == TOKEN_SEMICOLON ? NULL : ast_cast_expr(nct_parse_expression(P, 0), assign->what->expression.type);
|
||||
|
||||
ret = (AST*) assign;
|
||||
|
||||
} else {
|
||||
ASTStmtDecl *decl = malloc(sizeof(*ret));
|
||||
ASTStmtDecl *decl = calloc(1, sizeof(*ret));
|
||||
decl->nodeKind = AST_STMT_DECL;
|
||||
decl->thing = entry;
|
||||
decl->next = NULL;
|
||||
@ -714,16 +708,12 @@ static AST *parse_declaration(Parser *P) {
|
||||
decl->expression = nct_parse_expression(P, 0);
|
||||
|
||||
if(type) {
|
||||
decl->expression = nct_cast_expr(decl->expression, type);
|
||||
if(decl->expression) {
|
||||
decl->expression = ast_cast_expr(decl->expression, type);
|
||||
}
|
||||
} else {
|
||||
entry->type = decl->expression->expression.type;
|
||||
}
|
||||
|
||||
if(decl->expression) {
|
||||
//if(ret->expression->expression.constantType == EXPRESSION_NOT_CONSTANT) {
|
||||
// stahp(1, 4142, "Symbol declaration may contain constant expressions only.");
|
||||
//}
|
||||
}
|
||||
} else if(isExternal) {
|
||||
entry->kind = VARTABLEENTRY_SYMBOL;
|
||||
entry->data.symbol.isLocal = isLocal;
|
||||
@ -837,6 +827,24 @@ void nct_parse_statement(Parser *P) {
|
||||
|
||||
pushstat(P, ret);
|
||||
|
||||
return;
|
||||
} else if(maybe(P, TOKEN_RECORD)) {
|
||||
// Do nothing. This is handled in nct_parse_chunk.
|
||||
|
||||
expect(P, TOKEN_IDENTIFIER);
|
||||
expect(P, TOKEN_SQUIGGLY_L);
|
||||
size_t depth = 1;
|
||||
while(1) {
|
||||
TokenKind tk = get(P).type;
|
||||
if(tk == TOKEN_SQUIGGLY_L) {
|
||||
depth++;
|
||||
} else if(tk == TOKEN_SQUIGGLY_R) {
|
||||
depth--;
|
||||
if(depth == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if(peek(P, 0).type == TOKEN_IDENTIFIER) {
|
||||
if(!strcmp(peek(P, 0).content, "@align")) {
|
||||
@ -906,7 +914,7 @@ void nct_parse_statement(Parser *P) {
|
||||
ret->nodeKind = AST_STMT_ASSIGN;
|
||||
ret->next = NULL;
|
||||
ret->what = e;
|
||||
ret->to = nct_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type);
|
||||
ret->to = ast_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type);
|
||||
|
||||
//if(ret->what->nodeKind == AST_EXPR_VAR) {
|
||||
// reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret);
|
||||
@ -929,6 +937,54 @@ void nct_parse_statement(Parser *P) {
|
||||
}
|
||||
}
|
||||
|
||||
Type *nct_parse_record_definition(Parser *P) {
|
||||
expect(P, TOKEN_RECORD);
|
||||
|
||||
Token name = expect(P, TOKEN_IDENTIFIER);
|
||||
|
||||
expect(P, TOKEN_SQUIGGLY_L);
|
||||
|
||||
Type *tr = calloc(1, sizeof(TypeRecord));
|
||||
tr->type = TYPE_TYPE_RECORD;
|
||||
tr->record.name = strndup(name.content, name.length);
|
||||
|
||||
size_t nextOffset = 0;
|
||||
|
||||
while(peek(P, 0).type != TOKEN_SQUIGGLY_R) {
|
||||
if(peek(P, 0).type == TOKEN_NUMBER) {
|
||||
ASTExprPrimitive *explicitOffset = parse_prim(P);
|
||||
nextOffset = explicitOffset->val;
|
||||
free(explicitOffset);
|
||||
|
||||
expect(P, TOKEN_COLON);
|
||||
}
|
||||
|
||||
size_t fi = tr->record.fieldCount++;
|
||||
tr->record.fieldOffsets = realloc(tr->record.fieldOffsets, sizeof(*tr->record.fieldOffsets) * tr->record.fieldCount);
|
||||
tr->record.fieldTypes = realloc(tr->record.fieldTypes, sizeof(*tr->record.fieldTypes) * tr->record.fieldCount);
|
||||
tr->record.fieldNames = realloc(tr->record.fieldNames, sizeof(*tr->record.fieldNames) * tr->record.fieldCount);
|
||||
|
||||
Type *fieldType = nct_parse_typename(P);
|
||||
Token fieldName = expect(P, TOKEN_IDENTIFIER);
|
||||
|
||||
tr->record.fieldTypes[fi] = fieldType;
|
||||
tr->record.fieldNames[fi] = strndup(fieldName.content, fieldName.length);
|
||||
tr->record.fieldOffsets[fi] = nextOffset;
|
||||
|
||||
nextOffset += type_size(tr->record.fieldTypes[fi]);
|
||||
|
||||
if(tr->record.size < nextOffset) {
|
||||
tr->record.size = nextOffset;
|
||||
}
|
||||
|
||||
expect(P, TOKEN_SEMICOLON);
|
||||
}
|
||||
|
||||
expect(P, TOKEN_SQUIGGLY_R);
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
||||
ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable *toplevelParent, Type *ft) {
|
||||
AST *ret = calloc(1, sizeof(ASTChunk));
|
||||
ret->nodeKind = AST_CHUNK;
|
||||
@ -949,8 +1005,6 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable
|
||||
P->topLevel = &ret->chunk;
|
||||
}
|
||||
|
||||
//vartable_new_reachingdefs_for_all_vars(P->scope);
|
||||
|
||||
/* Find all symbol names and struct types ahead of time. Searches for colons as those can only mean symbol declarations */
|
||||
|
||||
P->skimMode++;
|
||||
@ -983,6 +1037,16 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable
|
||||
if(!d) abort();
|
||||
|
||||
free(d); /* We don't need it. */
|
||||
} else if(k == TOKEN_RECORD) {
|
||||
P->i--;
|
||||
|
||||
Type *tr = nct_parse_record_definition(P);
|
||||
|
||||
VarTableEntry *vte = calloc(1, sizeof(*vte));
|
||||
vte->kind = VARTABLEENTRY_TYPE;
|
||||
vte->data.type.ptr = tr;
|
||||
|
||||
vartable_set(P->scope, tr->record.name, vte);
|
||||
}
|
||||
}
|
||||
P->i = oldIdx;
|
||||
@ -1012,8 +1076,6 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable
|
||||
nct_parse_statement(P);
|
||||
}
|
||||
|
||||
//vartable_coalesce_reachingdefs_for_all_vars(P->scope);
|
||||
|
||||
size_t nonSymbols = 0;
|
||||
for(size_t i = 0; i < P->scope->count; i++) {
|
||||
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
|
||||
|
@ -72,6 +72,11 @@ Type *primitive_parse(const char *src) {
|
||||
ret->vector = 1;
|
||||
}
|
||||
|
||||
if(*src) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->next = primitiveDatabase[hash];
|
||||
primitiveDatabase[hash] = ret;
|
||||
|
||||
@ -94,6 +99,8 @@ size_t type_size(Type *t) {
|
||||
return 4;
|
||||
} else if(t->type == TYPE_TYPE_ARRAY) {
|
||||
return type_size(t->array.of) * t->array.length;
|
||||
} else if(t->type == TYPE_TYPE_RECORD) {
|
||||
return t->record.size;
|
||||
}
|
||||
|
||||
abort();
|
||||
|
16
src/types.h
16
src/types.h
@ -5,7 +5,7 @@
|
||||
#include<stdint.h>
|
||||
|
||||
typedef enum {
|
||||
TYPE_TYPE_PRIMITIVE, TYPE_TYPE_COMPOUND, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_ERROR
|
||||
TYPE_TYPE_PRIMITIVE, TYPE_TYPE_RECORD, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_ERROR
|
||||
} TypeType;
|
||||
|
||||
union Type;
|
||||
@ -51,6 +51,19 @@ typedef struct TypeArray {
|
||||
size_t length; /* 0 means unknown */
|
||||
} TypeArray;
|
||||
|
||||
typedef struct TypeRecord {
|
||||
TypeType type;
|
||||
|
||||
char *name;
|
||||
|
||||
size_t size;
|
||||
|
||||
union Type **fieldTypes;
|
||||
size_t *fieldOffsets;
|
||||
char **fieldNames;
|
||||
size_t fieldCount;
|
||||
} TypeRecord;
|
||||
|
||||
typedef union Type {
|
||||
TypeType type;
|
||||
|
||||
@ -58,6 +71,7 @@ typedef union Type {
|
||||
TypePointer pointer;
|
||||
TypeFunction function;
|
||||
TypeArray array;
|
||||
TypeRecord record;
|
||||
} Type;
|
||||
|
||||
extern Type TYPE_ERROR;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include"utils.h"
|
||||
#include<stdlib.h>
|
||||
#include<string.h>
|
||||
#include<assert.h>
|
||||
|
||||
struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) {
|
||||
struct ReachingDefs *ret = calloc(1, sizeof(*ret));
|
||||
@ -92,3 +93,11 @@ void vartable_coalesce_reachingdefs_for_all_vars(VarTable *this) {
|
||||
vartable_coalesce_reachingdefs_for_all_vars(this->parent);
|
||||
}
|
||||
}
|
||||
|
||||
void vte_precolor(VarTableEntry *vte, int color) {
|
||||
assert(vte->kind == VARTABLEENTRY_VAR);
|
||||
assert(!vte->data.var.precolored);
|
||||
|
||||
vte->data.var.precolored = true;
|
||||
vte->data.var.color = color;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include<stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
VARTABLEENTRY_SYMBOL, VARTABLEENTRY_STACK, VARTABLEENTRY_VAR
|
||||
VARTABLEENTRY_SYMBOL, VARTABLEENTRY_VAR, VARTABLEENTRY_TYPE
|
||||
} VarTableEntryKind;
|
||||
|
||||
union AST;
|
||||
@ -64,6 +64,9 @@ typedef struct VarTableEntry {
|
||||
UseDef *usedefFirst;
|
||||
UseDef *usedefLast;
|
||||
} var;
|
||||
struct {
|
||||
Type *ptr;
|
||||
} type;
|
||||
};
|
||||
} data;
|
||||
} VarTableEntry;
|
||||
@ -84,4 +87,6 @@ VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*);
|
||||
void vartable_new_reachingdefs_for_all_vars(VarTable*);
|
||||
void vartable_coalesce_reachingdefs_for_all_vars(VarTable*);
|
||||
|
||||
void vte_precolor(VarTableEntry *vte, int color);
|
||||
|
||||
#endif
|
||||
|
145
src/x86.h
145
src/x86.h
@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include<string.h>
|
||||
#include"ntc.h"
|
||||
#include<assert.h>
|
||||
|
||||
#define COLOR_EAX 0
|
||||
#define COLOR_ECX 1
|
||||
#define COLOR_EDX 2
|
||||
@ -10,6 +14,10 @@
|
||||
#define XOP_NOT_MEM 1
|
||||
#define XOP_MEM 2
|
||||
static inline int is_xop(AST *e) {
|
||||
if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) {
|
||||
e = e->exprCast.what;
|
||||
}
|
||||
|
||||
if(e->nodeKind == AST_EXPR_PRIMITIVE) {
|
||||
return XOP_NOT_MEM;
|
||||
} else if(e->nodeKind == AST_EXPR_VAR) {
|
||||
@ -21,6 +29,10 @@ static inline int is_xop(AST *e) {
|
||||
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
|
||||
AST *c = e->exprUnOp.operand;
|
||||
|
||||
if(c->nodeKind == AST_EXPR_CAST && c->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && c->exprCast.to->type == TYPE_TYPE_POINTER) {
|
||||
c = c->exprCast.what;
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -40,3 +52,136 @@ static inline int is_xop(AST *e) {
|
||||
|
||||
return XOP_NOT_XOP;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
NOT_AT_ALL_IT,
|
||||
DEST_IS_BAD_XOP,
|
||||
SRC0_IS_BAD_XOP,
|
||||
SRC1_IS_BAD_XOP,
|
||||
DEST_NOT_PRECOLORED,
|
||||
SRC0_NOT_PRECOLORED,
|
||||
SRC1_NOT_PRECOLORED,
|
||||
DEST_NOT_SRC0,
|
||||
MISSING_MULHI_FOR_MUL,
|
||||
GUCCI,
|
||||
} WhysItBad_Huh;
|
||||
|
||||
typedef enum {
|
||||
I086 = 0,
|
||||
I186 = 1,
|
||||
I286 = 2,
|
||||
I386 = 3,
|
||||
IUNKNOWN86 = 255,
|
||||
} X86Target;
|
||||
|
||||
static inline X86Target x86_target() {
|
||||
const char *str = ntc_get_arg("target");
|
||||
|
||||
if(!str) return I386;
|
||||
|
||||
if(!strcmp(str, "086")) {
|
||||
return I086;
|
||||
}
|
||||
|
||||
if(!strcmp(str, "186")) {
|
||||
return I186;
|
||||
}
|
||||
|
||||
if(!strcmp(str, "286")) {
|
||||
return I286;
|
||||
}
|
||||
|
||||
if(!strcmp(str, "386")) {
|
||||
return I386;
|
||||
}
|
||||
|
||||
return IUNKNOWN86;
|
||||
}
|
||||
|
||||
static inline size_t x86_max_gpr_size() {
|
||||
switch(x86_target()) {
|
||||
case I086:
|
||||
case I186:
|
||||
case I286:
|
||||
return 2;
|
||||
case I386:
|
||||
return 4;
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool x86_imul_supported() {
|
||||
return x86_target() >= I186;
|
||||
}
|
||||
|
||||
static inline WhysItBad_Huh x86_test_mul_matching_mulhi(AST *mulhi, AST *mul) {
|
||||
assert(mulhi->statement.next == mul);
|
||||
|
||||
if(mulhi->stmtAssign.to->nodeKind != AST_EXPR_BINARY_OP) {
|
||||
return NOT_AT_ALL_IT;
|
||||
}
|
||||
|
||||
if(mulhi->stmtAssign.to->exprBinOp.operator != BINOP_MULHI) {
|
||||
return NOT_AT_ALL_IT;
|
||||
}
|
||||
|
||||
if(!ast_expression_equal(mulhi->stmtAssign.to->exprBinOp.operands[0], mul->stmtAssign.to->exprBinOp.operands[0])) {
|
||||
return NOT_AT_ALL_IT;
|
||||
}
|
||||
|
||||
if(!ast_expression_equal(mulhi->stmtAssign.to->exprBinOp.operands[1], mul->stmtAssign.to->exprBinOp.operands[1])) {
|
||||
return NOT_AT_ALL_IT;
|
||||
}
|
||||
|
||||
if(is_xop(mulhi->stmtAssign.what) != XOP_NOT_MEM) {
|
||||
return DEST_IS_BAD_XOP;
|
||||
}
|
||||
|
||||
return GUCCI;
|
||||
}
|
||||
|
||||
static inline WhysItBad_Huh x86_test_mul(AST *stmtPrev, AST *stmt) {
|
||||
if(stmt->nodeKind != AST_STMT_ASSIGN) {
|
||||
return NOT_AT_ALL_IT;
|
||||
}
|
||||
|
||||
if(stmt->stmtAssign.to->nodeKind != AST_EXPR_BINARY_OP) {
|
||||
return NOT_AT_ALL_IT;
|
||||
}
|
||||
|
||||
if(stmt->stmtAssign.to->exprBinOp.operator != BINOP_MUL) {
|
||||
return NOT_AT_ALL_IT;
|
||||
}
|
||||
|
||||
if(stmt->stmtAssign.what->nodeKind != AST_EXPR_VAR || stmt->stmtAssign.what->exprVar.thing->kind != VARTABLEENTRY_VAR) {
|
||||
return DEST_IS_BAD_XOP;
|
||||
}
|
||||
|
||||
if(x86_imul_supported()) {
|
||||
return GUCCI;
|
||||
} else if(stmt->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
|
||||
return SRC1_IS_BAD_XOP;
|
||||
}
|
||||
|
||||
if(is_xop(stmt->stmtAssign.to->exprBinOp.operands[1]) == XOP_NOT_XOP) {
|
||||
return SRC1_IS_BAD_XOP;
|
||||
}
|
||||
|
||||
/*if(stmt->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && x86_get_target() < I186) {
|
||||
return SRC1_IS_BAD_XOP;
|
||||
}*/
|
||||
|
||||
if(!ast_expression_equal(stmt->stmtAssign.what, stmt->stmtAssign.to->exprBinOp.operands[0])) {
|
||||
return DEST_NOT_SRC0;
|
||||
}
|
||||
|
||||
if(!stmt->stmtAssign.what->exprVar.thing->data.var.precolored) {
|
||||
return DEST_NOT_PRECOLORED;
|
||||
}
|
||||
|
||||
if(x86_test_mul_matching_mulhi(stmtPrev, stmt) != GUCCI) {
|
||||
return MISSING_MULHI_FOR_MUL;
|
||||
}
|
||||
|
||||
return GUCCI;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user