diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index df2b48631d..86027d425a 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -6,18 +6,14 @@ #include #include "Common/Arm64Emitter.h" -#include "Common/Assert.h" -#include "Common/BitUtils.h" +#include "Common/ArmCommon.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Core/Core.h" -#include "Core/CoreTiming.h" #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" #include "Core/PowerPC/JitCommon/DivUtils.h" #include "Core/PowerPC/PPCTables.h" -#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; using namespace JitCommon; @@ -1306,13 +1302,10 @@ void JitArm64::subfex(UGeckoInstruction inst) JITDISABLE(bJITIntegerOff); FALLBACK_IF(inst.OE); - bool mex = inst.SUBOP10 & 32; - int a = inst.RA, b = inst.RB, d = inst.RD; + const bool mex = inst.SUBOP10 & 32; + const int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && (mex || gpr.IsImm(b))) - { - const u32 i = gpr.GetImm(a); - const u32 j = mex ? -1 : gpr.GetImm(b); + const auto handle_imm = [&](const u32 i, const u32 j) { const u32 imm = ~i + j; const bool is_zero = imm == 0; const bool is_all_ones = imm == 0xFFFFFFFF; @@ -1339,7 +1332,12 @@ void JitArm64::subfex(UGeckoInstruction inst) { gpr.BindToRegister(d, false); ARM64Reg RD = gpr.R(d); - if (is_all_ones) + if (is_zero) + { + // RD = 0 + carry + CSET(RD, CC_CS); + } + else if (is_all_ones) { // RD = -1 + carry = carry ? 0 : -1 // CSETM sets the destination to -1 if the condition is true, 0 @@ -1380,6 +1378,21 @@ void JitArm64::subfex(UGeckoInstruction inst) { ComputeCarry(false); } + }; + + if (!mex && a == b) + { + // Special case: subfe A, B, B is a common compiler idiom to copy the carry + // flag to a register. + // We handle this as-if we're dealing with two identical immediate values. + // The exact values used here don't matter. We use zeroes. + handle_imm(0, 0); + } + else if (gpr.IsImm(a) && (mex || gpr.IsImm(b))) + { + const u32 i = gpr.GetImm(a); + const u32 j = mex ? -1 : gpr.GetImm(b); + handle_imm(i, j); } else {