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