summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2026-06-28 11:14:47 +0200
committerGitHub <noreply@github.com>2026-06-28 11:14:47 +0200
commitafdee595f69ffc485e54a8727525dbc52a4df14c (patch)
treebe668a1fc2d527b33a4fae492e3388e155d38a4c /Source
parent9416eb9537d4cdbee83f38128321e70096841800 (diff)
parent711c3e1013772634dd8787c659de84aadb9de4c2 (diff)
Merge pull request #14198 from JosJuice/jit64-cmpxx-rb-comparand
Jit64: Improve cmpXX imm handling
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp92
1 files changed, 57 insertions, 35 deletions
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<u32> 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();
}
}