From 49e9cd42d450ae6252439559c5f385e70a3c0f18 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 17 Nov 2025 20:00:36 +0100 Subject: [PATCH] JitArm64: Call GetImm before BindToRegister in subfcx When BindToRegister is called, the register cache marks the relevant guest register as no longer containing an immediate. However, subfcx was calling GetImm after BindToRegister. This led to a lot of panic alerts after 2995aa5be4 added an assert to GetImm to check that the passed-in register is an immediate. Both before and after 2995aa5be4, the actual value of the immediate wasn't overwritten by BindForRegister, only the fact that the register is an immediate. Because of this, the emitted code happened to work correctly. --- .../PowerPC/JitArm64/JitArm64_Integer.cpp | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index dd01d6dbddb..cd8b00d49f3 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -1267,53 +1267,55 @@ void JitArm64::subfcx(UGeckoInstruction inst) int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a, 0)) + if (gpr.IsImm(a)) { - if (d != b) + const u32 imm = gpr.GetImm(a); + + if (imm == 0) { - gpr.BindToRegister(d, false); - MOV(gpr.R(d), gpr.R(b)); + if (d != b) + { + gpr.BindToRegister(d, false); + MOV(gpr.R(d), gpr.R(b)); + } + ComputeCarry(true); + if (inst.Rc) + ComputeRC0(gpr.R(d)); + return; + } + + const bool low_12 = (imm & 0xFFF) == imm; + const bool high_12 = (imm & 0xFFF000) == imm; + if (low_12 || high_12) + { + gpr.BindToRegister(d, d == b); + CARRY_IF_NEEDED(SUB, SUBS, gpr.R(d), gpr.R(b), high_12 ? imm >> 12 : imm, high_12); + ComputeCarry(); + if (inst.Rc) + ComputeRC0(gpr.R(d)); + return; } - ComputeCarry(true); - if (inst.Rc) - ComputeRC0(gpr.R(d)); } - else if (gpr.IsImm(a) && ((gpr.GetImm(a) & 0xFFF) == gpr.GetImm(a))) - { - gpr.BindToRegister(d, d == b); - CARRY_IF_NEEDED(SUB, SUBS, gpr.R(d), gpr.R(b), gpr.GetImm(a)); - ComputeCarry(); - if (inst.Rc) - ComputeRC0(gpr.R(d)); - } - else if (gpr.IsImm(a) && ((gpr.GetImm(a) & 0xFFF000) == gpr.GetImm(a))) - { - gpr.BindToRegister(d, d == b); - CARRY_IF_NEEDED(SUB, SUBS, gpr.R(d), gpr.R(b), gpr.GetImm(a) >> 12, true); - ComputeCarry(); - if (inst.Rc) - ComputeRC0(gpr.R(d)); - } - else if (gpr.IsImm(b, 0)) + + if (gpr.IsImm(b, 0)) { gpr.BindToRegister(d, d == a); CARRY_IF_NEEDED(NEG, NEGS, gpr.R(d), gpr.R(a)); ComputeCarry(); if (inst.Rc) ComputeRC0(gpr.R(d)); + return; } - else - { - gpr.BindToRegister(d, d == a || d == b); - // d = b - a - CARRY_IF_NEEDED(SUB, SUBS, gpr.R(d), gpr.R(b), gpr.R(a)); + gpr.BindToRegister(d, d == a || d == b); - ComputeCarry(); + // d = b - a + CARRY_IF_NEEDED(SUB, SUBS, gpr.R(d), gpr.R(b), gpr.R(a)); - if (inst.Rc) - ComputeRC0(gpr.R(d)); - } + ComputeCarry(); + + if (inst.Rc) + ComputeRC0(gpr.R(d)); } void JitArm64::subfzex(UGeckoInstruction inst)