PowerPC: move SO bit to a more convenient location

Spacing the LT and SO bits like in the native PowerPC format makes it easier to
convert to that format (see mfcr).
This commit is contained in:
Tillmann Karras 2021-06-06 06:12:21 +01:00
parent aff39af5fb
commit 25a701aa1b
5 changed files with 39 additions and 45 deletions

View File

@ -25,7 +25,7 @@ enum CRBits
// Optimized CR implementation. Instead of storing CR in its PowerPC format // Optimized CR implementation. Instead of storing CR in its PowerPC format
// (4 bit value, SO/EQ/LT/GT), we store instead a 64 bit value for each of // (4 bit value, SO/EQ/LT/GT), we store instead a 64 bit value for each of
// the 8 CR register parts. This 64 bit value follows this format: // the 8 CR register parts. This 64 bit value follows this format:
// - SO iff. bit 61 is set // - SO iff. bit 59 is set
// - EQ iff. lower 32 bits == 0 // - EQ iff. lower 32 bits == 0
// - GT iff. (s64)cr_val > 0 // - GT iff. (s64)cr_val > 0
// - LT iff. bit 62 is set // - LT iff. bit 62 is set
@ -46,7 +46,7 @@ struct ConditionRegister
static u64 PPCToInternal(u8 value) static u64 PPCToInternal(u8 value)
{ {
u64 cr_val = 0x100000000; u64 cr_val = 0x100000000;
cr_val |= (u64) !!(value & CR_SO) << 61; cr_val |= (u64) !!(value & CR_SO) << 59;
cr_val |= (u64) !(value & CR_EQ); cr_val |= (u64) !(value & CR_EQ);
cr_val |= (u64) !(value & CR_GT) << 63; cr_val |= (u64) !(value & CR_GT) << 63;
cr_val |= (u64) !!(value & CR_LT) << 62; cr_val |= (u64) !!(value & CR_LT) << 62;
@ -63,14 +63,12 @@ struct ConditionRegister
const u64 cr_val = fields[cr_field]; const u64 cr_val = fields[cr_field];
u32 ppc_cr = 0; u32 ppc_cr = 0;
// SO // LT/SO
ppc_cr |= !!(cr_val & (1ull << 61)); ppc_cr |= (cr_val >> 59) & (PowerPC::CR_LT | PowerPC::CR_SO);
// EQ // EQ
ppc_cr |= ((cr_val & 0xFFFFFFFF) == 0) << 1; ppc_cr |= ((cr_val & 0xFFFFFFFF) == 0) << PowerPC::CR_EQ_BIT;
// GT // GT
ppc_cr |= (static_cast<s64>(cr_val) > 0) << 2; ppc_cr |= (static_cast<s64>(cr_val) > 0) << PowerPC::CR_GT_BIT;
// LT
ppc_cr |= !!(cr_val & (1ull << 62)) << 3;
return ppc_cr; return ppc_cr;
} }

View File

@ -13,7 +13,7 @@ void Interpreter::Helper_UpdateCR0(u32 value)
{ {
s64 sign_extended = (s64)(s32)value; s64 sign_extended = (s64)(s32)value;
u64 cr_val = (u64)sign_extended; u64 cr_val = (u64)sign_extended;
cr_val = (cr_val & ~(1ull << 61)) | ((u64)PowerPC::GetXER_SO() << 61); cr_val = (cr_val & ~(1ull << 59)) | ((u64)PowerPC::GetXER_SO() << 59);
PowerPC::ppcState.cr.fields[0] = cr_val; PowerPC::ppcState.cr.fields[0] = cr_val;
} }

View File

@ -24,8 +24,8 @@ void Jit64::GetCRFieldBit(int field, int bit, X64Reg out, bool negate)
{ {
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: // check bit 61 set case PowerPC::CR_SO_BIT: // check bit 59 set
BT(64, CROffset(field), Imm8(61)); BT(64, CROffset(field), Imm8(59));
SETcc(negate ? CC_NC : CC_C, R(out)); SETcc(negate ? CC_NC : CC_C, R(out));
break; break;
@ -59,9 +59,9 @@ void Jit64::SetCRFieldBit(int field, int bit, X64Reg in)
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: // set bit 61 to input case PowerPC::CR_SO_BIT: // set bit 59 to input
BTR(64, R(RSCRATCH2), Imm8(61)); BTR(64, R(RSCRATCH2), Imm8(59));
SHL(64, R(in), Imm8(61)); SHL(64, R(in), Imm8(59));
OR(64, R(RSCRATCH2), R(in)); OR(64, R(RSCRATCH2), R(in));
break; break;
@ -95,7 +95,7 @@ void Jit64::ClearCRFieldBit(int field, int bit)
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: case PowerPC::CR_SO_BIT:
BTR(64, CROffset(field), Imm8(61)); BTR(64, CROffset(field), Imm8(59));
break; break;
case PowerPC::CR_EQ_BIT: case PowerPC::CR_EQ_BIT:
@ -126,7 +126,7 @@ void Jit64::SetCRFieldBit(int field, int bit)
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: case PowerPC::CR_SO_BIT:
BTS(64, R(RSCRATCH), Imm8(61)); BTS(64, R(RSCRATCH), Imm8(59));
break; break;
case PowerPC::CR_EQ_BIT: case PowerPC::CR_EQ_BIT:
@ -162,8 +162,8 @@ FixupBranch Jit64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
{ {
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: // check bit 61 set case PowerPC::CR_SO_BIT: // check bit 59 set
BT(64, CROffset(field), Imm8(61)); BT(64, CROffset(field), Imm8(59));
return J_CC(jump_if_set ? CC_C : CC_NC, true); return J_CC(jump_if_set ? CC_C : CC_NC, true);
case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0 case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0

View File

@ -301,19 +301,15 @@ void CommonAsmRoutines::GenMfcr()
X64Reg tmp = RSCRATCH2; X64Reg tmp = RSCRATCH2;
X64Reg cr_val = RSCRATCH_EXTRA; X64Reg cr_val = RSCRATCH_EXTRA;
XOR(32, R(dst), R(dst)); XOR(32, R(dst), R(dst));
// Upper bits of tmp need to be zeroed.
XOR(32, R(tmp), R(tmp));
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
static const u32 m_flagTable[8] = {0x0, 0x1, 0x8, 0x9, 0x0, 0x1, 0x8, 0x9};
if (i != 0) if (i != 0)
SHL(32, R(dst), Imm8(4)); SHL(32, R(dst), Imm8(4));
MOV(64, R(cr_val), PPCSTATE(cr.fields[i])); MOV(64, R(cr_val), PPCSTATE(cr.fields[i]));
// Upper bits of tmp need to be zeroed.
// Note: tmp is used later for address calculations and thus
// can't be zero-ed once. This also prevents partial
// register stalls due to SETcc.
XOR(32, R(tmp), R(tmp));
// EQ: Bits 31-0 == 0; set flag bit 1 // EQ: Bits 31-0 == 0; set flag bit 1
TEST(32, R(cr_val), R(cr_val)); TEST(32, R(cr_val), R(cr_val));
SETcc(CC_Z, R(tmp)); SETcc(CC_Z, R(tmp));
@ -324,11 +320,11 @@ void CommonAsmRoutines::GenMfcr()
SETcc(CC_G, R(tmp)); SETcc(CC_G, R(tmp));
LEA(32, dst, MComplex(dst, tmp, SCALE_4, 0)); LEA(32, dst, MComplex(dst, tmp, SCALE_4, 0));
// SO: Bit 61 set; set flag bit 0 // SO: Bit 59 set; set flag bit 0
// LT: Bit 62 set; set flag bit 3 // LT: Bit 62 set; set flag bit 3
SHR(64, R(cr_val), Imm8(61)); SHR(64, R(cr_val), Imm8(59));
LEA(64, tmp, MConst(m_flagTable)); AND(32, R(cr_val), Imm8(PowerPC::CR_LT | PowerPC::CR_SO));
OR(32, R(dst), MComplex(tmp, cr_val, SCALE_4, 0)); OR(32, R(dst), R(cr_val));
} }
RET(); RET();

View File

@ -21,8 +21,8 @@ FixupBranch JitArm64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: // check bit 61 set case PowerPC::CR_SO_BIT: // check bit 59 set
return jump_if_set ? TBNZ(XA, 61) : TBZ(XA, 61); return jump_if_set ? TBNZ(XA, 59) : TBZ(XA, 59);
case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0 case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0
return jump_if_set ? CBZ(WA) : CBNZ(WA); return jump_if_set ? CBZ(WA) : CBNZ(WA);
case PowerPC::CR_GT_BIT: // check val > 0 case PowerPC::CR_GT_BIT: // check val > 0
@ -441,20 +441,20 @@ void JitArm64::crXXX(UGeckoInstruction inst)
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: case PowerPC::CR_SO_BIT:
AND(XA, XA, 64 - 62, 62, true); // XA & ~(1<<61) ANDI2R(XA, XA, ~(u64(1) << 59));
break; break;
case PowerPC::CR_EQ_BIT: case PowerPC::CR_EQ_BIT:
FixGTBeforeSettingCRFieldBit(XA); FixGTBeforeSettingCRFieldBit(XA);
ORR(XA, XA, 0, 0, true); // XA | 1<<0 ORRI2R(XA, XA, 1);
break; break;
case PowerPC::CR_GT_BIT: case PowerPC::CR_GT_BIT:
ORR(XA, XA, 64 - 63, 0, true); // XA | 1<<63 ORRI2R(XA, XA, u64(1) << 63);
break; break;
case PowerPC::CR_LT_BIT: case PowerPC::CR_LT_BIT:
AND(XA, XA, 64 - 63, 62, true); // XA & ~(1<<62) ANDI2R(XA, XA, ~(u64(1) << 62));
break; break;
} }
return; return;
@ -476,23 +476,23 @@ void JitArm64::crXXX(UGeckoInstruction inst)
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: case PowerPC::CR_SO_BIT:
ORR(XA, XA, 64 - 61, 0, true); // XA | 1<<61 ORRI2R(XA, XA, u64(1) << 59);
break; break;
case PowerPC::CR_EQ_BIT: case PowerPC::CR_EQ_BIT:
AND(XA, XA, 32, 31, true); // Clear lower 32bits ANDI2R(XA, XA, 0xFFFF'FFFF'0000'0000);
break; break;
case PowerPC::CR_GT_BIT: case PowerPC::CR_GT_BIT:
AND(XA, XA, 0, 62, true); // XA & ~(1<<63) ANDI2R(XA, XA, ~(u64(1) << 63));
break; break;
case PowerPC::CR_LT_BIT: case PowerPC::CR_LT_BIT:
ORR(XA, XA, 64 - 62, 0, true); // XA | 1<<62 ORRI2R(XA, XA, u64(1) << 62);
break; break;
} }
ORR(XA, XA, 32, 0, true); // XA | 1<<32 ORRI2R(XA, XA, u64(1) << 32);
return; return;
} }
@ -519,8 +519,8 @@ void JitArm64::crXXX(UGeckoInstruction inst)
ARM64Reg WC = EncodeRegTo32(XC); ARM64Reg WC = EncodeRegTo32(XC);
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: // check bit 61 set case PowerPC::CR_SO_BIT: // check bit 59 set
UBFX(out, XC, 61, 1); UBFX(out, XC, 59, 1);
if (negate) if (negate)
EOR(out, out, 0, 0, true); // XC ^ 1 EOR(out, out, 0, 0, true); // XC ^ 1
break; break;
@ -581,8 +581,8 @@ void JitArm64::crXXX(UGeckoInstruction inst)
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: // set bit 61 to input case PowerPC::CR_SO_BIT: // set bit 59 to input
BFI(XB, XA, 61, 1); BFI(XB, XA, 59, 1);
break; break;
case PowerPC::CR_EQ_BIT: // clear low 32 bits, set bit 0 to !input case PowerPC::CR_EQ_BIT: // clear low 32 bits, set bit 0 to !input
@ -625,11 +625,11 @@ void JitArm64::mfcr(UGeckoInstruction inst)
// SO // SO
if (i == 0) if (i == 0)
{ {
UBFX(XA, CR, 61, 1); UBFX(XA, CR, 59, 1);
} }
else else
{ {
UBFX(XC, CR, 61, 1); UBFX(XC, CR, 59, 1);
ORR(XA, XC, XA, ArithOption(XA, ShiftType::LSL, 4)); ORR(XA, XC, XA, ArithOption(XA, ShiftType::LSL, 4));
} }