JitArm64_SystemRegisters: Use ScopedARM64Reg

This commit is contained in:
Sintendo 2024-06-23 23:21:07 +02:00
parent be2b466743
commit defb2d65a6

View File

@ -48,17 +48,16 @@ void JitArm64::FixGTBeforeSettingCRFieldBit(Arm64Gen::ARM64Reg reg)
// if the internal representation either has bit 63 set or has all bits set to zero. // if the internal representation either has bit 63 set or has all bits set to zero.
// If all bits are zero and we set some bit that's unrelated to GT, we need to set bit 63 so GT // If all bits are zero and we set some bit that's unrelated to GT, we need to set bit 63 so GT
// doesn't accidentally become considered set. Gross but necessary; this can break actual games. // doesn't accidentally become considered set. Gross but necessary; this can break actual games.
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA); ARM64Reg XA = EncodeRegTo64(WA);
ORR(XA, reg, LogicalImm(1ULL << 63, GPRSize::B64)); ORR(XA, reg, LogicalImm(1ULL << 63, GPRSize::B64));
CMP(reg, ARM64Reg::ZR); CMP(reg, ARM64Reg::ZR);
CSEL(reg, reg, XA, CC_NEQ); CSEL(reg, reg, XA, CC_NEQ);
gpr.Unlock(WA);
} }
void JitArm64::UpdateFPExceptionSummary(ARM64Reg fpscr) void JitArm64::UpdateFPExceptionSummary(ARM64Reg fpscr)
{ {
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
// fpscr.VX = (fpscr & FPSCR_VX_ANY) != 0 // fpscr.VX = (fpscr & FPSCR_VX_ANY) != 0
MOVI2R(WA, FPSCR_VX_ANY); MOVI2R(WA, FPSCR_VX_ANY);
@ -71,8 +70,6 @@ void JitArm64::UpdateFPExceptionSummary(ARM64Reg fpscr)
TST(WA, fpscr, ArithOption(fpscr, ShiftType::LSR, 22)); TST(WA, fpscr, ArithOption(fpscr, ShiftType::LSR, 22));
CSET(WA, CCFlags::CC_NEQ); CSET(WA, CCFlags::CC_NEQ);
BFI(fpscr, WA, MathUtil::IntLog2(FPSCR_FEX), 1); BFI(fpscr, WA, MathUtil::IntLog2(FPSCR_FEX), 1);
gpr.Unlock(WA);
} }
void JitArm64::UpdateRoundingMode() void JitArm64::UpdateRoundingMode()
@ -135,7 +132,7 @@ void JitArm64::mcrxr(UGeckoInstruction inst)
JITDISABLE(bJITSystemRegistersOff); JITDISABLE(bJITSystemRegistersOff);
gpr.BindCRToRegister(inst.CRFD, false); gpr.BindCRToRegister(inst.CRFD, false);
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA); ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg XB = gpr.CR(inst.CRFD); ARM64Reg XB = gpr.CR(inst.CRFD);
ARM64Reg WB = EncodeRegTo32(XB); ARM64Reg WB = EncodeRegTo32(XB);
@ -155,8 +152,6 @@ void JitArm64::mcrxr(UGeckoInstruction inst)
// Clear XER[0-3] // Clear XER[0-3]
static_assert(PPCSTATE_OFF(xer_ca) + 1 == PPCSTATE_OFF(xer_so_ov)); static_assert(PPCSTATE_OFF(xer_ca) + 1 == PPCSTATE_OFF(xer_so_ov));
STRH(IndexType::Unsigned, ARM64Reg::WZR, PPC_REG, PPCSTATE_OFF(xer_ca)); STRH(IndexType::Unsigned, ARM64Reg::WZR, PPC_REG, PPCSTATE_OFF(xer_ca));
gpr.Unlock(WA);
} }
void JitArm64::mfsr(UGeckoInstruction inst) void JitArm64::mfsr(UGeckoInstruction inst)
@ -186,14 +181,12 @@ void JitArm64::mfsrin(UGeckoInstruction inst)
ARM64Reg RB = gpr.R(b); ARM64Reg RB = gpr.R(b);
ARM64Reg RD = gpr.R(d); ARM64Reg RD = gpr.R(d);
ARM64Reg index = gpr.GetReg(); auto index = gpr.GetScopedReg();
ARM64Reg addr = EncodeRegTo64(RD); ARM64Reg addr = EncodeRegTo64(RD);
UBFM(index, RB, 28, 31); UBFM(index, RB, 28, 31);
ADDI2R(addr, PPC_REG, PPCSTATE_OFF_SR(0), addr); ADDI2R(addr, PPC_REG, PPCSTATE_OFF_SR(0), addr);
LDR(RD, addr, ArithOption(EncodeRegTo64(index), true)); LDR(RD, addr, ArithOption(EncodeRegTo64(index), true));
gpr.Unlock(index);
} }
void JitArm64::mtsrin(UGeckoInstruction inst) void JitArm64::mtsrin(UGeckoInstruction inst)
@ -206,14 +199,12 @@ void JitArm64::mtsrin(UGeckoInstruction inst)
ARM64Reg RB = gpr.R(b); ARM64Reg RB = gpr.R(b);
ARM64Reg RD = gpr.R(d); ARM64Reg RD = gpr.R(d);
ARM64Reg index = gpr.GetReg(); auto index = gpr.GetScopedReg();
ARM64Reg addr = gpr.GetReg(); auto addr = gpr.GetScopedReg();
UBFM(index, RB, 28, 31); UBFM(index, RB, 28, 31);
ADDI2R(EncodeRegTo64(addr), PPC_REG, PPCSTATE_OFF_SR(0), EncodeRegTo64(addr)); ADDI2R(EncodeRegTo64(addr), PPC_REG, PPCSTATE_OFF_SR(0), EncodeRegTo64(addr));
STR(RD, EncodeRegTo64(addr), ArithOption(EncodeRegTo64(index), true)); STR(RD, EncodeRegTo64(addr), ArithOption(EncodeRegTo64(index), true));
gpr.Unlock(index, addr);
} }
void JitArm64::twx(UGeckoInstruction inst) void JitArm64::twx(UGeckoInstruction inst)
@ -223,7 +214,7 @@ void JitArm64::twx(UGeckoInstruction inst)
s32 a = inst.RA; s32 a = inst.RA;
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
if (inst.OPCD == 3) // twi if (inst.OPCD == 3) // twi
{ {
@ -278,8 +269,6 @@ void JitArm64::twx(UGeckoInstruction inst)
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG); fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
WriteExit(js.compilerPC + 4); WriteExit(js.compilerPC + 4);
} }
gpr.Unlock(WA);
} }
void JitArm64::mfspr(UGeckoInstruction inst) void JitArm64::mfspr(UGeckoInstruction inst)
@ -294,19 +283,19 @@ void JitArm64::mfspr(UGeckoInstruction inst)
case SPR_TL: case SPR_TL:
case SPR_TU: case SPR_TU:
{ {
ARM64Reg Wg = gpr.GetReg(); auto Wg = gpr.GetScopedReg();
ARM64Reg Xg = EncodeRegTo64(Wg); ARM64Reg Xg = EncodeRegTo64(Wg);
ARM64Reg Wresult = gpr.GetReg(); auto Wresult = gpr.GetScopedReg();
ARM64Reg Xresult = EncodeRegTo64(Wresult); ARM64Reg Xresult = EncodeRegTo64(Wresult);
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
ARM64Reg WB = gpr.GetReg(); auto WB = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA); ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg XB = EncodeRegTo64(WB); ARM64Reg XB = EncodeRegTo64(WB);
ARM64Reg VC = fpr.GetReg(); auto VC = fpr.GetScopedReg();
ARM64Reg VD = fpr.GetReg(); auto VD = fpr.GetScopedReg();
ARM64Reg SC = EncodeRegToSingle(VC); ARM64Reg SC = EncodeRegToSingle(VC);
ARM64Reg SD = EncodeRegToSingle(VD); ARM64Reg SD = EncodeRegToSingle(VD);
@ -371,8 +360,6 @@ void JitArm64::mfspr(UGeckoInstruction inst)
else else
LSR(EncodeRegTo64(gpr.R(n)), Xresult, 32); LSR(EncodeRegTo64(gpr.R(n)), Xresult, 32);
gpr.Unlock(Wg, Wresult, WA, WB);
fpr.Unlock(VC, VD);
break; break;
} }
} }
@ -381,22 +368,18 @@ void JitArm64::mfspr(UGeckoInstruction inst)
LSR(EncodeRegTo64(gpr.R(d)), Xresult, 32); LSR(EncodeRegTo64(gpr.R(d)), Xresult, 32);
else else
MOV(gpr.R(d), Wresult); MOV(gpr.R(d), Wresult);
gpr.Unlock(Wg, Wresult, WA, WB);
fpr.Unlock(VC, VD);
} }
break; break;
case SPR_XER: case SPR_XER:
{ {
gpr.BindToRegister(d, false); gpr.BindToRegister(d, false);
ARM64Reg RD = gpr.R(d); ARM64Reg RD = gpr.R(d);
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
LDRH(IndexType::Unsigned, RD, PPC_REG, PPCSTATE_OFF(xer_stringctrl)); LDRH(IndexType::Unsigned, RD, PPC_REG, PPCSTATE_OFF(xer_stringctrl));
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
ORR(RD, RD, WA, ArithOption(WA, ShiftType::LSL, XER_CA_SHIFT)); ORR(RD, RD, WA, ArithOption(WA, ShiftType::LSL, XER_CA_SHIFT));
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov)); LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov));
ORR(RD, RD, WA, ArithOption(WA, ShiftType::LSL, XER_OV_SHIFT)); ORR(RD, RD, WA, ArithOption(WA, ShiftType::LSL, XER_OV_SHIFT));
gpr.Unlock(WA);
} }
break; break;
case SPR_WPAR: case SPR_WPAR:
@ -462,14 +445,13 @@ void JitArm64::mtspr(UGeckoInstruction inst)
case SPR_XER: case SPR_XER:
{ {
ARM64Reg RD = gpr.R(inst.RD); ARM64Reg RD = gpr.R(inst.RD);
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
AND(WA, RD, LogicalImm(0xFFFFFF7F, GPRSize::B32)); AND(WA, RD, LogicalImm(0xFFFFFF7F, GPRSize::B32));
STRH(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_stringctrl)); STRH(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_stringctrl));
UBFM(WA, RD, XER_CA_SHIFT, XER_CA_SHIFT + 1); UBFM(WA, RD, XER_CA_SHIFT, XER_CA_SHIFT + 1);
STRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); STRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
UBFM(WA, RD, XER_OV_SHIFT, 31); // Same as WA = RD >> XER_OV_SHIFT UBFM(WA, RD, XER_OV_SHIFT, 31); // Same as WA = RD >> XER_OV_SHIFT
STRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov)); STRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov));
gpr.Unlock(WA);
} }
break; break;
default: default:
@ -553,114 +535,112 @@ void JitArm64::crXXX(UGeckoInstruction inst)
return; return;
} }
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA); ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg WB = gpr.GetReg();
ARM64Reg XB = EncodeRegTo64(WB);
// creqv or crnand or crnor
bool negateA = inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
// crandc or crorc or crnand or crnor
bool negateB =
inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
// GetCRFieldBit
for (int i = 0; i < 2; i++)
{ {
int field = i ? inst.CRBB >> 2 : inst.CRBA >> 2; auto WB = gpr.GetScopedReg();
int bit = i ? 3 - (inst.CRBB & 3) : 3 - (inst.CRBA & 3); ARM64Reg XB = EncodeRegTo64(WB);
ARM64Reg out = i ? XB : XA;
bool negate = i ? negateB : negateA;
ARM64Reg XC = gpr.CR(field); // creqv or crnand or crnor
ARM64Reg WC = EncodeRegTo32(XC); bool negateA = inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
switch (bit) // crandc or crorc or crnand or crnor
bool negateB =
inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
// GetCRFieldBit
for (int i = 0; i < 2; i++)
{ {
case PowerPC::CR_SO_BIT: // check bit 59 set int field = i ? inst.CRBB >> 2 : inst.CRBA >> 2;
UBFX(out, XC, PowerPC::CR_EMU_SO_BIT, 1); int bit = i ? 3 - (inst.CRBB & 3) : 3 - (inst.CRBA & 3);
if (negate) ARM64Reg out = i ? XB : XA;
EOR(out, out, LogicalImm(1, GPRSize::B64)); bool negate = i ? negateB : negateA;
break;
case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0 ARM64Reg XC = gpr.CR(field);
CMP(WC, ARM64Reg::WZR); ARM64Reg WC = EncodeRegTo32(XC);
CSET(out, negate ? CC_NEQ : CC_EQ); switch (bit)
break; {
case PowerPC::CR_SO_BIT: // check bit 59 set
UBFX(out, XC, PowerPC::CR_EMU_SO_BIT, 1);
if (negate)
EOR(out, out, LogicalImm(1, GPRSize::B64));
break;
case PowerPC::CR_GT_BIT: // check val > 0 case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0
CMP(XC, ARM64Reg::ZR); CMP(WC, ARM64Reg::WZR);
CSET(out, negate ? CC_LE : CC_GT); CSET(out, negate ? CC_NEQ : CC_EQ);
break; break;
case PowerPC::CR_LT_BIT: // check bit 62 set case PowerPC::CR_GT_BIT: // check val > 0
UBFX(out, XC, PowerPC::CR_EMU_LT_BIT, 1); CMP(XC, ARM64Reg::ZR);
if (negate) CSET(out, negate ? CC_LE : CC_GT);
EOR(out, out, LogicalImm(1, GPRSize::B64)); break;
break;
default: case PowerPC::CR_LT_BIT: // check bit 62 set
ASSERT_MSG(DYNA_REC, false, "Invalid CR bit"); UBFX(out, XC, PowerPC::CR_EMU_LT_BIT, 1);
if (negate)
EOR(out, out, LogicalImm(1, GPRSize::B64));
break;
default:
ASSERT_MSG(DYNA_REC, false, "Invalid CR bit");
}
} }
}
// Compute combined bit // Compute combined bit
switch (inst.SUBOP10) switch (inst.SUBOP10)
{ {
case 33: // crnor: ~(A || B) == (~A && ~B) case 33: // crnor: ~(A || B) == (~A && ~B)
case 129: // crandc: A && ~B case 129: // crandc: A && ~B
case 257: // crand: A && B case 257: // crand: A && B
AND(XA, XA, XB); AND(XA, XA, XB);
break; break;
case 193: // crxor: A ^ B case 193: // crxor: A ^ B
case 289: // creqv: ~(A ^ B) = ~A ^ B case 289: // creqv: ~(A ^ B) = ~A ^ B
EOR(XA, XA, XB); EOR(XA, XA, XB);
break; break;
case 225: // crnand: ~(A && B) == (~A || ~B) case 225: // crnand: ~(A && B) == (~A || ~B)
case 417: // crorc: A || ~B case 417: // crorc: A || ~B
case 449: // cror: A || B case 449: // cror: A || B
ORR(XA, XA, XB); ORR(XA, XA, XB);
break; break;
}
} }
// Store result bit in CRBD // Store result bit in CRBD
int field = inst.CRBD >> 2; int field = inst.CRBD >> 2;
int bit = 3 - (inst.CRBD & 3); int bit = 3 - (inst.CRBD & 3);
gpr.Unlock(WB);
WB = ARM64Reg::INVALID_REG;
gpr.BindCRToRegister(field, true); gpr.BindCRToRegister(field, true);
XB = gpr.CR(field); ARM64Reg CR = gpr.CR(field);
if (bit != PowerPC::CR_GT_BIT) if (bit != PowerPC::CR_GT_BIT)
FixGTBeforeSettingCRFieldBit(XB); FixGTBeforeSettingCRFieldBit(CR);
switch (bit) switch (bit)
{ {
case PowerPC::CR_SO_BIT: // set bit 59 to input case PowerPC::CR_SO_BIT: // set bit 59 to input
BFI(XB, XA, PowerPC::CR_EMU_SO_BIT, 1); BFI(CR, XA, PowerPC::CR_EMU_SO_BIT, 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
AND(XB, XB, LogicalImm(0xFFFF'FFFF'0000'0000, GPRSize::B64)); AND(CR, CR, LogicalImm(0xFFFF'FFFF'0000'0000, GPRSize::B64));
EOR(XA, XA, LogicalImm(1, GPRSize::B64)); EOR(XA, XA, LogicalImm(1, GPRSize::B64));
ORR(XB, XB, XA); ORR(CR, CR, XA);
break; break;
case PowerPC::CR_GT_BIT: // set bit 63 to !input case PowerPC::CR_GT_BIT: // set bit 63 to !input
EOR(XA, XA, LogicalImm(1, GPRSize::B64)); EOR(XA, XA, LogicalImm(1, GPRSize::B64));
BFI(XB, XA, 63, 1); BFI(CR, XA, 63, 1);
break; break;
case PowerPC::CR_LT_BIT: // set bit 62 to input case PowerPC::CR_LT_BIT: // set bit 62 to input
BFI(XB, XA, PowerPC::CR_EMU_LT_BIT, 1); BFI(CR, XA, PowerPC::CR_EMU_LT_BIT, 1);
break; break;
} }
ORR(XB, XB, LogicalImm(1ULL << 32, GPRSize::B64)); ORR(CR, CR, LogicalImm(1ULL << 32, GPRSize::B64));
gpr.Unlock(WA);
} }
void JitArm64::mfcr(UGeckoInstruction inst) void JitArm64::mfcr(UGeckoInstruction inst)
@ -670,8 +650,8 @@ void JitArm64::mfcr(UGeckoInstruction inst)
gpr.BindToRegister(inst.RD, false); gpr.BindToRegister(inst.RD, false);
ARM64Reg WA = gpr.R(inst.RD); ARM64Reg WA = gpr.R(inst.RD);
ARM64Reg WB = gpr.GetReg(); auto WB = gpr.GetScopedReg();
ARM64Reg WC = gpr.GetReg(); auto WC = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA); ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg XB = EncodeRegTo64(WB); ARM64Reg XB = EncodeRegTo64(WB);
ARM64Reg XC = EncodeRegTo64(WC); ARM64Reg XC = EncodeRegTo64(WC);
@ -716,8 +696,6 @@ void JitArm64::mfcr(UGeckoInstruction inst)
else if (!js.op->crInUse[i]) else if (!js.op->crInUse[i])
gpr.StoreCRRegisters(BitSet8{i}, WC); gpr.StoreCRRegisters(BitSet8{i}, WC);
} }
gpr.Unlock(WB, WC);
} }
void JitArm64::mtcrf(UGeckoInstruction inst) void JitArm64::mtcrf(UGeckoInstruction inst)
@ -729,7 +707,7 @@ void JitArm64::mtcrf(UGeckoInstruction inst)
if (crm != 0) if (crm != 0)
{ {
ARM64Reg RS = gpr.R(inst.RS); ARM64Reg RS = gpr.R(inst.RS);
ARM64Reg WB = gpr.GetReg(); auto WB = gpr.GetScopedReg();
ARM64Reg XB = EncodeRegTo64(WB); ARM64Reg XB = EncodeRegTo64(WB);
MOVP2R(XB, PowerPC::ConditionRegister::s_crTable.data()); MOVP2R(XB, PowerPC::ConditionRegister::s_crTable.data());
for (int i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
@ -753,7 +731,6 @@ void JitArm64::mtcrf(UGeckoInstruction inst)
LDR(CR, XB, ArithOption(CR, true)); LDR(CR, XB, ArithOption(CR, true));
} }
} }
gpr.Unlock(WB);
} }
} }
@ -771,7 +748,7 @@ void JitArm64::mcrfs(UGeckoInstruction inst)
gpr.BindCRToRegister(field, false); gpr.BindCRToRegister(field, false);
ARM64Reg CR = gpr.CR(field); ARM64Reg CR = gpr.CR(field);
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
ARM64Reg WCR = EncodeRegTo32(CR); ARM64Reg WCR = EncodeRegTo32(CR);
ARM64Reg XA = EncodeRegTo64(WA); ARM64Reg XA = EncodeRegTo64(WA);
@ -789,8 +766,6 @@ void JitArm64::mcrfs(UGeckoInstruction inst)
MOVP2R(XA, PowerPC::ConditionRegister::s_crTable.data()); MOVP2R(XA, PowerPC::ConditionRegister::s_crTable.data());
LDR(CR, XA, ArithOption(CR, true)); LDR(CR, XA, ArithOption(CR, true));
gpr.Unlock(WA);
} }
void JitArm64::mffsx(UGeckoInstruction inst) void JitArm64::mffsx(UGeckoInstruction inst)
@ -799,7 +774,7 @@ void JitArm64::mffsx(UGeckoInstruction inst)
JITDISABLE(bJITSystemRegistersOff); JITDISABLE(bJITSystemRegistersOff);
FALLBACK_IF(inst.Rc); FALLBACK_IF(inst.Rc);
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA); ARM64Reg XA = EncodeRegTo64(WA);
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr)); LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
@ -808,8 +783,6 @@ void JitArm64::mffsx(UGeckoInstruction inst)
ORR(XA, XA, LogicalImm(0xFFF8'0000'0000'0000, GPRSize::B64)); ORR(XA, XA, LogicalImm(0xFFF8'0000'0000'0000, GPRSize::B64));
m_float_emit.FMOV(EncodeRegToDouble(VD), XA); m_float_emit.FMOV(EncodeRegToDouble(VD), XA);
gpr.Unlock(WA);
} }
void JitArm64::mtfsb0x(UGeckoInstruction inst) void JitArm64::mtfsb0x(UGeckoInstruction inst)
@ -824,17 +797,17 @@ void JitArm64::mtfsb0x(UGeckoInstruction inst)
if (mask == FPSCR_FEX || mask == FPSCR_VX) if (mask == FPSCR_FEX || mask == FPSCR_VX)
return; return;
ARM64Reg WA = gpr.GetReg(); {
auto WA = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr)); LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
AND(WA, WA, LogicalImm(inverted_mask, GPRSize::B32)); AND(WA, WA, LogicalImm(inverted_mask, GPRSize::B32));
if ((mask & (FPSCR_ANY_X | FPSCR_ANY_E)) != 0) if ((mask & (FPSCR_ANY_X | FPSCR_ANY_E)) != 0)
UpdateFPExceptionSummary(WA); UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr)); STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
}
gpr.Unlock(WA);
if (inst.CRBD >= 29) if (inst.CRBD >= 29)
UpdateRoundingMode(); UpdateRoundingMode();
@ -852,25 +825,24 @@ void JitArm64::mtfsb1x(UGeckoInstruction inst)
if (mask == FPSCR_FEX || mask == FPSCR_VX) if (mask == FPSCR_FEX || mask == FPSCR_VX)
return; return;
ARM64Reg WA = gpr.GetReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
if ((mask & FPSCR_ANY_X) != 0)
{ {
ARM64Reg WB = gpr.GetReg(); auto WA = gpr.GetScopedReg();
TST(WA, LogicalImm(mask, GPRSize::B32));
ORR(WB, WA, LogicalImm(1 << 31, GPRSize::B32)); LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
CSEL(WA, WA, WB, CCFlags::CC_NEQ);
gpr.Unlock(WB); if ((mask & FPSCR_ANY_X) != 0)
{
auto WB = gpr.GetScopedReg();
TST(WA, LogicalImm(mask, GPRSize::B32));
ORR(WB, WA, LogicalImm(1 << 31, GPRSize::B32));
CSEL(WA, WA, WB, CCFlags::CC_NEQ);
}
ORR(WA, WA, LogicalImm(mask, GPRSize::B32));
if ((mask & (FPSCR_ANY_X | FPSCR_ANY_E)) != 0)
UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
} }
ORR(WA, WA, LogicalImm(mask, GPRSize::B32));
if ((mask & (FPSCR_ANY_X | FPSCR_ANY_E)) != 0)
UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(WA);
if (inst.CRBD >= 29) if (inst.CRBD >= 29)
UpdateRoundingMode(); UpdateRoundingMode();
@ -887,32 +859,31 @@ void JitArm64::mtfsfix(UGeckoInstruction inst)
u8 shift = 28 - 4 * inst.CRFD; u8 shift = 28 - 4 * inst.CRFD;
u32 mask = 0xF << shift; u32 mask = 0xF << shift;
ARM64Reg WA = gpr.GetReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
if (imm == 0xF)
{ {
ORR(WA, WA, LogicalImm(mask, GPRSize::B32)); auto WA = gpr.GetScopedReg();
}
else if (imm == 0x0)
{
const u32 inverted_mask = ~mask;
AND(WA, WA, LogicalImm(inverted_mask, GPRSize::B32));
}
else
{
ARM64Reg WB = gpr.GetReg();
MOVZ(WB, imm);
BFI(WA, WB, shift, 4);
gpr.Unlock(WB);
}
if ((mask & (FPSCR_FEX | FPSCR_VX | FPSCR_ANY_X | FPSCR_ANY_E)) != 0) LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(WA); if (imm == 0xF)
{
ORR(WA, WA, LogicalImm(mask, GPRSize::B32));
}
else if (imm == 0x0)
{
const u32 inverted_mask = ~mask;
AND(WA, WA, LogicalImm(inverted_mask, GPRSize::B32));
}
else
{
auto WB = gpr.GetScopedReg();
MOVZ(WB, imm);
BFI(WA, WB, shift, 4);
}
if ((mask & (FPSCR_FEX | FPSCR_VX | FPSCR_ANY_X | FPSCR_ANY_E)) != 0)
UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
}
// Field 7 contains NI and RN. // Field 7 contains NI and RN.
if (inst.CRFD == 7) if (inst.CRFD == 7)
@ -936,49 +907,43 @@ void JitArm64::mtfsfx(UGeckoInstruction inst)
if (mask == 0xFFFFFFFF) if (mask == 0xFFFFFFFF)
{ {
ARM64Reg VB = fpr.R(inst.FB, RegType::LowerPair); ARM64Reg VB = fpr.R(inst.FB, RegType::LowerPair);
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
m_float_emit.FMOV(WA, EncodeRegToSingle(VB)); m_float_emit.FMOV(WA, EncodeRegToSingle(VB));
UpdateFPExceptionSummary(WA); UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr)); STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(WA);
} }
else if (mask != 0) else if (mask != 0)
{ {
ARM64Reg VB = fpr.R(inst.FB, RegType::LowerPair); ARM64Reg VB = fpr.R(inst.FB, RegType::LowerPair);
ARM64Reg WA = gpr.GetReg(); auto WA = gpr.GetScopedReg();
ARM64Reg WB = gpr.GetReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
m_float_emit.FMOV(WB, EncodeRegToSingle(VB));
if (LogicalImm imm = LogicalImm(mask, GPRSize::B32))
{ {
const u32 inverted_mask = ~mask; auto WB = gpr.GetScopedReg();
AND(WA, WA, LogicalImm(inverted_mask, GPRSize::B32));
AND(WB, WB, imm); LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
m_float_emit.FMOV(WB, EncodeRegToSingle(VB));
if (LogicalImm imm = LogicalImm(mask, GPRSize::B32))
{
const u32 inverted_mask = ~mask;
AND(WA, WA, LogicalImm(inverted_mask, GPRSize::B32));
AND(WB, WB, imm);
}
else
{
auto WC = gpr.GetScopedReg();
MOVI2R(WC, mask);
BIC(WA, WA, WC);
AND(WB, WB, WC);
}
ORR(WA, WA, WB);
} }
else
{
ARM64Reg WC = gpr.GetReg();
MOVI2R(WC, mask);
BIC(WA, WA, WC);
AND(WB, WB, WC);
gpr.Unlock(WC);
}
ORR(WA, WA, WB);
gpr.Unlock(WB);
if ((mask & (FPSCR_FEX | FPSCR_VX | FPSCR_ANY_X | FPSCR_ANY_E)) != 0) if ((mask & (FPSCR_FEX | FPSCR_VX | FPSCR_ANY_X | FPSCR_ANY_E)) != 0)
UpdateFPExceptionSummary(WA); UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr)); STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(WA);
} }
if (inst.FM & 1) if (inst.FM & 1)