Merge pull request #13266 from JosJuice/jitarm64-cr-bits-1-to-31

JitArm64: Fix creqv/crorc setting eq bit
This commit is contained in:
JosJuice 2025-01-19 13:00:30 +01:00 committed by GitHub
commit af87d60b6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 8 deletions

View File

@ -356,7 +356,10 @@ protected:
void WriteBLRExit(Arm64Gen::ARM64Reg dest);
void GetCRFieldBit(int field, int bit, Arm64Gen::ARM64Reg out);
void SetCRFieldBit(int field, int bit, Arm64Gen::ARM64Reg in, bool negate = false);
// This assumes that all bits except for bit 0 (LSB) are set to 0. But if bits_1_to_31_are_set
// equals true, it instead assumes that all of bits 1 to 31 are set.
void SetCRFieldBit(int field, int bit, Arm64Gen::ARM64Reg in, bool negate = false,
bool bits_1_to_31_are_set = false);
void ClearCRFieldBit(int field, int bit);
void SetCRFieldBit(int field, int bit);
void FixGTBeforeSettingCRFieldBit(Arm64Gen::ARM64Reg reg);

View File

@ -50,7 +50,8 @@ void JitArm64::GetCRFieldBit(int field, int bit, ARM64Reg out)
}
}
void JitArm64::SetCRFieldBit(int field, int bit, ARM64Reg in, bool negate)
void JitArm64::SetCRFieldBit(int field, int bit, ARM64Reg in, bool negate,
bool bits_1_to_31_are_set)
{
gpr.BindCRToRegister(field, true);
ARM64Reg CR = gpr.CR(field);
@ -70,7 +71,9 @@ void JitArm64::SetCRFieldBit(int field, int bit, ARM64Reg in, bool negate)
AND(CR, CR, LogicalImm(0xFFFF'FFFF'0000'0000, GPRSize::B64));
ORR(CR, CR, in);
if (!negate)
EOR(CR, CR, LogicalImm(1ULL << 0, GPRSize::B64));
EOR(CR, CR, LogicalImm(bits_1_to_31_are_set ? 0xFFFF'FFFFULL : 1ULL, GPRSize::B64));
else if (bits_1_to_31_are_set)
AND(CR, CR, LogicalImm(0xFFFF'FFFF'0000'0001ULL, GPRSize::B64));
break;
case PowerPC::CR_GT_BIT: // set bit 63 to !input
@ -632,8 +635,12 @@ void JitArm64::crXXX(UGeckoInstruction inst)
}
}
// crnor or crnand
const bool negate_result = inst.SUBOP10 == 33 || inst.SUBOP10 == 225;
const u32 crbd_bit = 3 - (inst.CRBD & 3);
// crnor, crnand and sometimes creqv
const bool negate_result =
inst.SUBOP10 == 33 || inst.SUBOP10 == 225 ||
(inst.SUBOP10 == 289 && (crbd_bit == PowerPC::CR_EQ_BIT || crbd_bit == PowerPC::CR_GT_BIT));
bool bits_1_to_31_are_set = false;
auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA);
@ -661,7 +668,17 @@ void JitArm64::crXXX(UGeckoInstruction inst)
break;
case 289: // creqv: ~(A ^ B) = A ^ ~B
EON(XA, XA, XB);
// Both of these two implementations are equally correct, but which one is more efficient
// depends on which bit we're going to set in CRBD
if (negate_result)
{
EOR(XA, XA, XB);
}
else
{
EON(WA, WA, WB);
bits_1_to_31_are_set = true;
}
break;
case 33: // crnor: ~(A || B)
@ -670,13 +687,14 @@ void JitArm64::crXXX(UGeckoInstruction inst)
break;
case 417: // crorc: A || ~B
ORN(XA, XA, XB);
ORN(WA, WA, WB);
bits_1_to_31_are_set = true;
break;
}
}
// Store result bit in CRBD
SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3), XA, negate_result);
SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3), XA, negate_result, bits_1_to_31_are_set);
}
void JitArm64::mfcr(UGeckoInstruction inst)