diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 70f61d8b9a..978951118c 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -541,39 +541,38 @@ void Jit64::cmpXX(UGeckoInstruction inst) u32 crf = inst.CRFD; bool merge_branch = CheckMergedBranch(crf); - bool signedCompare; - RCOpArg comparand; + bool signedCompare = false; + std::optional imm_comparand; switch (inst.OPCD) { // cmp / cmpl case 31: signedCompare = (inst.SUBOP10 == 0); - comparand = signedCompare ? gpr.Use(b, RCMode::Read) : gpr.Bind(b, RCMode::Read); - RegCache::Realize(comparand); + if (gpr.IsImm(b)) + imm_comparand = gpr.Imm32(b); break; // cmpli case 10: signedCompare = false; - comparand = RCOpArg::Imm32((u32)inst.UIMM); + imm_comparand = u32(inst.UIMM); break; // cmpi case 11: signedCompare = true; - comparand = RCOpArg::Imm32((u32)(s32)(s16)inst.UIMM); + imm_comparand = u32(s32(s16(inst.UIMM))); break; default: - signedCompare = false; // silence compiler warning PanicAlertFmt("cmpXX"); } - if (gpr.IsImm(a) && comparand.IsImm()) + if (gpr.IsImm(a) && imm_comparand.has_value()) { // Both registers contain immediate values, so we can pre-compile the compare result - s64 compareResult = signedCompare ? (s64)gpr.SImm32(a) - (s64)comparand.SImm32() : - (u64)gpr.Imm32(a) - (u64)comparand.Imm32(); + s64 compareResult = signedCompare ? s64(gpr.SImm32(a)) - s64(s32(imm_comparand.value())) : + u64(gpr.Imm32(a)) - u64(imm_comparand.value()); if (compareResult == (s32)compareResult) { MOV(64, PPCSTATE_CR(crf), Imm32((u32)compareResult)); @@ -585,15 +584,12 @@ void Jit64::cmpXX(UGeckoInstruction inst) } if (merge_branch) - { - RegCache::Unlock(comparand); DoMergedBranchImmediate(compareResult); - } return; } - if (!gpr.IsImm(a) && !signedCompare && comparand.IsImm() && comparand.Imm32() == 0) + if (!gpr.IsImm(a) && !signedCompare && imm_comparand == u32(0)) { RCX64Reg Ra = gpr.Bind(a, RCMode::Read); RegCache::Realize(Ra); @@ -602,12 +598,38 @@ void Jit64::cmpXX(UGeckoInstruction inst) if (merge_branch) { TEST(64, Ra, Ra); - RegCache::Unlock(comparand, Ra); + RegCache::Unlock(Ra); DoMergedBranchCondition(); } return; } + const bool comparand_needs_reg = + !signedCompare && imm_comparand.has_value() && (imm_comparand.value() & 0x80000000U) != 0; + + RCOpArg Rb; + OpArg comparand; + if (inst.OPCD != 31) + { + // The comparand is from the instruction encoding, so we can't get it from the register cache. + comparand = Imm32(imm_comparand.value()); + } + else if (signedCompare && imm_comparand.has_value()) + { + // Asking the register cache for the comparand might give us a register, but we prefer an imm. + comparand = Imm32(imm_comparand.value()); + } + else if (imm_comparand != u32(0)) + { + // Ask the register cache for the comparand. We prefer getting a register, + // but may also accept imm or memory depending on the circumstances. + Rb = signedCompare ? + gpr.Use(b, RCMode::Read) : + (comparand_needs_reg ? gpr.Bind(b, RCMode::Read) : gpr.BindOrImm(b, RCMode::Read)); + RegCache::Realize(Rb); + comparand = Rb; + } + const X64Reg input = RSCRATCH; if (gpr.IsImm(a)) { @@ -626,25 +648,7 @@ void Jit64::cmpXX(UGeckoInstruction inst) MOVZX(64, 32, input, Ra); } - if (comparand.IsImm()) - { - // sign extension will ruin this, so store it in a register - if (!signedCompare && (comparand.Imm32() & 0x80000000U) != 0) - { - MOV(32, R(RSCRATCH2), comparand); - comparand = RCOpArg::R(RSCRATCH2); - } - } - else - { - if (signedCompare) - { - MOVSX(64, 32, RSCRATCH2, comparand); - comparand = RCOpArg::R(RSCRATCH2); - } - } - - if (comparand.IsImm() && comparand.Imm32() == 0) + if (imm_comparand == u32(0)) { MOV(64, PPCSTATE_CR(crf), R(input)); // Place the comparison next to the branch for macro-op fusion @@ -653,13 +657,31 @@ void Jit64::cmpXX(UGeckoInstruction inst) } else { + if (comparand.IsImm()) + { + if (comparand_needs_reg) + { + // sign extension will ruin this, so store it in a register + MOV(32, R(RSCRATCH2), comparand); + comparand = R(RSCRATCH2); + } + } + else + { + if (signedCompare) + { + MOVSX(64, 32, RSCRATCH2, comparand); + comparand = R(RSCRATCH2); + } + } + SUB(64, R(input), comparand); MOV(64, PPCSTATE_CR(crf), R(input)); } if (merge_branch) { - RegCache::Unlock(comparand); + RegCache::Unlock(Rb); DoMergedBranchCondition(); } }