From d7e449ab75ca0a5a704ec9b19cc0dde5bfedfea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Oct 2026 21:45:10 +0200 Subject: [PATCH] ARM JIT: Fix ins with msb below pos, ext past bit 31, and constant max/min ins with msb below pos encoded an invalid BFI instead of doing nothing, as the interpreter and the other JITs do, and ext with pos + size past 32 an invalid UBFX. max and min of two constants compared them unsigned. Found by CPUEquivalence. Co-Authored-By: Claude Opus 5.5 --- Core/MIPS/ARM/ArmCompALU.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index aa0b782732..44d22199bb 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -425,7 +425,7 @@ namespace MIPSComp case 44: //R(rd) = max(R(rs), R(rt); break; //max if (gpr.IsImm(rs) && gpr.IsImm(rt)) { - gpr.SetImm(rd, std::max(gpr.GetImm(rs), gpr.GetImm(rt))); + gpr.SetImm(rd, std::max((s32)gpr.GetImm(rs), (s32)gpr.GetImm(rt))); break; } gpr.MapDirtyInIn(rd, rs, rt); @@ -441,7 +441,7 @@ namespace MIPSComp case 45: //R(rd) = min(R(rs), R(rt)); break; //min if (gpr.IsImm(rs) && gpr.IsImm(rt)) { - gpr.SetImm(rd, std::min(gpr.GetImm(rs), gpr.GetImm(rt))); + gpr.SetImm(rd, std::min((s32)gpr.GetImm(rs), (s32)gpr.GetImm(rt))); break; } gpr.MapDirtyInIn(rd, rs, rt); @@ -555,7 +555,8 @@ namespace MIPSComp gpr.MapDirtyIn(rt, rs); #if PPSSPP_ARCH(ARMV7) - UBFX(gpr.R(rt), gpr.R(rs), pos, size); + // Bits past 31 come out as zero, and UBFX can't encode them. + UBFX(gpr.R(rt), gpr.R(rs), pos, std::min(size, 32 - pos)); #else MOV(gpr.R(rt), Operand2(gpr.R(rs), ST_LSR, pos)); ANDI2R(gpr.R(rt), gpr.R(rt), mask, SCRATCHREG1); @@ -566,6 +567,9 @@ namespace MIPSComp { u32 sourcemask = mask >> pos; u32 destmask = ~(sourcemask << pos); + // With msb below pos there's nothing to insert, and no BFI for it. + if (sourcemask == 0) + return; if (gpr.IsImm(rs)) { u32 inserted = (gpr.GetImm(rs) & sourcemask) << pos; if (gpr.IsImm(rt)) {