Jits: Fix accidentally setting GT in CR when clearing EQ
https://bugs.dolphin-emu.org/issues/12526
This commit is contained in:
parent
c648058efd
commit
de3fed6093
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue