#pragma once #include #include"ntc.h" #include #define COLOR_EAX 0 #define COLOR_ECX 1 #define COLOR_EDX 2 #define COLOR_EBX 3 // Can expression be expressed as a single x86 operand? #define XOP_NOT_XOP 0 #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) { return e->exprVar.thing->kind == VARTABLEENTRY_VAR ? XOP_NOT_MEM : XOP_MEM; } 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 && is_xop(e->exprUnOp.operand->exprBinOp.operands[0]) == XOP_NOT_MEM && is_xop(e->exprUnOp.operand->exprBinOp.operands[1]) == XOP_NOT_MEM) { return XOP_MEM; } 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) { return XOP_NOT_MEM; } 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) || (c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR)) { if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) { return XOP_MEM; } else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { return XOP_MEM; } else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && c->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && c->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { int scale = c->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val; if(scale == 1 || scale == 2 || scale == 4 || scale == 8) { return XOP_MEM; } } } } else if(e->nodeKind == AST_EXPR_STACK_POINTER) { return XOP_NOT_MEM; } 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; }