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) { } else if(n->nodeKind == AST_STMT_ASSIGN) {
generic_visitor(&n->stmtAssign.what, stmt, stmtPrev, chu, tlc, ud, handler); 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) { } else if(n->nodeKind == AST_STMT_IF) {
generic_visitor(&n->stmtIf.expression, stmt, stmtPrev, chu, tlc, ud, handler); generic_visitor(&n->stmtIf.expression, stmt, stmtPrev, chu, tlc, ud, handler);
generic_visitor(&n->stmtIf.then, 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++) { for(size_t i = 0; i < n->expression.type->array.length; i++) {
generic_visitor(&n->exprArray.items[i], stmt, stmtPrev, chu, tlc, ud, handler); 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 { } else {
abort(); abort();
} }
@ -219,9 +224,15 @@ static void adduse(VarTableEntry *vte, AST *use, AST *whole) {
assert(vte->data.var.reachingDefs != NULL); 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)); UseDef *ud = malloc(sizeof(*ud));
ud->def = vte->data.var.reachingDefs->defs[d]; ud->def = rd->defs[d];
ud->use = use; ud->use = use;
ud->stmt = whole; ud->stmt = whole;
ud->next = NULL; 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) { } else if(a->nodeKind == AST_EXPR_CAST) {
ast_usedef_pass(tlc, a->exprCast.what, wholestmt); ast_usedef_pass(tlc, a->exprCast.what, wholestmt);
} else if(a->nodeKind == AST_EXPR_STACK_POINTER) { } 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_BREAK) {
} else if(a->nodeKind == AST_STMT_CONTINUE) { } else if(a->nodeKind == AST_STMT_CONTINUE) {
} else if(a->nodeKind == AST_STMT_EXT_ALIGN) { } else if(a->nodeKind == AST_STMT_EXT_ALIGN) {
@ -441,6 +453,8 @@ char *type_to_string(Type *t) {
char *r = malp("%s*", c); char *r = malp("%s*", c);
free(c); free(c);
return r; return r;
} else if(t->type == TYPE_TYPE_RECORD) {
return malp("%s", t->record.name);
} }
return strdup("@unimp"); return strdup("@unimp");
@ -523,6 +537,9 @@ static char *ast_dumpe(AST *e) {
case BINOP_GEQUAL: case BINOP_GEQUAL:
op = ">="; op = ">=";
break; break;
case BINOP_MULHI:
op = "*^";
break;
default: default:
abort(); abort();
} }
@ -571,6 +588,23 @@ static char *ast_dumpe(AST *e) {
out = out2; out = out2;
} }
return out; 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]); return malp("@unimp:%s", AST_KIND_STR[e->nodeKind]);
@ -671,3 +705,138 @@ AST *ast_deep_copy(AST *src) {
abort(); 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_EXPR_FUNC) \
K(AST_STMT_EXT_ORG) \ K(AST_STMT_EXT_ORG) \
K(AST_STMT_EXT_SECTION) \ 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; typedef enum ENUMPAK { AST_KINDS(GEN_ENUM) } ASTKind;
extern const char *AST_KIND_STR[]; extern const char *AST_KIND_STR[];
@ -56,17 +58,23 @@ typedef enum ENUMPAK {
BINOP_BITWISE_AND = 2, BINOP_BITWISE_AND = 2,
BINOP_BITWISE_OR = 3, BINOP_BITWISE_OR = 3,
BINOP_BITWISE_XOR = 4, BINOP_BITWISE_XOR = 4,
BINOP_SIMPLES = 5, BINOP_SIMPLES = 5,
BINOP_MUL = 5, BINOP_MUL = 5,
BINOP_DIV = 6, BINOP_DIV = 6,
BINOP_EQUAL = 7, BINOP_2OPS = 7,
BINOP_NEQUAL = 8,
BINOP_LESS = 9, BINOP_MULHI = 7,
BINOP_GREATER = 10, BINOP_MOD = 8,
BINOP_LEQUAL = 11,
BINOP_GEQUAL = 12, BINOP_EQUAL = 9,
BINOP_NEQUAL = 10,
BINOP_LESS = 11,
BINOP_GREATER = 12,
BINOP_LEQUAL = 13,
BINOP_GEQUAL = 14,
BINOP_WTF = 999, BINOP_WTF = 999,
} BinaryOp; } BinaryOp;
@ -261,6 +269,19 @@ typedef struct {
union AST **items; union AST **items;
} ASTExprArray; } ASTExprArray;
typedef struct {
ASTExpr;
Type *size;
} ASTExprExtSalloc;
typedef struct {
ASTExpr;
union AST *a;
const char *b;
} ASTExprDot;
typedef struct { typedef struct {
ASTStmt; ASTStmt;
@ -303,6 +324,8 @@ typedef union AST {
ASTExprCast exprCast; ASTExprCast exprCast;
ASTExprArray exprArray; ASTExprArray exprArray;
ASTExprFunc exprFunc; ASTExprFunc exprFunc;
ASTExprDot exprDot;
ASTExprExtSalloc exprExtSalloc;
ASTStmtExtOrg stmtExtOrg; ASTStmtExtOrg stmtExtOrg;
ASTStmtExtSection stmtExtSection; ASTStmtExtSection stmtExtSection;
} AST; } AST;
@ -322,6 +345,10 @@ char *ast_dump(AST *tlc);
AST *ast_deep_copy(AST*); 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, ...); __attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...);
#endif #endif

267
src/cg.c
View File

@ -101,10 +101,28 @@ static const char *xj(BinaryOp op) {
case BINOP_GREATER: return "a"; case BINOP_GREATER: return "a";
case BINOP_LEQUAL: return "be"; case BINOP_LEQUAL: return "be";
case BINOP_GEQUAL: return "ae"; 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) { static const char *xop_sz(AST *tlc, AST *e, int sz) {
#define XOPBUFS 16 #define XOPBUFS 16
#define XOPBUFSZ 24 #define XOPBUFSZ 24
@ -113,7 +131,48 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
char *ret = bufs[bufidx]; 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); snprintf(ret, XOPBUFSZ, "esp", tlc->chunk.stackReservation);
} else if(e->nodeKind == AST_EXPR_VAR) { } else if(e->nodeKind == AST_EXPR_VAR) {
VarTableEntry *v = e->exprVar.thing; VarTableEntry *v = e->exprVar.thing;
@ -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); snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), v->data.symbol.name);
} else abort(); } else abort();
} else if(e->nodeKind == AST_EXPR_PRIMITIVE) { } else if(e->nodeKind == AST_EXPR_PRIMITIVE) {
snprintf(ret, XOPBUFSZ, "%i", e->exprPrim.val); 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_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));
} 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) { } 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); 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 { } else {
return NULL; 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))) { if(s->stmtAssign.to && is_xop(s->stmtAssign.what) == XOP_NOT_MEM && is_xop(s->stmtAssign.to) == XOP_NOT_MEM && !strcmp(xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to))) {
// It's a noop // It's a noop
} else if(s->stmtAssign.to) { } else if(s->stmtAssign.to) {
if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && (s->stmtAssign.to->exprBinOp.operator == BINOP_ADD || s->stmtAssign.to->exprBinOp.operator == BINOP_SUB) && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val == 1) { if(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 // 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 { struct PrecolorState {
ASTExprVar *mustBeSpilled; VarTableEntry *mustBeSpilled;
}; };
static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
struct PrecolorState *this = 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->nodeKind == AST_STMT_RETURN && n->stmtReturn.val) {
if(n->stmtReturn.val) { assert(n->stmtReturn.val->nodeKind == AST_EXPR_VAR && n->stmtReturn.val->exprVar.thing->kind == VARTABLEENTRY_VAR);
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) {
if(vte->data.var.precolored && vte->data.var.color != requiredColor) { // Precoloring collision!
// Precoloring collision! this->mustBeSpilled = vte;
this->mustBeSpilled = vte; return;
return;
}
vte->data.var.color = requiredColor;
vte->data.var.precolored = true;
} }
vte->data.var.color = requiredColor;
vte->data.var.precolored = true;
} else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.to->nodeKind == AST_EXPR_CALL) { } 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); 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; 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.color = requiredColor;
vte->data.var.precolored = true; 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); return ((*a)->data.var.degree * (*a)->data.var.priority) - ((*b)->data.var.degree * (*b)->data.var.priority);
} }
int cg_go(AST *a) { int cg_go(AST *a) {
do { ast_usedef_reset(a);
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);
size_t adjCount = 0; size_t adjCount = 0;
Adjacency *adjs = calloc(adjCount, sizeof(*adjs)); Adjacency *adjs = calloc(adjCount, sizeof(*adjs));
@ -873,11 +894,17 @@ nextColor:;
if(lastColor >= 4) { if(lastColor >= 4) {
// Spill node with highest degree // Spill node with highest degree
struct Spill2StackState state; VarTableEntry *chosen = NULL;
memset(&state, 0, sizeof(state)); for(ssize_t i = a->chunk.varCount - 1; i >= 0; i--) {
state.target = vars[a->chunk.varCount - 1]; 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; return 0;
} }

View File

@ -9,18 +9,17 @@
// can be trivially translated to the target architecture. // can be trivially translated to the target architecture.
// //
// This file along with CG is strictly for IA-32 and will fail for other // This file along with CG is strictly for IA-32 and will fail for other
// architecture. // architectures.
#include"x86.h" #include"x86.h"
#include<string.h> #include<string.h>
/* Split away complex expression into a new local variable */ static VarTableEntry *create_dumbtemp(AST *tlc, Type *itstype) {
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
static size_t vidx = 0; static size_t vidx = 0;
VarTableEntry *vte = calloc(1, sizeof(*vte)); VarTableEntry *vte = calloc(1, sizeof(*vte));
vte->kind = VARTABLEENTRY_VAR; vte->kind = VARTABLEENTRY_VAR;
vte->type = e->expression.type; vte->type = itstype;
vte->data.var.color = -1; vte->data.var.color = -1;
vte->data.var.precolored = false; vte->data.var.precolored = false;
vte->data.var.degree = 0; 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 = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
tlc->chunk.vars[tlc->chunk.varCount - 1] = vte; 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 // Alter AST
ASTExprVar *ev[2]; 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); 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 { struct DumbenState {
int effective; 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) { } else if(s->nodeKind == AST_STMT_RETURN) {
// ret specifically returns in eax always, so it needs to be in a var // ret specifically returns in eax always, so it needs to be in a precolored var
if(s->stmtReturn.val && (!is_xop(s->stmtReturn.val) || s->stmtReturn.val->nodeKind == AST_EXPR_PRIMITIVE)) { 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; this->effective = 1;
vte_precolor(retval->exprVar.thing, COLOR_EAX);
} }
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) { } 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: // into:
// a = f(x); // a = f(x);
// So `a` would be colored as `eax`
s->stmtExpr.expr = varify(tlc, chu, stmtPrev, s, s->stmtExpr.expr); 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 = f(x);
// a; // a;
if(stmtPrev) { if(stmtPrev) {
assert(stmtPrev->statement.next->statement.next == s); assert(stmtPrev->statement.next->statement.next == s);
stmtPrev->statement.next->statement.next = s->statement.next; stmtPrev->statement.next->statement.next = s->statement.next;
} else { } else {
assert(chu->chunk.statementFirst->statement.next = s); assert(chu->chunk.statementFirst->statement.next == s);
chu->chunk.statementFirst->statement.next = s->statement.next; 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) { 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; stmtPrev->statement.next = s->statement.next;
this->effective = 1; this->effective = 1;
} else { } 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->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) {
s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to); 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; this->effective = 1;
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) { } 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) { WhysItBad_Huh because = x86_test_mul(stmtPrev, s);
s->stmtAssign.what = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what);
this->effective = 1;
}
/*if(!(s->statement.next && s->statement.next->nodeKind == AST_STMT_ASSIGN && s->statement.next->stmtAssign.)) { 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) {
// TODO: implement multiplication 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])) { } 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: // 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) { void dumben_pre(AST *tlc) {
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor); 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) { void dumben_go(AST* tlc) {
size_t i = 0; size_t i = 0;
while(1) { while(1) {
if(i == 20000) {
puts("TOO MANY DUMBS");
abort();
}
fprintf(stderr, "; Dumbing down %lu...\n", i++); fprintf(stderr, "; Dumbing down %lu...\n", i++);
struct DumbenState state; struct DumbenState state;
@ -329,5 +499,7 @@ void dumben_go(AST* tlc) {
if(!successful) { if(!successful) {
break; break;
} }
fputs(ast_dump(tlc), stderr);
} }
} }

View File

@ -34,7 +34,7 @@ char *TOKEN_NAMES[] = {
"'['", "'['",
"']'", "']'",
"'?'", "'?'",
"string" "string",
"'!='", "'!='",
"'!'", "'!'",
"'continue'", "'continue'",
@ -44,6 +44,10 @@ char *TOKEN_NAMES[] = {
"'>='", "'>='",
"'<'", "'<'",
"'>'", "'>'",
"'*^'",
"'record'",
"'.'",
"'as'",
}; };
static int isAlpha(int c) { static int isAlpha(int c) {
@ -62,7 +66,7 @@ static int isWS(int c) {
return c == ' ' || c == '\n' || c == '\r' || c == '\b' || c == '\t'; 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 size_t currentColumn = 0;
static int ungetted = EOF; static int ungetted = EOF;
@ -130,6 +134,10 @@ Token nct_tokenize(FILE *f) {
return tok; return tok;
} else if(c == '*') { } else if(c == '*') {
tok.type = TOKEN_STAR; tok.type = TOKEN_STAR;
int c = nextc(f);
if(c == '^') {
tok.type = TOKEN_STAR_CARET;
} else ungetc(c, f);
return tok; return tok;
} else if(c == '&') { } else if(c == '&') {
tok.type = TOKEN_AMPERSAND; tok.type = TOKEN_AMPERSAND;
@ -197,6 +205,9 @@ Token nct_tokenize(FILE *f) {
} else if(c == ',') { } else if(c == ',') {
tok.type = TOKEN_COMMA; tok.type = TOKEN_COMMA;
return tok; return tok;
} else if(c == '.') {
tok.type = TOKEN_DOT;
return tok;
} else if(c == '"') { } else if(c == '"') {
int capacity = 5; int capacity = 5;
char *content = malloc(capacity); char *content = malloc(capacity);
@ -225,14 +236,14 @@ Token nct_tokenize(FILE *f) {
tok.content = content; tok.content = content;
tok.length = i; tok.length = i;
return tok; return tok;
} else if(isAlpha(c) || c == '@') { } else if(isAlpha(c) || c == '@' || c == '_') {
int capacity = 5; int capacity = 5;
char *content = malloc(capacity); char *content = malloc(capacity);
size_t i = 0; size_t i = 0;
content[i++] = c; content[i++] = c;
while(c = nextc(f), (isAlphanum(c) || c == '@')) { while(c = nextc(f), (isAlphanum(c) || c == '@' || c == '_')) {
if(i == capacity - 1) { if(i == capacity - 1) {
content = realloc(content, capacity += 4); content = realloc(content, capacity += 4);
} }
@ -271,6 +282,14 @@ Token nct_tokenize(FILE *f) {
free(content); free(content);
tok.type = TOKEN_RETURN; tok.type = TOKEN_RETURN;
return tok; 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; tok.type = TOKEN_IDENTIFIER;

View File

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

View File

@ -8,6 +8,7 @@
#include"reporting.h" #include"reporting.h"
#include"cg.h" #include"cg.h"
#include"dumberdowner.h" #include"dumberdowner.h"
#include"x86.h"
static int argc; static int argc;
static char **argv; static char **argv;
@ -25,6 +26,10 @@ int main(int argc_, char **argv_) {
argc = argc_; argc = argc_;
argv = argv_; argv = argv_;
if(x86_target() == IUNKNOWN86) {
stahp(0, 0, "Unknown architecture %s", ntc_get_arg("target"));
}
const char *in = ntc_get_arg("in"); const char *in = ntc_get_arg("in");
FILE *f = in ? fopen(in, "rb") : stdin; FILE *f = in ? fopen(in, "rb") : stdin;
@ -50,6 +55,10 @@ int main(int argc_, char **argv_) {
while(!cg_go(chunk)) { while(!cg_go(chunk)) {
dumben_go(chunk); dumben_go(chunk);
fputs("\n; === Spill ===\n", stderr);
fputs(ast_dump(chunk), stderr);
fputc('\n', stderr);
} }
return 0; return 0;

View File

@ -157,75 +157,23 @@ static AST *exprvar(Parser *P, VarTableEntry *v) {
return a; 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); ASTChunk *nct_parse_chunk(Parser*, int, int, VarTable*, Type *ft);
Type *nct_parse_typename(Parser *P); 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) { AST *nct_parse_expression(Parser *P, int lOP) {
if(lOP == 0) { if(lOP == 0) {
// Test if this is an anonymous function // Test if this is an anonymous function
@ -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) { 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) { } else if(peek(P, 0).type == TOKEN_IDENTIFIER) {
if(!strcmp(peek(P, 0).content, "@stack")) { if(!strcmp(peek(P, 0).content, "@stack")) {
get(P); get(P);
ASTExprStackPointer *ret = malloc(sizeof(*ret)); ASTExprStackPointer *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_STACK_POINTER; ret->nodeKind = AST_EXPR_STACK_POINTER;
ret->type = primitive_parse("u32"); 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) { } else if(peek(P, 0).type == TOKEN_STRING) {
ASTExprStringLiteral *ret = malloc(sizeof(*ret)); ASTExprStringLiteral *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_STRING_LITERAL; ret->nodeKind = AST_EXPR_STRING_LITERAL;
@ -291,13 +255,42 @@ AST *nct_parse_expression(Parser *P, int lOP) {
ret->data = tok.content; ret->data = tok.content;
ret->length = tok.length; ret->length = tok.length;
return (AST*) ret; e = (AST*) ret;
} else if(maybe(P, TOKEN_PAREN_L)) { } 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); 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)) { if(maybe(P, TOKEN_STAR)) {
ASTExprUnaryOp *astop = malloc(sizeof(*astop)); ASTExprUnaryOp *astop = malloc(sizeof(*astop));
astop->nodeKind = AST_EXPR_UNARY_OP; astop->nodeKind = AST_EXPR_UNARY_OP;
@ -345,7 +338,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
return (AST *) astop; return (AST *) astop;
} }
} else return nct_parse_expression(P, lOP + 1); } else return nct_parse_expression(P, lOP + 1);
} else if(lOP == 3) { } else if(lOP == 4) {
AST *ret = nct_parse_expression(P, lOP + 1); AST *ret = nct_parse_expression(P, lOP + 1);
while(peek(P, 0).type == TOKEN_PAREN_L || peek(P, 0).type == TOKEN_SQUAREN_L) { 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)) { if(!maybe(P, TOKEN_PAREN_R)) {
while(peek(P, 0).type != TOKEN_PAREN_R && peek(P, 0).type != TOKEN_COMMA) { 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 = 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++; argCount++;
@ -423,13 +416,14 @@ AST *nct_parse_expression(Parser *P, int lOP) {
} }
return ret; return ret;
} else if(lOP == 2) { } else if(lOP == 3) {
AST *ret = nct_parse_expression(P, lOP + 1); 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) { while(1) {
BinaryOp op; BinaryOp op;
if(maybe(P, TOKEN_STAR)) op = BINOP_MUL; 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 if(maybe(P, TOKEN_SLASH)) op = BINOP_DIV;
else break; else break;
@ -455,12 +449,14 @@ AST *nct_parse_expression(Parser *P, int lOP) {
} }
} }
binop_implicit_cast(astop);
ret = (AST*) astop; ret = (AST*) astop;
} }
} }
return ret; return ret;
} else if(lOP == 1) { } else if(lOP == 2) {
AST *ret = nct_parse_expression(P, lOP + 1); AST *ret = nct_parse_expression(P, lOP + 1);
if( if(
@ -481,7 +477,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
ASTExprBinaryOp *astop = malloc(sizeof(*astop)); ASTExprBinaryOp *astop = malloc(sizeof(*astop));
astop->nodeKind = AST_EXPR_BINARY_OP; astop->nodeKind = AST_EXPR_BINARY_OP;
astop->type = ret->expression.type; astop->type = NULL;
astop->operator = op; astop->operator = op;
astop->operands[0] = ret; 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."); 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)) { binop_implicit_cast(astop);
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;
}
}
ret = (AST*) 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; return ret;
} else if(lOP == 0) { } else if(lOP == 0) {
AST *ret = nct_parse_expression(P, lOP + 1); 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."); stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types.");
} }
if(!astop->type) { binop_implicit_cast(astop);
astop->type = operand->type;
} else {
if(type_size(operand->type) > type_size(astop->type)) {
astop->type = operand->type;
}
}
ret = (AST*) astop; ret = (AST*) astop;
} }
@ -571,7 +556,16 @@ Type *nct_parse_typename(Parser *P) {
goto backtrack; 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) { if(!ret) {
goto backtrack; goto backtrack;
@ -689,12 +683,12 @@ static AST *parse_declaration(Parser *P) {
//reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign); //reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign);
assign->what = exprvar(P, entry); 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; ret = (AST*) assign;
} else { } else {
ASTStmtDecl *decl = malloc(sizeof(*ret)); ASTStmtDecl *decl = calloc(1, sizeof(*ret));
decl->nodeKind = AST_STMT_DECL; decl->nodeKind = AST_STMT_DECL;
decl->thing = entry; decl->thing = entry;
decl->next = NULL; decl->next = NULL;
@ -714,16 +708,12 @@ static AST *parse_declaration(Parser *P) {
decl->expression = nct_parse_expression(P, 0); decl->expression = nct_parse_expression(P, 0);
if(type) { if(type) {
decl->expression = nct_cast_expr(decl->expression, type); if(decl->expression) {
decl->expression = ast_cast_expr(decl->expression, type);
}
} else { } else {
entry->type = decl->expression->expression.type; 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) { } else if(isExternal) {
entry->kind = VARTABLEENTRY_SYMBOL; entry->kind = VARTABLEENTRY_SYMBOL;
entry->data.symbol.isLocal = isLocal; entry->data.symbol.isLocal = isLocal;
@ -837,6 +827,24 @@ void nct_parse_statement(Parser *P) {
pushstat(P, ret); 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; return;
} else if(peek(P, 0).type == TOKEN_IDENTIFIER) { } else if(peek(P, 0).type == TOKEN_IDENTIFIER) {
if(!strcmp(peek(P, 0).content, "@align")) { if(!strcmp(peek(P, 0).content, "@align")) {
@ -906,7 +914,7 @@ void nct_parse_statement(Parser *P) {
ret->nodeKind = AST_STMT_ASSIGN; ret->nodeKind = AST_STMT_ASSIGN;
ret->next = NULL; ret->next = NULL;
ret->what = e; 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) { //if(ret->what->nodeKind == AST_EXPR_VAR) {
// reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret); // 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) { ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable *toplevelParent, Type *ft) {
AST *ret = calloc(1, sizeof(ASTChunk)); AST *ret = calloc(1, sizeof(ASTChunk));
ret->nodeKind = AST_CHUNK; ret->nodeKind = AST_CHUNK;
@ -949,8 +1005,6 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable
P->topLevel = &ret->chunk; 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 */ /* Find all symbol names and struct types ahead of time. Searches for colons as those can only mean symbol declarations */
P->skimMode++; P->skimMode++;
@ -983,6 +1037,16 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable
if(!d) abort(); if(!d) abort();
free(d); /* We don't need it. */ 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; P->i = oldIdx;
@ -1012,8 +1076,6 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable
nct_parse_statement(P); nct_parse_statement(P);
} }
//vartable_coalesce_reachingdefs_for_all_vars(P->scope);
size_t nonSymbols = 0; size_t nonSymbols = 0;
for(size_t i = 0; i < P->scope->count; i++) { for(size_t i = 0; i < P->scope->count; i++) {
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) { if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {

View File

@ -72,6 +72,11 @@ Type *primitive_parse(const char *src) {
ret->vector = 1; ret->vector = 1;
} }
if(*src) {
free(ret);
return NULL;
}
ret->next = primitiveDatabase[hash]; ret->next = primitiveDatabase[hash];
primitiveDatabase[hash] = ret; primitiveDatabase[hash] = ret;
@ -94,6 +99,8 @@ size_t type_size(Type *t) {
return 4; return 4;
} else if(t->type == TYPE_TYPE_ARRAY) { } else if(t->type == TYPE_TYPE_ARRAY) {
return type_size(t->array.of) * t->array.length; return type_size(t->array.of) * t->array.length;
} else if(t->type == TYPE_TYPE_RECORD) {
return t->record.size;
} }
abort(); abort();

View File

@ -5,7 +5,7 @@
#include<stdint.h> #include<stdint.h>
typedef enum { 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; } TypeType;
union Type; union Type;
@ -51,6 +51,19 @@ typedef struct TypeArray {
size_t length; /* 0 means unknown */ size_t length; /* 0 means unknown */
} TypeArray; } 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 { typedef union Type {
TypeType type; TypeType type;
@ -58,6 +71,7 @@ typedef union Type {
TypePointer pointer; TypePointer pointer;
TypeFunction function; TypeFunction function;
TypeArray array; TypeArray array;
TypeRecord record;
} Type; } Type;
extern Type TYPE_ERROR; extern Type TYPE_ERROR;

View File

@ -3,6 +3,7 @@
#include"utils.h" #include"utils.h"
#include<stdlib.h> #include<stdlib.h>
#include<string.h> #include<string.h>
#include<assert.h>
struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) { struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) {
struct ReachingDefs *ret = calloc(1, sizeof(*ret)); 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); 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> #include<stdbool.h>
typedef enum { typedef enum {
VARTABLEENTRY_SYMBOL, VARTABLEENTRY_STACK, VARTABLEENTRY_VAR VARTABLEENTRY_SYMBOL, VARTABLEENTRY_VAR, VARTABLEENTRY_TYPE
} VarTableEntryKind; } VarTableEntryKind;
union AST; union AST;
@ -64,6 +64,9 @@ typedef struct VarTableEntry {
UseDef *usedefFirst; UseDef *usedefFirst;
UseDef *usedefLast; UseDef *usedefLast;
} var; } var;
struct {
Type *ptr;
} type;
}; };
} data; } data;
} VarTableEntry; } VarTableEntry;
@ -84,4 +87,6 @@ VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*);
void vartable_new_reachingdefs_for_all_vars(VarTable*); void vartable_new_reachingdefs_for_all_vars(VarTable*);
void vartable_coalesce_reachingdefs_for_all_vars(VarTable*); void vartable_coalesce_reachingdefs_for_all_vars(VarTable*);
void vte_precolor(VarTableEntry *vte, int color);
#endif #endif

145
src/x86.h
View File

@ -1,5 +1,9 @@
#pragma once #pragma once
#include<string.h>
#include"ntc.h"
#include<assert.h>
#define COLOR_EAX 0 #define COLOR_EAX 0
#define COLOR_ECX 1 #define COLOR_ECX 1
#define COLOR_EDX 2 #define COLOR_EDX 2
@ -10,6 +14,10 @@
#define XOP_NOT_MEM 1 #define XOP_NOT_MEM 1
#define XOP_MEM 2 #define XOP_MEM 2
static inline int is_xop(AST *e) { 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) { if(e->nodeKind == AST_EXPR_PRIMITIVE) {
return XOP_NOT_MEM; return XOP_NOT_MEM;
} else if(e->nodeKind == AST_EXPR_VAR) { } 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) { } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
AST *c = e->exprUnOp.operand; 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) { if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_VAR) {
return XOP_MEM; 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) { } 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; 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;
}