From: Julian Seward Date: Sat, 31 Mar 2007 19:12:38 +0000 (+0000) Subject: Counterpart to r1745: teach the amd64 back end how to generate 'lea' X-Git-Tag: svn/VALGRIND_3_3_1^2~44 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=67d54e8e36686a3eaeb3b7785d843ca8c8fa95ee;p=thirdparty%2Fvalgrind.git Counterpart to r1745: teach the amd64 back end how to generate 'lea' instructions, and generate them in an important place. git-svn-id: svn://svn.valgrind.org/vex/trunk@1746 --- diff --git a/VEX/priv/host-amd64/hdefs.c b/VEX/priv/host-amd64/hdefs.c index 080eafe4f0..a45550debe 100644 --- a/VEX/priv/host-amd64/hdefs.c +++ b/VEX/priv/host-amd64/hdefs.c @@ -683,6 +683,13 @@ AMD64Instr* AMD64Instr_Unary64 ( AMD64UnaryOp op, HReg dst ) { 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; @@ -1062,6 +1069,12 @@ void ppAMD64Instr ( AMD64Instr* i, Bool mode64 ) 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); @@ -1385,6 +1398,10 @@ void getRegUsage_AMD64Instr ( HRegUsage* u, AMD64Instr* i, Bool mode64 ) 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()); @@ -1665,6 +1682,10 @@ void mapRegs_AMD64Instr ( HRegRemap* m, AMD64Instr* i, Bool mode64 ) 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; @@ -2473,6 +2494,12 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i, } 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) { diff --git a/VEX/priv/host-amd64/hdefs.h b/VEX/priv/host-amd64/hdefs.h index 874981ad0d..d146ac246a 100644 --- a/VEX/priv/host-amd64/hdefs.h +++ b/VEX/priv/host-amd64/hdefs.h @@ -369,6 +369,7 @@ typedef 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 */ @@ -450,6 +451,11 @@ typedef 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 { @@ -666,6 +672,7 @@ extern AMD64Instr* AMD64Instr_Imm64 ( ULong imm64, HReg dst ); 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* ); diff --git a/VEX/priv/host-amd64/isel.c b/VEX/priv/host-amd64/isel.c index d94eb1cc29..377c74903b 100644 --- a/VEX/priv/host-amd64/isel.c +++ b/VEX/priv/host-amd64/isel.c @@ -3663,6 +3663,30 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) 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);