diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h index 0b726521a6..a2b261d7b3 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit.h @@ -153,8 +153,7 @@ public: void addmex(UGeckoInstruction inst); void addzex(UGeckoInstruction inst); - void extsbx(UGeckoInstruction inst); - void extshx(UGeckoInstruction inst); + void extsXx(UGeckoInstruction inst); void sc(UGeckoInstruction _inst); void rfi(UGeckoInstruction _inst); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp index fa7c19aec8..927e83353f 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp @@ -190,8 +190,8 @@ static GekkoOPTemplate table31[] = {0, &Jit64::cmpXX}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, {32, &Jit64::cmpXX}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, {26, &Jit64::cntlzwx}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, - {922, &Jit64::extshx}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, - {954, &Jit64::extsbx}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {922, &Jit64::extsXx}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {954, &Jit64::extsXx}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {536, &Jit64::srwx}, //"srwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {792, &Jit64::srawx}, //"srawx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {824, &Jit64::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index ec5f68cd18..01212e3065 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -796,56 +796,37 @@ void Jit64::boolX(UGeckoInstruction inst) } } -void Jit64::extsbx(UGeckoInstruction inst) +void Jit64::extsXx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); int a = inst.RA, s = inst.RS; + int size = inst.SUBOP10 == 922 ? 16 : 8; if (gpr.R(s).IsImm()) { - gpr.SetImmediate32(a, (u32)(s32)(s8)gpr.R(s).offset); + gpr.SetImmediate32(a, (u32)(s32)(size == 16 ? (s16)gpr.R(s).offset : (s8)gpr.R(s).offset)); + if (inst.Rc) + ComputeRC(gpr.R(a)); } else { gpr.Lock(a, s); gpr.BindToRegister(a, a == s, true); - MOVSX(32, 8, gpr.RX(a), gpr.R(s)); + // exts is moderately commonly used with inst.Rc, so try to optimize it. + if (inst.Rc) + { + // Only do one movsx; the movzx is free on most modern CPUs. + MOVSX(64, size, gpr.RX(a), gpr.R(s)); + MOV(64, PPCSTATE(cr_val[0]), gpr.R(a)); + MOVZX(64, 32, gpr.RX(a), gpr.R(a)); + } + else + { + MOVSX(32, size, gpr.RX(a), gpr.R(s)); + } gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } -} - -void Jit64::extshx(UGeckoInstruction inst) -{ - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, s = inst.RS; - - if (gpr.R(s).IsImm()) - { - gpr.SetImmediate32(a, (u32)(s32)(s16)gpr.R(s).offset); - } - else - { - gpr.Lock(a, s); - gpr.KillImmediate(s, true, false); - gpr.BindToRegister(a, a == s, true); - // This looks a little dangerous, but it's safe because - // every 32-bit register has a 16-bit half at the same index - // as the 32-bit register. - MOVSX(32, 16, gpr.RX(a), gpr.R(s)); - gpr.UnlockAll(); - } - - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } } void Jit64::subfic(UGeckoInstruction inst)