This commit is contained in:
Mid 2025-02-27 20:10:02 +02:00
parent f349fc1d56
commit 2c6033e501
13 changed files with 966 additions and 297 deletions

175
src/ast.c
View File

@ -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);
}

View File

@ -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

261
src/cg.c
View File

@ -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);
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;
VarTableEntry *vte = n->stmtReturn.val->exprVar.thing;
const int requiredColor = COLOR_EAX;
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(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;
}

View File

@ -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;
s->stmtReturn.val = varify(tlc, chu, stmtPrev, s, 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))) {
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);
WhysItBad_Huh because = x86_test_mul(stmtPrev, s);
if(because == SRC0_IS_BAD_XOP) {
s->stmtAssign.to->exprBinOp.operands[0] = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[0]);
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]);
/*if(!(s->statement.next && s->statement.next->nodeKind == AST_STMT_ASSIGN && s->statement.next->stmtAssign.)) {
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;
// TODO: implement multiplication
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);
}
}

View File

@ -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;

View File

@ -44,6 +44,10 @@ typedef enum {
TOKEN_GEQUAL,
TOKEN_LESS,
TOKEN_GREATER,
TOKEN_STAR_CARET,
TOKEN_RECORD,
TOKEN_DOT,
TOKEN_AS,
} TokenKind;
typedef struct {

View File

@ -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;

View File

@ -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) {

View File

@ -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();

View File

@ -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;

View File

@ -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;
}

View File

@ -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
View File

@ -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;
}