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.
This commit is contained in:
JosJuice 2025-11-17 20:00:36 +01:00
parent 56532c850f
commit 49e9cd42d4

View File

@ -1267,53 +1267,55 @@ void JitArm64::subfcx(UGeckoInstruction inst)
int a = inst.RA, b = inst.RB, d = inst.RD; 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); if (d != b)
MOV(gpr.R(d), gpr.R(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)))
{ if (gpr.IsImm(b, 0))
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))
{ {
gpr.BindToRegister(d, d == a); gpr.BindToRegister(d, d == a);
CARRY_IF_NEEDED(NEG, NEGS, gpr.R(d), gpr.R(a)); CARRY_IF_NEEDED(NEG, NEGS, gpr.R(d), gpr.R(a));
ComputeCarry(); ComputeCarry();
if (inst.Rc) if (inst.Rc)
ComputeRC0(gpr.R(d)); ComputeRC0(gpr.R(d));
return;
} }
else
{
gpr.BindToRegister(d, d == a || d == b);
// d = b - a gpr.BindToRegister(d, d == a || d == b);
CARRY_IF_NEEDED(SUB, SUBS, gpr.R(d), gpr.R(b), gpr.R(a));
ComputeCarry(); // d = b - a
CARRY_IF_NEEDED(SUB, SUBS, gpr.R(d), gpr.R(b), gpr.R(a));
if (inst.Rc) ComputeCarry();
ComputeRC0(gpr.R(d));
} if (inst.Rc)
ComputeRC0(gpr.R(d));
} }
void JitArm64::subfzex(UGeckoInstruction inst) void JitArm64::subfzex(UGeckoInstruction inst)