i->Xin.Unary32.dst = dst;
return i;
}
+X86Instr* X86Instr_Lea32 ( X86AMode* am, HReg dst ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_Lea32;
+ i->Xin.Lea32.am = am;
+ i->Xin.Lea32.dst = dst;
+ return i;
+}
X86Instr* X86Instr_MulL ( Bool syned, X86RM* src ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
i->tag = Xin_MulL;
vex_printf("%sl ", showX86UnaryOp(i->Xin.Unary32.op));
ppHRegX86(i->Xin.Unary32.dst);
return;
+ case Xin_Lea32:
+ vex_printf("leal ");
+ ppX86AMode(i->Xin.Lea32.am);
+ vex_printf(",");
+ ppHRegX86(i->Xin.Lea32.dst);
+ return;
case Xin_MulL:
vex_printf("%cmull ", i->Xin.MulL.syned ? 's' : 'u');
ppX86RM(i->Xin.MulL.src);
case Xin_Unary32:
addHRegUse(u, HRmModify, i->Xin.Unary32.dst);
return;
+ case Xin_Lea32:
+ addRegUsage_X86AMode(u, i->Xin.Lea32.am);
+ addHRegUse(u, HRmWrite, i->Xin.Lea32.dst);
+ return;
case Xin_MulL:
addRegUsage_X86RM(u, i->Xin.MulL.src, HRmRead);
addHRegUse(u, HRmModify, hregX86_EAX());
case Xin_Unary32:
mapReg(m, &i->Xin.Unary32.dst);
return;
+ case Xin_Lea32:
+ mapRegs_X86AMode(m, i->Xin.Lea32.am);
+ mapReg(m, &i->Xin.Lea32.dst);
+ return;
case Xin_MulL:
mapRegs_X86RM(m, i->Xin.MulL.src);
return;
}
break;
+ case Xin_Lea32:
+ *p++ = 0x8D;
+ p = doAMode_M(p, i->Xin.Lea32.dst, i->Xin.Lea32.am);
+ goto done;
+
case Xin_MulL:
subopc = i->Xin.MulL.syned ? 5 : 4;
*p++ = 0xF7;
Xin_Test32, /* 32-bit test of REG against imm32 (AND, set
flags, discard result) */
Xin_Unary32, /* 32-bit not and neg */
+ Xin_Lea32, /* 32-bit compute EA into a reg */
Xin_MulL, /* 32 x 32 -> 64 multiply */
Xin_Div, /* 64/32 -> (32,32) div and mod */
Xin_Sh3232, /* shldl or shrdl */
X86UnaryOp op;
HReg dst;
} Unary32;
+ /* 32-bit compute EA into a reg */
+ struct {
+ X86AMode* am;
+ HReg dst;
+ } Lea32;
/* EDX:EAX = EAX *s/u r/m32 */
struct {
Bool syned;
extern X86Instr* X86Instr_Alu32R ( X86AluOp, X86RMI*, HReg );
extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*, X86AMode* );
extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, HReg dst );
+extern X86Instr* X86Instr_Lea32 ( X86AMode* am, HReg dst );
+
extern X86Instr* X86Instr_Sh32 ( X86ShiftOp, UInt, HReg );
extern X86Instr* X86Instr_Test32 ( UInt imm32, HReg dst );
extern X86Instr* X86Instr_MulL ( Bool syned, X86RM* );
IRType ty = typeOfIRExpr(env->type_env,e);
vassert(ty == Ity_I32);
+ /* Add32( Add32(expr1, Shl32(expr2, simm)), imm32 ) */
+ if (e->tag == Iex_Binop
+ && e->Iex.Binop.op == Iop_Add32
+ && e->Iex.Binop.arg2->tag == Iex_Const
+ && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
+ && e->Iex.Binop.arg1->tag == Iex_Binop
+ && e->Iex.Binop.arg1->Iex.Binop.op == Iop_Add32
+ && e->Iex.Binop.arg1->Iex.Binop.arg2->tag == Iex_Binop
+ && e->Iex.Binop.arg1->Iex.Binop.arg2->Iex.Binop.op == Iop_Shl32
+ && e->Iex.Binop.arg1
+ ->Iex.Binop.arg2->Iex.Binop.arg2->tag == Iex_Const
+ && e->Iex.Binop.arg1
+ ->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8) {
+ UInt shift = e->Iex.Binop.arg1
+ ->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
+ UInt imm32 = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
+ if (shift == 1 || shift == 2 || shift == 3) {
+ HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1->Iex.Binop.arg1);
+ HReg r2 = iselIntExpr_R(env, e->Iex.Binop.arg1
+ ->Iex.Binop.arg2->Iex.Binop.arg1 );
+ return X86AMode_IRRS(imm32, r1, r2, shift);
+ }
+ }
+
/* Add32(expr1, Shl32(expr2, imm)) */
if (e->tag == Iex_Binop
&& e->Iex.Binop.op == Iop_Add32
case Ist_WrTmp: {
IRTemp tmp = stmt->Ist.WrTmp.tmp;
IRType ty = typeOfIRTemp(env->type_env, tmp);
+
+ /* optimisation: if stmt->Ist.WrTmp.data is Add32(..,..),
+ compute it into an AMode and then use LEA. This usually
+ produces fewer instructions, often because (for memcheck
+ created IR) we get t = address-expression, (t is later used
+ twice) and so doing this naturally turns address-expression
+ back into an X86 amode. */
+ if (ty == Ity_I32
+ && stmt->Ist.WrTmp.data->tag == Iex_Binop
+ && stmt->Ist.WrTmp.data->Iex.Binop.op == Iop_Add32) {
+ X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.WrTmp.data);
+ HReg dst = lookupIRTemp(env, tmp);
+ if (am->tag == Xam_IR && am->Xam.IR.imm == 0) {
+ /* Hmm, iselIntExpr_AMode wimped out and just computed the
+ value into a register. Just emit a normal reg-reg move
+ so reg-alloc can coalesce it away in the usual way. */
+ HReg src = am->Xam.IR.reg;
+ addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst));
+ } else {
+ addInstr(env, X86Instr_Lea32(am,dst));
+ }
+ return;
+ }
+
if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
X86RMI* rmi = iselIntExpr_RMI(env, stmt->Ist.WrTmp.data);
HReg dst = lookupIRTemp(env, tmp);