summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2021-05-30 21:57:31 +0200
committerJosJuice <josjuice@gmail.com>2021-05-30 22:07:53 +0200
commitde3fed609339ec89ff93122d304598f3e4495685 (patch)
treecb2839526739b9c6fad73fc59c7a59fbde406a39 /Source
parentc648058efd4383b2ac69c4ed52e98973b735321b (diff)
Jits: Fix accidentally setting GT in CR when clearing EQ
https://bugs.dolphin-emu.org/issues/12526
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Core/PowerPC/Jit64/Jit.h1
-rw-r--r--Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp33
-rw-r--r--Source/Core/Core/PowerPC/JitArm64/Jit.h1
-rw-r--r--Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp35
4 files changed, 35 insertions, 35 deletions
diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h
index 358e7a8ea6..029cef0974 100644
--- a/Source/Core/Core/PowerPC/Jit64/Jit.h
+++ b/Source/Core/Core/PowerPC/Jit64/Jit.h
@@ -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.
diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp
index 99c323398f..8044986492 100644
--- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp
+++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp
@@ -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)
diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h
index 93263704fa..c16521b240 100644
--- a/Source/Core/Core/PowerPC/JitArm64/Jit.h
+++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h
@@ -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);
diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
index 074f4d3c42..33cf6d51b7 100644
--- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
+++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
@@ -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)
{