instructions, and generate them in an important place.
git-svn-id: svn://svn.valgrind.org/vex/trunk@1746
i->Ain.Unary64.dst = dst;
return i;
}
+AMD64Instr* AMD64Instr_Lea64 ( AMD64AMode* am, HReg dst ) {
+ AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr));
+ i->tag = Ain_Lea64;
+ i->Ain.Lea64.am = am;
+ i->Ain.Lea64.dst = dst;
+ return i;
+}
AMD64Instr* AMD64Instr_MulL ( Bool syned, AMD64RM* src ) {
AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr));
i->tag = Ain_MulL;
vex_printf("%sq ", showAMD64UnaryOp(i->Ain.Unary64.op));
ppHRegAMD64(i->Ain.Unary64.dst);
return;
+ case Ain_Lea64:
+ vex_printf("leaq ");
+ ppAMD64AMode(i->Ain.Lea64.am);
+ vex_printf(",");
+ ppHRegAMD64(i->Ain.Lea64.dst);
+ return;
case Ain_MulL:
vex_printf("%cmulq ", i->Ain.MulL.syned ? 's' : 'u');
ppAMD64RM(i->Ain.MulL.src);
case Ain_Unary64:
addHRegUse(u, HRmModify, i->Ain.Unary64.dst);
return;
+ case Ain_Lea64:
+ addRegUsage_AMD64AMode(u, i->Ain.Lea64.am);
+ addHRegUse(u, HRmWrite, i->Ain.Lea64.dst);
+ return;
case Ain_MulL:
addRegUsage_AMD64RM(u, i->Ain.MulL.src, HRmRead);
addHRegUse(u, HRmModify, hregAMD64_RAX());
case Ain_Unary64:
mapReg(m, &i->Ain.Unary64.dst);
return;
+ case Ain_Lea64:
+ mapRegs_AMD64AMode(m, i->Ain.Lea64.am);
+ mapReg(m, &i->Ain.Lea64.dst);
+ return;
case Ain_MulL:
mapRegs_AMD64RM(m, i->Ain.MulL.src);
return;
}
break;
+ case Ain_Lea64:
+ *p++ = rexAMode_M(i->Ain.Lea64.dst, i->Ain.Lea64.am);
+ *p++ = 0x8D;
+ p = doAMode_M(p, i->Ain.Lea64.dst, i->Ain.Lea64.am);
+ goto done;
+
case Ain_MulL:
subopc = i->Ain.MulL.syned ? 5 : 4;
switch (i->Ain.MulL.src->tag) {
Ain_Sh64, /* 64-bit shift/rotate, dst=REG or MEM */
Ain_Test64, /* 64-bit test (AND, set flags, discard result) */
Ain_Unary64, /* 64-bit not and neg */
+ Ain_Lea64, /* 64-bit compute EA into a reg */
Ain_MulL, /* widening multiply */
Ain_Div, /* div and mod */
//.. Xin_Sh3232, /* shldl or shrdl */
AMD64UnaryOp op;
HReg dst;
} Unary64;
+ /* 64-bit compute EA into a reg */
+ struct {
+ AMD64AMode* am;
+ HReg dst;
+ } Lea64;
/* 64 x 64 -> 128 bit widening multiply: RDX:RAX = RAX *s/u
r/m64 */
struct {
extern AMD64Instr* AMD64Instr_Alu64R ( AMD64AluOp, AMD64RMI*, HReg );
extern AMD64Instr* AMD64Instr_Alu64M ( AMD64AluOp, AMD64RI*, AMD64AMode* );
extern AMD64Instr* AMD64Instr_Unary64 ( AMD64UnaryOp op, HReg dst );
+extern AMD64Instr* AMD64Instr_Lea64 ( AMD64AMode* am, HReg dst );
extern AMD64Instr* AMD64Instr_Sh64 ( AMD64ShiftOp, UInt, HReg );
extern AMD64Instr* AMD64Instr_Test64 ( UInt imm32, HReg dst );
extern AMD64Instr* AMD64Instr_MulL ( Bool syned, AMD64RM* );
case Ist_WrTmp: {
IRTemp tmp = stmt->Ist.WrTmp.tmp;
IRType ty = typeOfIRTemp(env->type_env, tmp);
+
+ /* optimisation: if stmt->Ist.WrTmp.data is Add64(..,..),
+ 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 AMD64 amode. */
+ if (ty == Ity_I64
+ && stmt->Ist.WrTmp.data->tag == Iex_Binop
+ && stmt->Ist.WrTmp.data->Iex.Binop.op == Iop_Add64) {
+ AMD64AMode* am = iselIntExpr_AMode(env, stmt->Ist.WrTmp.data);
+ HReg dst = lookupIRTemp(env, tmp);
+ if (am->tag == Aam_IR && am->Aam.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->Aam.IR.reg;
+ addInstr(env, AMD64Instr_Alu64R(Aalu_MOV, AMD64RMI_Reg(src), dst));
+ } else {
+ addInstr(env, AMD64Instr_Lea64(am,dst));
+ }
+ return;
+ }
+
if (ty == Ity_I64 || ty == Ity_I32
|| ty == Ity_I16 || ty == Ity_I8) {
AMD64RMI* rmi = iselIntExpr_RMI(env, stmt->Ist.WrTmp.data);