193 lines
5.5 KiB
C
193 lines
5.5 KiB
C
#pragma once
|
|
|
|
#include<string.h>
|
|
#include"ntc.h"
|
|
#include<assert.h>
|
|
|
|
#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;
|
|
}
|