Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #9770 from JosJuice/jits-accidental-gt
Jits: Fix accidentally setting GT in CR when clearing EQ
  • Loading branch information
Tilka committed Jun 6, 2021
2 parents 6c0180f + de3fed6 commit 89af7b8
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 35 deletions.
1 change: 1 addition & 0 deletions Source/Core/Core/PowerPC/Jit64/Jit.h
Expand Up @@ -116,6 +116,7 @@ class Jit64 : public JitBase, public QuantizedMemoryRoutines
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.
Expand Down
33 changes: 17 additions & 16 deletions Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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:
Expand All @@ -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)
{
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/PowerPC/JitArm64/Jit.h
Expand Up @@ -255,6 +255,7 @@ class JitArm64 : public JitBase, public Arm64Gen::ARM64CodeBlock, public CommonA
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);
Expand Down
35 changes: 16 additions & 19 deletions Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down

0 comments on commit 89af7b8

Please sign in to comment.