Jits: Fix accidentally setting GT in CR when clearing EQ

https://bugs.dolphin-emu.org/issues/12526
This commit is contained in:
JosJuice 2021-05-30 21:57:31 +02:00
parent c648058efd
commit de3fed6093
4 changed files with 35 additions and 35 deletions

View File

@ -116,6 +116,7 @@ public:
void SetCRFieldBit(int field, int bit, Gen::X64Reg in);
void ClearCRFieldBit(int field, int bit);
void SetCRFieldBit(int field, int bit);
void FixGTBeforeSettingCRFieldBit(Gen::X64Reg reg);
// Generates a branch that will check if a given bit of a CR register part
// is set or not.

View File

@ -54,16 +54,8 @@ void Jit64::SetCRFieldBit(int field, int bit, X64Reg in)
MOV(64, R(RSCRATCH2), CROffset(field));
MOVZX(32, 8, in, R(in));
// Gross but necessary; if the input is totally zero and we set SO or LT,
// or even just add the (1<<32), GT will suddenly end up set without us
// intending to. This can break actual games, so fix it up.
if (bit != PowerPC::CR_GT_BIT)
{
TEST(64, R(RSCRATCH2), R(RSCRATCH2));
FixupBranch dont_clear_gt = J_CC(CC_NZ);
BTS(64, R(RSCRATCH2), Imm8(63));
SetJumpTarget(dont_clear_gt);
}
FixGTBeforeSettingCRFieldBit(RSCRATCH2);
switch (bit)
{
@ -107,7 +99,10 @@ void Jit64::ClearCRFieldBit(int field, int bit)
break;
case PowerPC::CR_EQ_BIT:
OR(64, CROffset(field), Imm8(1));
MOV(64, R(RSCRATCH), CROffset(field));
FixGTBeforeSettingCRFieldBit(RSCRATCH);
OR(64, R(RSCRATCH), Imm8(1));
MOV(64, CROffset(field), R(RSCRATCH));
break;
case PowerPC::CR_GT_BIT:
@ -126,12 +121,7 @@ void Jit64::SetCRFieldBit(int field, int bit)
{
MOV(64, R(RSCRATCH), CROffset(field));
if (bit != PowerPC::CR_GT_BIT)
{
TEST(64, R(RSCRATCH), R(RSCRATCH));
FixupBranch dont_clear_gt = J_CC(CC_NZ);
BTS(64, R(RSCRATCH), Imm8(63));
SetJumpTarget(dont_clear_gt);
}
FixGTBeforeSettingCRFieldBit(RSCRATCH);
switch (bit)
{
@ -157,6 +147,17 @@ void Jit64::SetCRFieldBit(int field, int bit)
MOV(64, CROffset(field), R(RSCRATCH));
}
void Jit64::FixGTBeforeSettingCRFieldBit(Gen::X64Reg reg)
{
// Gross but necessary; if the input is totally zero and we set SO or LT,
// or even just add the (1<<32), GT will suddenly end up set without us
// intending to. This can break actual games, so fix it up.
TEST(64, R(reg), R(reg));
FixupBranch dont_clear_gt = J_CC(CC_NZ);
BTS(64, R(reg), Imm8(63));
SetJumpTarget(dont_clear_gt);
}
FixupBranch Jit64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
{
switch (bit)

View File

@ -255,6 +255,7 @@ protected:
void FakeLKExit(u32 exit_address_after_return);
void WriteBLRExit(Arm64Gen::ARM64Reg dest);
void FixGTBeforeSettingCRFieldBit(Arm64Gen::ARM64Reg reg);
Arm64Gen::FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set);
void ComputeRC0(Arm64Gen::ARM64Reg reg);

View File

@ -36,6 +36,19 @@ FixupBranch JitArm64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
}
}
void JitArm64::FixGTBeforeSettingCRFieldBit(Arm64Gen::ARM64Reg reg)
{
// Gross but necessary; if the input is totally zero and we set SO or LT,
// or even just add the (1<<32), GT will suddenly end up set without us
// intending to. This can break actual games, so fix it up.
ARM64Reg WA = gpr.GetReg();
ARM64Reg XA = EncodeRegTo64(WA);
ORR(XA, reg, 64 - 63, 0, true); // XB | 1<<63
CMP(reg, ARM64Reg::ZR);
CSEL(reg, reg, XA, CC_NEQ);
gpr.Unlock(WA);
}
void JitArm64::mtmsr(UGeckoInstruction inst)
{
INSTRUCTION_START
@ -432,6 +445,7 @@ void JitArm64::crXXX(UGeckoInstruction inst)
break;
case PowerPC::CR_EQ_BIT:
FixGTBeforeSettingCRFieldBit(XA);
ORR(XA, XA, 0, 0, true); // XA | 1<<0
break;
@ -457,14 +471,7 @@ void JitArm64::crXXX(UGeckoInstruction inst)
ARM64Reg XA = gpr.CR(field);
if (bit != PowerPC::CR_GT_BIT)
{
ARM64Reg WB = gpr.GetReg();
ARM64Reg XB = EncodeRegTo64(WB);
ORR(XB, XA, 64 - 63, 0, true); // XA | 1<<63
CMP(XA, ARM64Reg::ZR);
CSEL(XA, XA, XB, CC_NEQ);
gpr.Unlock(WB);
}
FixGTBeforeSettingCRFieldBit(XA);
switch (bit)
{
@ -569,18 +576,8 @@ void JitArm64::crXXX(UGeckoInstruction inst)
gpr.BindCRToRegister(field, true);
XB = gpr.CR(field);
// Gross but necessary; if the input is totally zero and we set SO or LT,
// or even just add the (1<<32), GT will suddenly end up set without us
// intending to. This can break actual games, so fix it up.
if (bit != PowerPC::CR_GT_BIT)
{
ARM64Reg WC = gpr.GetReg();
ARM64Reg XC = EncodeRegTo64(WC);
ORR(XC, XB, 64 - 63, 0, true); // XB | 1<<63
CMP(XB, ARM64Reg::ZR);
CSEL(XB, XB, XC, CC_NEQ);
gpr.Unlock(WC);
}
FixGTBeforeSettingCRFieldBit(XB);
switch (bit)
{