diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h index a41ce65375..c1237463d8 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit.h @@ -103,6 +103,8 @@ public: void ComputeRC(preg_t preg, bool needs_test = true, bool needs_sext = true); void AndWithMask(Gen::X64Reg reg, u32 mask); + void RotateLeft(int bits, Gen::X64Reg regOp, const Gen::OpArg& arg, u8 rotate); + bool CheckMergedBranch(u32 crf) const; void DoMergedBranch(); void DoMergedBranchCondition(); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 74362c12c1..5a8d25bbac 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -202,6 +202,27 @@ void Jit64::AndWithMask(X64Reg reg, u32 mask) AND(32, R(reg), Imm32(mask)); } +void Jit64::RotateLeft(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) +{ + const bool is_same_reg = arg.IsSimpleReg(regOp); + + if (cpu_info.bBMI2 && !is_same_reg && rotate != 0) + { + RORX(bits, regOp, arg, bits - rotate); + return; + } + + if (!is_same_reg) + { + MOV(bits, R(regOp), arg); + } + + if (rotate != 0) + { + ROL(bits, R(regOp), Imm8(rotate)); + } +} + // Following static functions are used in conjunction with regimmop static u32 Add(u32 a, u32 b) { @@ -1560,34 +1581,34 @@ void Jit64::rlwinmx(UGeckoInstruction inst) SHL(32, Ra, Imm8(inst.SH)); needs_sext = inst.SH + mask_size >= 32; } - else + else if (left_shift) { if (a != s) MOV(32, Ra, Rs); - if (left_shift) + SHL(32, Ra, Imm8(inst.SH)); + } + else if (right_shift) + { + if (a != s) + MOV(32, Ra, Rs); + + SHR(32, Ra, Imm8(inst.MB)); + needs_sext = false; + } + else + { + RotateLeft(32, Ra, Rs, inst.SH); + + if (!(inst.MB == 0 && inst.ME == 31)) { - SHL(32, Ra, Imm8(inst.SH)); - } - else if (right_shift) - { - SHR(32, Ra, Imm8(inst.MB)); - needs_sext = false; - } - else - { - if (inst.SH != 0) - ROL(32, Ra, Imm8(inst.SH)); - if (!(inst.MB == 0 && inst.ME == 31)) - { - // we need flags if we're merging the branch - if (inst.Rc && CheckMergedBranch(0)) - AND(32, Ra, Imm32(mask)); - else - AndWithMask(Ra, mask); - needs_sext = inst.MB == 0; - needs_test = false; - } + // we need flags if we're merging the branch + if (inst.Rc && CheckMergedBranch(0)) + AND(32, Ra, Imm32(mask)); + else + AndWithMask(Ra, mask); + needs_sext = inst.MB == 0; + needs_test = false; } } @@ -1627,10 +1648,7 @@ void Jit64::rlwimix(UGeckoInstruction inst) RCOpArg Rs = gpr.Use(s, RCMode::Read); RCX64Reg Ra = gpr.Bind(a, RCMode::Read); RegCache::Realize(Rs, Ra); - if (a != s) - MOV(32, Ra, Rs); - if (inst.SH) - ROL(32, Ra, Imm8(inst.SH)); + RotateLeft(32, Ra, Rs, inst.SH); needs_test = true; } else if (gpr.IsImm(s)) @@ -1652,18 +1670,19 @@ void Jit64::rlwimix(UGeckoInstruction inst) RCX64Reg Ra = gpr.Bind(a, RCMode::Write); RegCache::Realize(Rs, Ra); - MOV(32, Ra, Rs); if (isLeftShift) { + MOV(32, Ra, Rs); SHL(32, Ra, Imm8(inst.SH)); } else if (isRightShift) { + MOV(32, Ra, Rs); SHR(32, Ra, Imm8(32 - inst.SH)); } else { - ROL(32, Ra, Imm8(inst.SH)); + RotateLeft(32, Ra, Rs, inst.SH); AND(32, Ra, Imm32(mask)); } OR(32, Ra, Imm32(maskA)); @@ -1675,22 +1694,23 @@ void Jit64::rlwimix(UGeckoInstruction inst) RCX64Reg Ra = gpr.Bind(a, RCMode::ReadWrite); RegCache::Realize(Rs, Ra); - MOV(32, R(RSCRATCH), Rs); if (isLeftShift) { + MOV(32, R(RSCRATCH), Rs); SHL(32, R(RSCRATCH), Imm8(inst.SH)); AndWithMask(Ra, ~mask); OR(32, Ra, R(RSCRATCH)); } else if (isRightShift) { + MOV(32, R(RSCRATCH), Rs); SHR(32, R(RSCRATCH), Imm8(32 - inst.SH)); AndWithMask(Ra, ~mask); OR(32, Ra, R(RSCRATCH)); } else { - ROL(32, R(RSCRATCH), Imm8(inst.SH)); + RotateLeft(32, RSCRATCH, Rs, inst.SH); XOR(32, R(RSCRATCH), Ra); AndWithMask(RSCRATCH, mask); XOR(32, Ra, R(RSCRATCH));