Merge pull request #9396 from lioncash/arm
JitArm64_RegCache: Interface cleanup
This commit is contained in:
commit
344a74aa11
|
@ -144,8 +144,8 @@ void JitArm64::Shutdown()
|
|||
void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
|
||||
{
|
||||
FlushCarry();
|
||||
gpr.Flush(FlushMode::FLUSH_ALL, js.op);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL, js.op);
|
||||
gpr.Flush(FlushMode::All, js.op);
|
||||
fpr.Flush(FlushMode::All, js.op);
|
||||
|
||||
if (js.op->opinfo->flags & FL_ENDBLOCK)
|
||||
{
|
||||
|
@ -198,8 +198,8 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
|
|||
SwitchToFarCode();
|
||||
SetJumpTarget(handleException);
|
||||
|
||||
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
gpr.Flush(FlushMode::MaintainState);
|
||||
fpr.Flush(FlushMode::MaintainState);
|
||||
|
||||
WriteExceptionExit(js.compilerPC);
|
||||
|
||||
|
@ -212,8 +212,8 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
|
|||
void JitArm64::HLEFunction(u32 hook_index)
|
||||
{
|
||||
FlushCarry();
|
||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
|
||||
MOVI2R(W0, js.compilerPC);
|
||||
MOVI2R(W1, hook_index);
|
||||
|
@ -731,8 +731,8 @@ void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||
TST(W30, 23, 2);
|
||||
B(CC_EQ, done_here);
|
||||
|
||||
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
gpr.Flush(FlushMode::MaintainState);
|
||||
fpr.Flush(FlushMode::MaintainState);
|
||||
WriteExceptionExit(js.compilerPC, true);
|
||||
SwitchToNearCode();
|
||||
SetJumpTarget(exit);
|
||||
|
@ -763,8 +763,8 @@ void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||
B(CC_EQ, done_here);
|
||||
gpr.Unlock(WA);
|
||||
|
||||
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
gpr.Flush(FlushMode::MaintainState);
|
||||
fpr.Flush(FlushMode::MaintainState);
|
||||
WriteExceptionExit(js.compilerPC, true);
|
||||
SwitchToNearCode();
|
||||
SetJumpTarget(NoExtException);
|
||||
|
@ -787,8 +787,8 @@ void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||
SwitchToFarCode();
|
||||
SetJumpTarget(far_addr);
|
||||
|
||||
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
gpr.Flush(FlushMode::MaintainState);
|
||||
fpr.Flush(FlushMode::MaintainState);
|
||||
|
||||
LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
|
||||
ORR(WA, WA, 26, 0); // EXCEPTION_FPU_UNAVAILABLE
|
||||
|
@ -807,8 +807,8 @@ void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||
|
||||
if (SConfig::GetInstance().bJITRegisterCacheOff)
|
||||
{
|
||||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
FlushCarry();
|
||||
}
|
||||
|
||||
|
@ -833,8 +833,8 @@ void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||
|
||||
if (code_block.m_broken)
|
||||
{
|
||||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
WriteExit(nextPC);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ void JitArm64::sc(UGeckoInstruction inst)
|
|||
INSTRUCTION_START
|
||||
JITDISABLE(bJITBranchOff);
|
||||
|
||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
|
||||
ARM64Reg WA = gpr.GetReg();
|
||||
|
||||
|
@ -38,8 +38,8 @@ void JitArm64::rfi(UGeckoInstruction inst)
|
|||
INSTRUCTION_START
|
||||
JITDISABLE(bJITBranchOff);
|
||||
|
||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
|
||||
// See Interpreter rfi for details
|
||||
const u32 mask = 0x87C0FFFF;
|
||||
|
@ -96,8 +96,8 @@ void JitArm64::bx(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
|
||||
if (js.op->branchIsIdleLoop)
|
||||
{
|
||||
|
@ -154,8 +154,8 @@ void JitArm64::bcx(UGeckoInstruction inst)
|
|||
}
|
||||
gpr.Unlock(WA);
|
||||
|
||||
gpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE);
|
||||
fpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE);
|
||||
gpr.Flush(FlushMode::MaintainState);
|
||||
fpr.Flush(FlushMode::MaintainState);
|
||||
|
||||
if (js.op->branchIsIdleLoop)
|
||||
{
|
||||
|
@ -183,8 +183,8 @@ void JitArm64::bcx(UGeckoInstruction inst)
|
|||
|
||||
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
|
||||
{
|
||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
}
|
||||
|
@ -206,8 +206,8 @@ void JitArm64::bcctrx(UGeckoInstruction inst)
|
|||
// BO_2 == 1z1zz -> b always
|
||||
|
||||
// NPC = CTR & 0xfffffffc;
|
||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
|
||||
if (inst.LK_3)
|
||||
{
|
||||
|
@ -275,8 +275,8 @@ void JitArm64::bclrx(UGeckoInstruction inst)
|
|||
gpr.Unlock(WB);
|
||||
}
|
||||
|
||||
gpr.Flush(conditional ? FlushMode::FLUSH_MAINTAIN_STATE : FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(conditional ? FlushMode::FLUSH_MAINTAIN_STATE : FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(conditional ? FlushMode::MaintainState : FlushMode::All);
|
||||
fpr.Flush(conditional ? FlushMode::MaintainState : FlushMode::All);
|
||||
|
||||
if (js.op->branchIsIdleLoop)
|
||||
{
|
||||
|
@ -305,8 +305,8 @@ void JitArm64::bclrx(UGeckoInstruction inst)
|
|||
|
||||
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
|
||||
{
|
||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
|
|||
|
||||
if (packed)
|
||||
{
|
||||
RegType type = inputs_are_singles ? REG_REG_SINGLE : REG_REG;
|
||||
u8 size = inputs_are_singles ? 32 : 64;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = inputs_are_singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
const RegType type = inputs_are_singles ? RegType::Single : RegType::Register;
|
||||
const u8 size = inputs_are_singles ? 32 : 64;
|
||||
const auto reg_encoder = inputs_are_singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
|
||||
VA = reg_encoder(fpr.R(a, type));
|
||||
if (use_b)
|
||||
|
@ -71,10 +71,12 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
|
|||
}
|
||||
else
|
||||
{
|
||||
RegType type = (inputs_are_singles && single) ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR;
|
||||
RegType type_out = single ? (inputs_are_singles ? REG_DUP_SINGLE : REG_DUP) : REG_LOWER_PAIR;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) =
|
||||
(inputs_are_singles && single) ? EncodeRegToSingle : EncodeRegToDouble;
|
||||
const RegType type =
|
||||
(inputs_are_singles && single) ? RegType::LowerPairSingle : RegType::LowerPair;
|
||||
const RegType type_out =
|
||||
single ? (inputs_are_singles ? RegType::DuplicatedSingle : RegType::Duplicated) :
|
||||
RegType::LowerPair;
|
||||
const auto reg_encoder = (inputs_are_singles && single) ? EncodeRegToSingle : EncodeRegToDouble;
|
||||
|
||||
VA = reg_encoder(fpr.R(a, type));
|
||||
if (use_b)
|
||||
|
@ -125,8 +127,9 @@ void JitArm64::fp_logic(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITFloatingPointOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
u32 b = inst.FB, d = inst.FD;
|
||||
u32 op10 = inst.SUBOP10;
|
||||
const u32 b = inst.FB;
|
||||
const u32 d = inst.FD;
|
||||
const u32 op10 = inst.SUBOP10;
|
||||
|
||||
bool packed = inst.OPCD == 4;
|
||||
|
||||
|
@ -134,16 +137,16 @@ void JitArm64::fp_logic(UGeckoInstruction inst)
|
|||
if (op10 == 72 && b == d)
|
||||
return;
|
||||
|
||||
bool single = fpr.IsSingle(b, !packed);
|
||||
u8 size = single ? 32 : 64;
|
||||
const bool single = fpr.IsSingle(b, !packed);
|
||||
const u8 size = single ? 32 : 64;
|
||||
|
||||
if (packed)
|
||||
{
|
||||
RegType type = single ? REG_REG_SINGLE : REG_REG;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = single ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
const RegType type = single ? RegType::Single : RegType::Register;
|
||||
const auto reg_encoder = single ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
|
||||
ARM64Reg VB = reg_encoder(fpr.R(b, type));
|
||||
ARM64Reg VD = reg_encoder(fpr.RW(d, type));
|
||||
const ARM64Reg VB = reg_encoder(fpr.R(b, type));
|
||||
const ARM64Reg VD = reg_encoder(fpr.RW(d, type));
|
||||
|
||||
switch (op10)
|
||||
{
|
||||
|
@ -167,11 +170,11 @@ void JitArm64::fp_logic(UGeckoInstruction inst)
|
|||
}
|
||||
else
|
||||
{
|
||||
RegType type = single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = single ? EncodeRegToSingle : EncodeRegToDouble;
|
||||
const RegType type = single ? RegType::LowerPairSingle : RegType::LowerPair;
|
||||
const auto reg_encoder = single ? EncodeRegToSingle : EncodeRegToDouble;
|
||||
|
||||
ARM64Reg VB = fpr.R(b, type);
|
||||
ARM64Reg VD = fpr.RW(d, type);
|
||||
const ARM64Reg VB = fpr.R(b, type);
|
||||
const ARM64Reg VD = fpr.RW(d, type);
|
||||
|
||||
switch (op10)
|
||||
{
|
||||
|
@ -201,26 +204,29 @@ void JitArm64::fselx(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITFloatingPointOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD;
|
||||
const u32 a = inst.FA;
|
||||
const u32 b = inst.FB;
|
||||
const u32 c = inst.FC;
|
||||
const u32 d = inst.FD;
|
||||
|
||||
if (fpr.IsSingle(a, true))
|
||||
{
|
||||
ARM64Reg VA = fpr.R(a, REG_LOWER_PAIR_SINGLE);
|
||||
const ARM64Reg VA = fpr.R(a, RegType::LowerPairSingle);
|
||||
m_float_emit.FCMPE(EncodeRegToSingle(VA));
|
||||
}
|
||||
else
|
||||
{
|
||||
ARM64Reg VA = fpr.R(a, REG_LOWER_PAIR);
|
||||
const ARM64Reg VA = fpr.R(a, RegType::LowerPair);
|
||||
m_float_emit.FCMPE(EncodeRegToDouble(VA));
|
||||
}
|
||||
|
||||
bool single = fpr.IsSingle(b, true) && fpr.IsSingle(c, true);
|
||||
RegType type = single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = single ? EncodeRegToSingle : EncodeRegToDouble;
|
||||
const bool single = fpr.IsSingle(b, true) && fpr.IsSingle(c, true);
|
||||
const RegType type = single ? RegType::LowerPairSingle : RegType::LowerPair;
|
||||
const auto reg_encoder = single ? EncodeRegToSingle : EncodeRegToDouble;
|
||||
|
||||
ARM64Reg VB = fpr.R(b, type);
|
||||
ARM64Reg VC = fpr.R(c, type);
|
||||
ARM64Reg VD = fpr.RW(d, type);
|
||||
const ARM64Reg VB = fpr.R(b, type);
|
||||
const ARM64Reg VC = fpr.R(c, type);
|
||||
const ARM64Reg VD = fpr.RW(d, type);
|
||||
|
||||
m_float_emit.FCSEL(reg_encoder(VD), reg_encoder(VC), reg_encoder(VB), CC_GE);
|
||||
}
|
||||
|
@ -232,21 +238,22 @@ void JitArm64::frspx(UGeckoInstruction inst)
|
|||
FALLBACK_IF(inst.Rc);
|
||||
FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF);
|
||||
|
||||
u32 b = inst.FB, d = inst.FD;
|
||||
const u32 b = inst.FB;
|
||||
const u32 d = inst.FD;
|
||||
|
||||
if (fpr.IsSingle(b, true))
|
||||
{
|
||||
// Source is already in single precision, so no need to do anything but to copy to PSR1.
|
||||
ARM64Reg VB = fpr.R(b, REG_LOWER_PAIR_SINGLE);
|
||||
ARM64Reg VD = fpr.RW(d, REG_DUP_SINGLE);
|
||||
const ARM64Reg VB = fpr.R(b, RegType::LowerPairSingle);
|
||||
const ARM64Reg VD = fpr.RW(d, RegType::DuplicatedSingle);
|
||||
|
||||
if (b != d)
|
||||
m_float_emit.FMOV(EncodeRegToSingle(VD), EncodeRegToSingle(VB));
|
||||
}
|
||||
else
|
||||
{
|
||||
ARM64Reg VB = fpr.R(b, REG_LOWER_PAIR);
|
||||
ARM64Reg VD = fpr.RW(d, REG_DUP_SINGLE);
|
||||
const ARM64Reg VB = fpr.R(b, RegType::LowerPair);
|
||||
const ARM64Reg VD = fpr.RW(d, RegType::DuplicatedSingle);
|
||||
|
||||
m_float_emit.FCVT(32, 64, EncodeRegToDouble(VD), EncodeRegToDouble(VB));
|
||||
}
|
||||
|
@ -258,18 +265,19 @@ void JitArm64::fcmpX(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITFloatingPointOff);
|
||||
FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF);
|
||||
|
||||
u32 a = inst.FA, b = inst.FB;
|
||||
int crf = inst.CRFD;
|
||||
const u32 a = inst.FA;
|
||||
const u32 b = inst.FB;
|
||||
const int crf = inst.CRFD;
|
||||
|
||||
bool singles = fpr.IsSingle(a, true) && fpr.IsSingle(b, true);
|
||||
RegType type = singles ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToSingle : EncodeRegToDouble;
|
||||
const bool singles = fpr.IsSingle(a, true) && fpr.IsSingle(b, true);
|
||||
const RegType type = singles ? RegType::LowerPairSingle : RegType::LowerPair;
|
||||
const auto reg_encoder = singles ? EncodeRegToSingle : EncodeRegToDouble;
|
||||
|
||||
ARM64Reg VA = reg_encoder(fpr.R(a, type));
|
||||
ARM64Reg VB = reg_encoder(fpr.R(b, type));
|
||||
const ARM64Reg VA = reg_encoder(fpr.R(a, type));
|
||||
const ARM64Reg VB = reg_encoder(fpr.R(b, type));
|
||||
|
||||
gpr.BindCRToRegister(crf, false);
|
||||
ARM64Reg XA = gpr.CR(crf);
|
||||
const ARM64Reg XA = gpr.CR(crf);
|
||||
|
||||
FixupBranch pNaN, pLesser, pGreater;
|
||||
FixupBranch continue1, continue2, continue3;
|
||||
|
@ -320,14 +328,15 @@ void JitArm64::fctiwzx(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITFloatingPointOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
u32 b = inst.FB, d = inst.FD;
|
||||
const u32 b = inst.FB;
|
||||
const u32 d = inst.FD;
|
||||
|
||||
bool single = fpr.IsSingle(b, true);
|
||||
const bool single = fpr.IsSingle(b, true);
|
||||
|
||||
ARM64Reg VB = fpr.R(b, single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR);
|
||||
ARM64Reg VD = fpr.RW(d);
|
||||
const ARM64Reg VB = fpr.R(b, single ? RegType::LowerPairSingle : RegType::LowerPair);
|
||||
const ARM64Reg VD = fpr.RW(d);
|
||||
|
||||
ARM64Reg V0 = fpr.GetReg();
|
||||
const ARM64Reg V0 = fpr.GetReg();
|
||||
|
||||
// Generate 0xFFF8000000000000ULL
|
||||
m_float_emit.MOVI(64, EncodeRegToDouble(V0), 0xFFFF000000000000ULL);
|
||||
|
@ -339,7 +348,7 @@ void JitArm64::fctiwzx(UGeckoInstruction inst)
|
|||
}
|
||||
else
|
||||
{
|
||||
ARM64Reg V1 = gpr.GetReg();
|
||||
const ARM64Reg V1 = gpr.GetReg();
|
||||
|
||||
m_float_emit.FCVTS(V1, EncodeRegToDouble(VB), RoundingMode::Z);
|
||||
m_float_emit.FMOV(EncodeRegToSingle(VD), V1);
|
||||
|
|
|
@ -75,12 +75,13 @@ void JitArm64::lfXX(UGeckoInstruction inst)
|
|||
u32 imm_addr = 0;
|
||||
bool is_immediate = false;
|
||||
|
||||
RegType type = !!(flags & BackPatchInfo::FLAG_SIZE_F64) ? REG_LOWER_PAIR : REG_DUP_SINGLE;
|
||||
const RegType type =
|
||||
(flags & BackPatchInfo::FLAG_SIZE_F64) != 0 ? RegType::LowerPair : RegType::DuplicatedSingle;
|
||||
|
||||
gpr.Lock(W0, W30);
|
||||
fpr.Lock(Q0);
|
||||
|
||||
ARM64Reg VD = fpr.RW(inst.FD, type);
|
||||
const ARM64Reg VD = fpr.RW(inst.FD, type);
|
||||
ARM64Reg addr_reg = W0;
|
||||
|
||||
if (update)
|
||||
|
@ -244,9 +245,9 @@ void JitArm64::stfXX(UGeckoInstruction inst)
|
|||
gpr.Lock(W0, W1, W30);
|
||||
fpr.Lock(Q0);
|
||||
|
||||
bool single = (flags & BackPatchInfo::FLAG_SIZE_F32) && fpr.IsSingle(inst.FS, true);
|
||||
const bool single = (flags & BackPatchInfo::FLAG_SIZE_F32) && fpr.IsSingle(inst.FS, true);
|
||||
|
||||
ARM64Reg V0 = fpr.R(inst.FS, single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR);
|
||||
const ARM64Reg V0 = fpr.R(inst.FS, single ? RegType::LowerPairSingle : RegType::LowerPair);
|
||||
|
||||
if (single)
|
||||
{
|
||||
|
|
|
@ -31,16 +31,16 @@ void JitArm64::psq_l(UGeckoInstruction inst)
|
|||
// X2 is a temporary
|
||||
// Q0 is the return register
|
||||
// Q1 is a temporary
|
||||
bool update = inst.OPCD == 57;
|
||||
s32 offset = inst.SIMM_12;
|
||||
const bool update = inst.OPCD == 57;
|
||||
const s32 offset = inst.SIMM_12;
|
||||
|
||||
gpr.Lock(W0, W1, W2, W30);
|
||||
fpr.Lock(Q0, Q1);
|
||||
|
||||
ARM64Reg arm_addr = gpr.R(inst.RA);
|
||||
ARM64Reg scale_reg = W0;
|
||||
ARM64Reg addr_reg = W1;
|
||||
ARM64Reg type_reg = W2;
|
||||
const ARM64Reg arm_addr = gpr.R(inst.RA);
|
||||
constexpr ARM64Reg scale_reg = W0;
|
||||
constexpr ARM64Reg addr_reg = W1;
|
||||
constexpr ARM64Reg type_reg = W2;
|
||||
ARM64Reg VS;
|
||||
|
||||
if (inst.RA || update) // Always uses the register on update
|
||||
|
@ -57,13 +57,13 @@ void JitArm64::psq_l(UGeckoInstruction inst)
|
|||
|
||||
if (update)
|
||||
{
|
||||
gpr.BindToRegister(inst.RA, REG_REG);
|
||||
gpr.BindToRegister(inst.RA, true);
|
||||
MOV(arm_addr, addr_reg);
|
||||
}
|
||||
|
||||
if (js.assumeNoPairedQuantize)
|
||||
{
|
||||
VS = fpr.RW(inst.RS, REG_REG_SINGLE);
|
||||
VS = fpr.RW(inst.RS, RegType::Single);
|
||||
if (!inst.W)
|
||||
{
|
||||
ADD(EncodeRegTo64(addr_reg), EncodeRegTo64(addr_reg), MEM_REG);
|
||||
|
@ -85,7 +85,7 @@ void JitArm64::psq_l(UGeckoInstruction inst)
|
|||
LDR(X30, X30, ArithOption(EncodeRegTo64(type_reg), true));
|
||||
BLR(X30);
|
||||
|
||||
VS = fpr.RW(inst.RS, REG_REG_SINGLE);
|
||||
VS = fpr.RW(inst.RS, RegType::Single);
|
||||
m_float_emit.ORR(EncodeRegToDouble(VS), D0, D0);
|
||||
}
|
||||
|
||||
|
@ -113,20 +113,20 @@ void JitArm64::psq_st(UGeckoInstruction inst)
|
|||
// X1 is the address
|
||||
// Q0 is the store register
|
||||
|
||||
bool update = inst.OPCD == 61;
|
||||
s32 offset = inst.SIMM_12;
|
||||
const bool update = inst.OPCD == 61;
|
||||
const s32 offset = inst.SIMM_12;
|
||||
|
||||
gpr.Lock(W0, W1, W2, W30);
|
||||
fpr.Lock(Q0, Q1);
|
||||
|
||||
bool single = fpr.IsSingle(inst.RS);
|
||||
const bool single = fpr.IsSingle(inst.RS);
|
||||
|
||||
ARM64Reg arm_addr = gpr.R(inst.RA);
|
||||
ARM64Reg VS = fpr.R(inst.RS, single ? REG_REG_SINGLE : REG_REG);
|
||||
const ARM64Reg arm_addr = gpr.R(inst.RA);
|
||||
const ARM64Reg VS = fpr.R(inst.RS, single ? RegType::Single : RegType::Register);
|
||||
|
||||
ARM64Reg scale_reg = W0;
|
||||
ARM64Reg addr_reg = W1;
|
||||
ARM64Reg type_reg = W2;
|
||||
constexpr ARM64Reg scale_reg = W0;
|
||||
constexpr ARM64Reg addr_reg = W1;
|
||||
constexpr ARM64Reg type_reg = W2;
|
||||
|
||||
BitSet32 gprs_in_use = gpr.GetCallerSavedUsed();
|
||||
BitSet32 fprs_in_use = fpr.GetCallerSavedUsed();
|
||||
|
@ -149,7 +149,7 @@ void JitArm64::psq_st(UGeckoInstruction inst)
|
|||
|
||||
if (update)
|
||||
{
|
||||
gpr.BindToRegister(inst.RA, REG_REG);
|
||||
gpr.BindToRegister(inst.RA, true);
|
||||
MOV(arm_addr, addr_reg);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,16 +22,18 @@ void JitArm64::ps_mergeXX(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITPairedOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
u32 a = inst.FA, b = inst.FB, d = inst.FD;
|
||||
const u32 a = inst.FA;
|
||||
const u32 b = inst.FB;
|
||||
const u32 d = inst.FD;
|
||||
|
||||
bool singles = fpr.IsSingle(a) && fpr.IsSingle(b);
|
||||
RegType type = singles ? REG_REG_SINGLE : REG_REG;
|
||||
u8 size = singles ? 32 : 64;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
const bool singles = fpr.IsSingle(a) && fpr.IsSingle(b);
|
||||
const RegType type = singles ? RegType::Single : RegType::Register;
|
||||
const u8 size = singles ? 32 : 64;
|
||||
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
|
||||
ARM64Reg VA = fpr.R(a, type);
|
||||
ARM64Reg VB = fpr.R(b, type);
|
||||
ARM64Reg VD = fpr.RW(d, type);
|
||||
const ARM64Reg VA = fpr.R(a, type);
|
||||
const ARM64Reg VB = fpr.R(b, type);
|
||||
const ARM64Reg VD = fpr.RW(d, type);
|
||||
|
||||
switch (inst.SUBOP10)
|
||||
{
|
||||
|
@ -73,18 +75,20 @@ void JitArm64::ps_mulsX(UGeckoInstruction inst)
|
|||
FALLBACK_IF(inst.Rc);
|
||||
FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF);
|
||||
|
||||
u32 a = inst.FA, c = inst.FC, d = inst.FD;
|
||||
const u32 a = inst.FA;
|
||||
const u32 c = inst.FC;
|
||||
const u32 d = inst.FD;
|
||||
|
||||
bool upper = inst.SUBOP5 == 13;
|
||||
const bool upper = inst.SUBOP5 == 13;
|
||||
|
||||
bool singles = fpr.IsSingle(a) && fpr.IsSingle(c);
|
||||
RegType type = singles ? REG_REG_SINGLE : REG_REG;
|
||||
u8 size = singles ? 32 : 64;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
const bool singles = fpr.IsSingle(a) && fpr.IsSingle(c);
|
||||
const RegType type = singles ? RegType::Single : RegType::Register;
|
||||
const u8 size = singles ? 32 : 64;
|
||||
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
|
||||
ARM64Reg VA = fpr.R(a, type);
|
||||
ARM64Reg VC = fpr.R(c, type);
|
||||
ARM64Reg VD = fpr.RW(d, type);
|
||||
const ARM64Reg VA = fpr.R(a, type);
|
||||
const ARM64Reg VC = fpr.R(c, type);
|
||||
const ARM64Reg VD = fpr.RW(d, type);
|
||||
|
||||
m_float_emit.FMUL(size, reg_encoder(VD), reg_encoder(VA), reg_encoder(VC), upper ? 1 : 0);
|
||||
|
||||
|
@ -98,18 +102,21 @@ void JitArm64::ps_maddXX(UGeckoInstruction inst)
|
|||
FALLBACK_IF(inst.Rc);
|
||||
FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF);
|
||||
|
||||
u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD;
|
||||
u32 op5 = inst.SUBOP5;
|
||||
const u32 a = inst.FA;
|
||||
const u32 b = inst.FB;
|
||||
const u32 c = inst.FC;
|
||||
const u32 d = inst.FD;
|
||||
const u32 op5 = inst.SUBOP5;
|
||||
|
||||
bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
|
||||
RegType type = singles ? REG_REG_SINGLE : REG_REG;
|
||||
u8 size = singles ? 32 : 64;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
const bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
|
||||
const RegType type = singles ? RegType::Single : RegType::Register;
|
||||
const u8 size = singles ? 32 : 64;
|
||||
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
|
||||
ARM64Reg VA = reg_encoder(fpr.R(a, type));
|
||||
ARM64Reg VB = reg_encoder(fpr.R(b, type));
|
||||
ARM64Reg VC = reg_encoder(fpr.R(c, type));
|
||||
ARM64Reg VD = reg_encoder(fpr.RW(d, type));
|
||||
const ARM64Reg VA = reg_encoder(fpr.R(a, type));
|
||||
const ARM64Reg VB = reg_encoder(fpr.R(b, type));
|
||||
const ARM64Reg VC = reg_encoder(fpr.R(c, type));
|
||||
const ARM64Reg VD = reg_encoder(fpr.RW(d, type));
|
||||
ARM64Reg V0Q = INVALID_REG;
|
||||
ARM64Reg V0 = INVALID_REG;
|
||||
if (d != b && (d == a || d == c))
|
||||
|
@ -255,17 +262,20 @@ void JitArm64::ps_sel(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITPairedOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD;
|
||||
const u32 a = inst.FA;
|
||||
const u32 b = inst.FB;
|
||||
const u32 c = inst.FC;
|
||||
const u32 d = inst.FD;
|
||||
|
||||
bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
|
||||
RegType type = singles ? REG_REG_SINGLE : REG_REG;
|
||||
u8 size = singles ? 32 : 64;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
const bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
|
||||
const RegType type = singles ? RegType::Single : RegType::Register;
|
||||
const u8 size = singles ? 32 : 64;
|
||||
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
|
||||
ARM64Reg VA = reg_encoder(fpr.R(a, type));
|
||||
ARM64Reg VB = reg_encoder(fpr.R(b, type));
|
||||
ARM64Reg VC = reg_encoder(fpr.R(c, type));
|
||||
ARM64Reg VD = reg_encoder(fpr.RW(d, type));
|
||||
const ARM64Reg VA = reg_encoder(fpr.R(a, type));
|
||||
const ARM64Reg VB = reg_encoder(fpr.R(b, type));
|
||||
const ARM64Reg VC = reg_encoder(fpr.R(c, type));
|
||||
const ARM64Reg VD = reg_encoder(fpr.RW(d, type));
|
||||
|
||||
if (d != b && d != c)
|
||||
{
|
||||
|
@ -274,8 +284,8 @@ void JitArm64::ps_sel(UGeckoInstruction inst)
|
|||
}
|
||||
else
|
||||
{
|
||||
ARM64Reg V0Q = fpr.GetReg();
|
||||
ARM64Reg V0 = reg_encoder(V0Q);
|
||||
const ARM64Reg V0Q = fpr.GetReg();
|
||||
const ARM64Reg V0 = reg_encoder(V0Q);
|
||||
m_float_emit.FCMGE(size, V0, VA);
|
||||
m_float_emit.BSL(V0, VC, VB);
|
||||
m_float_emit.MOV(VD, V0);
|
||||
|
@ -290,20 +300,23 @@ void JitArm64::ps_sumX(UGeckoInstruction inst)
|
|||
FALLBACK_IF(inst.Rc);
|
||||
FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF);
|
||||
|
||||
u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD;
|
||||
const u32 a = inst.FA;
|
||||
const u32 b = inst.FB;
|
||||
const u32 c = inst.FC;
|
||||
const u32 d = inst.FD;
|
||||
|
||||
bool upper = inst.SUBOP5 == 11;
|
||||
const bool upper = inst.SUBOP5 == 11;
|
||||
|
||||
bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
|
||||
RegType type = singles ? REG_REG_SINGLE : REG_REG;
|
||||
u8 size = singles ? 32 : 64;
|
||||
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
const bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
|
||||
const RegType type = singles ? RegType::Single : RegType::Register;
|
||||
const u8 size = singles ? 32 : 64;
|
||||
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;
|
||||
|
||||
ARM64Reg VA = fpr.R(a, type);
|
||||
ARM64Reg VB = fpr.R(b, type);
|
||||
ARM64Reg VC = fpr.R(c, type);
|
||||
ARM64Reg VD = fpr.RW(d, type);
|
||||
ARM64Reg V0 = fpr.GetReg();
|
||||
const ARM64Reg VA = fpr.R(a, type);
|
||||
const ARM64Reg VB = fpr.R(b, type);
|
||||
const ARM64Reg VC = fpr.R(c, type);
|
||||
const ARM64Reg VD = fpr.RW(d, type);
|
||||
const ARM64Reg V0 = fpr.GetReg();
|
||||
|
||||
m_float_emit.DUP(size, reg_encoder(V0), reg_encoder(upper ? VA : VB), upper ? 0 : 1);
|
||||
if (d != c)
|
||||
|
|
|
@ -27,7 +27,7 @@ void Arm64RegCache::Init(ARM64XEmitter* emitter)
|
|||
ARM64Reg Arm64RegCache::GetReg()
|
||||
{
|
||||
// If we have no registers left, dump the most stale register first
|
||||
if (!GetUnlockedRegisterCount())
|
||||
if (GetUnlockedRegisterCount() == 0)
|
||||
FlushMostStaleRegister();
|
||||
|
||||
for (auto& it : m_host_registers)
|
||||
|
@ -45,12 +45,14 @@ ARM64Reg Arm64RegCache::GetReg()
|
|||
return INVALID_REG;
|
||||
}
|
||||
|
||||
u32 Arm64RegCache::GetUnlockedRegisterCount()
|
||||
u32 Arm64RegCache::GetUnlockedRegisterCount() const
|
||||
{
|
||||
u32 unlocked_registers = 0;
|
||||
for (auto& it : m_host_registers)
|
||||
for (const auto& it : m_host_registers)
|
||||
{
|
||||
if (!it.IsLocked())
|
||||
++unlocked_registers;
|
||||
}
|
||||
return unlocked_registers;
|
||||
}
|
||||
|
||||
|
@ -81,7 +83,7 @@ void Arm64RegCache::FlushMostStaleRegister()
|
|||
const u32 last_used = reg.GetLastUsed();
|
||||
|
||||
if (last_used > most_stale_amount &&
|
||||
(reg.GetType() != REG_NOTLOADED && reg.GetType() != REG_IMM))
|
||||
(reg.GetType() != RegType::NotLoaded && reg.GetType() != RegType::Immediate))
|
||||
{
|
||||
most_stale_preg = i;
|
||||
most_stale_amount = last_used;
|
||||
|
@ -105,7 +107,7 @@ void Arm64GPRCache::Start(PPCAnalyst::BlockRegStats& stats)
|
|||
{
|
||||
}
|
||||
|
||||
bool Arm64GPRCache::IsCalleeSaved(ARM64Reg reg)
|
||||
bool Arm64GPRCache::IsCalleeSaved(ARM64Reg reg) const
|
||||
{
|
||||
static constexpr std::array<ARM64Reg, 11> callee_regs{{
|
||||
X28,
|
||||
|
@ -158,7 +160,7 @@ void Arm64GPRCache::FlushRegister(size_t index, bool maintain_state)
|
|||
OpArg& reg = guest_reg.reg;
|
||||
size_t bitsize = guest_reg.bitsize;
|
||||
|
||||
if (reg.GetType() == REG_REG)
|
||||
if (reg.GetType() == RegType::Register)
|
||||
{
|
||||
ARM64Reg host_reg = reg.GetReg();
|
||||
if (reg.IsDirty())
|
||||
|
@ -170,7 +172,7 @@ void Arm64GPRCache::FlushRegister(size_t index, bool maintain_state)
|
|||
reg.Flush();
|
||||
}
|
||||
}
|
||||
else if (reg.GetType() == REG_IMM)
|
||||
else if (reg.GetType() == RegType::Immediate)
|
||||
{
|
||||
if (!reg.GetImm())
|
||||
{
|
||||
|
@ -202,8 +204,8 @@ void Arm64GPRCache::FlushRegisters(BitSet32 regs, bool maintain_state)
|
|||
// We've got two guest registers in a row to store
|
||||
OpArg& reg1 = m_guest_registers[i];
|
||||
OpArg& reg2 = m_guest_registers[i + 1];
|
||||
if (reg1.IsDirty() && reg2.IsDirty() && reg1.GetType() == REG_REG &&
|
||||
reg2.GetType() == REG_REG)
|
||||
if (reg1.IsDirty() && reg2.IsDirty() && reg1.GetType() == RegType::Register &&
|
||||
reg2.GetType() == RegType::Register)
|
||||
{
|
||||
size_t ppc_offset = GetGuestByIndex(i).ppc_offset;
|
||||
ARM64Reg RX1 = R(GetGuestByIndex(i));
|
||||
|
@ -239,8 +241,8 @@ void Arm64GPRCache::FlushCRRegisters(BitSet32 regs, bool maintain_state)
|
|||
|
||||
void Arm64GPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op)
|
||||
{
|
||||
FlushRegisters(BitSet32(~0U), mode == FLUSH_MAINTAIN_STATE);
|
||||
FlushCRRegisters(BitSet32(~0U), mode == FLUSH_MAINTAIN_STATE);
|
||||
FlushRegisters(BitSet32(~0U), mode == FlushMode::MaintainState);
|
||||
FlushCRRegisters(BitSet32(~0U), mode == FlushMode::MaintainState);
|
||||
}
|
||||
|
||||
ARM64Reg Arm64GPRCache::R(const GuestRegInfo& guest_reg)
|
||||
|
@ -253,10 +255,9 @@ ARM64Reg Arm64GPRCache::R(const GuestRegInfo& guest_reg)
|
|||
|
||||
switch (reg.GetType())
|
||||
{
|
||||
case REG_REG: // already in a reg
|
||||
case RegType::Register: // already in a reg
|
||||
return reg.GetReg();
|
||||
break;
|
||||
case REG_IMM: // Is an immediate
|
||||
case RegType::Immediate: // Is an immediate
|
||||
{
|
||||
ARM64Reg host_reg = bitsize != 64 ? GetReg() : EncodeRegTo64(GetReg());
|
||||
m_emit->MOVI2R(host_reg, reg.GetImm());
|
||||
|
@ -265,7 +266,7 @@ ARM64Reg Arm64GPRCache::R(const GuestRegInfo& guest_reg)
|
|||
return host_reg;
|
||||
}
|
||||
break;
|
||||
case REG_NOTLOADED: // Register isn't loaded at /all/
|
||||
case RegType::NotLoaded: // Register isn't loaded at /all/
|
||||
{
|
||||
// This is a bit annoying. We try to keep these preloaded as much as possible
|
||||
// This can also happen on cases where PPCAnalyst isn't feeing us proper register usage
|
||||
|
@ -288,7 +289,7 @@ ARM64Reg Arm64GPRCache::R(const GuestRegInfo& guest_reg)
|
|||
void Arm64GPRCache::SetImmediate(const GuestRegInfo& guest_reg, u32 imm)
|
||||
{
|
||||
OpArg& reg = guest_reg.reg;
|
||||
if (reg.GetType() == REG_REG)
|
||||
if (reg.GetType() == RegType::Register)
|
||||
UnlockRegister(DecodeReg(reg.GetReg()));
|
||||
reg.LoadToImm(imm);
|
||||
}
|
||||
|
@ -296,14 +297,14 @@ void Arm64GPRCache::SetImmediate(const GuestRegInfo& guest_reg, u32 imm)
|
|||
void Arm64GPRCache::BindToRegister(const GuestRegInfo& guest_reg, bool do_load)
|
||||
{
|
||||
OpArg& reg = guest_reg.reg;
|
||||
size_t bitsize = guest_reg.bitsize;
|
||||
const size_t bitsize = guest_reg.bitsize;
|
||||
|
||||
reg.ResetLastUsed();
|
||||
|
||||
reg.SetDirty(true);
|
||||
if (reg.GetType() == REG_NOTLOADED)
|
||||
if (reg.GetType() == RegType::NotLoaded)
|
||||
{
|
||||
ARM64Reg host_reg = bitsize != 64 ? GetReg() : EncodeRegTo64(GetReg());
|
||||
const ARM64Reg host_reg = bitsize != 64 ? GetReg() : EncodeRegTo64(GetReg());
|
||||
reg.Load(host_reg);
|
||||
if (do_load)
|
||||
m_emit->LDR(INDEX_UNSIGNED, host_reg, PPC_REG, u32(guest_reg.ppc_offset));
|
||||
|
@ -351,12 +352,14 @@ void Arm64GPRCache::GetAllocationOrder()
|
|||
m_host_registers.push_back(HostReg(reg));
|
||||
}
|
||||
|
||||
BitSet32 Arm64GPRCache::GetCallerSavedUsed()
|
||||
BitSet32 Arm64GPRCache::GetCallerSavedUsed() const
|
||||
{
|
||||
BitSet32 registers(0);
|
||||
for (auto& it : m_host_registers)
|
||||
for (const auto& it : m_host_registers)
|
||||
{
|
||||
if (it.IsLocked() && !IsCalleeSaved(it.GetReg()))
|
||||
registers[DecodeReg(it.GetReg())] = 1;
|
||||
registers[DecodeReg(it.GetReg())] = true;
|
||||
}
|
||||
return registers;
|
||||
}
|
||||
|
||||
|
@ -366,7 +369,7 @@ void Arm64GPRCache::FlushByHost(ARM64Reg host_reg)
|
|||
for (size_t i = 0; i < m_guest_registers.size(); ++i)
|
||||
{
|
||||
const OpArg& reg = m_guest_registers[i];
|
||||
if (reg.GetType() == REG_REG && DecodeReg(reg.GetReg()) == host_reg)
|
||||
if (reg.GetType() == RegType::Register && DecodeReg(reg.GetReg()) == host_reg)
|
||||
{
|
||||
FlushRegister(i, false);
|
||||
return;
|
||||
|
@ -387,11 +390,11 @@ void Arm64FPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op)
|
|||
{
|
||||
const RegType reg_type = m_guest_registers[i].GetType();
|
||||
|
||||
if (reg_type != REG_NOTLOADED && reg_type != REG_IMM)
|
||||
if (reg_type != RegType::NotLoaded && reg_type != RegType::Immediate)
|
||||
{
|
||||
// XXX: Determine if we can keep a register in the lower 64bits
|
||||
// Which will allow it to be callee saved.
|
||||
FlushRegister(i, mode == FLUSH_MAINTAIN_STATE);
|
||||
FlushRegister(i, mode == FlushMode::MaintainState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -405,90 +408,90 @@ ARM64Reg Arm64FPRCache::R(size_t preg, RegType type)
|
|||
|
||||
switch (reg.GetType())
|
||||
{
|
||||
case REG_REG_SINGLE:
|
||||
case RegType::Single:
|
||||
{
|
||||
// We're asked for singles, so just return the register.
|
||||
if (type == REG_REG_SINGLE || type == REG_LOWER_PAIR_SINGLE)
|
||||
if (type == RegType::Single || type == RegType::LowerPairSingle)
|
||||
return host_reg;
|
||||
|
||||
// Else convert this register back to doubles.
|
||||
m_float_emit->FCVTL(64, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg));
|
||||
reg.Load(host_reg, REG_REG);
|
||||
reg.Load(host_reg, RegType::Register);
|
||||
[[fallthrough]];
|
||||
}
|
||||
case REG_REG: // already in a reg
|
||||
case RegType::Register: // already in a reg
|
||||
{
|
||||
return host_reg;
|
||||
}
|
||||
case REG_LOWER_PAIR_SINGLE:
|
||||
case RegType::LowerPairSingle:
|
||||
{
|
||||
// We're asked for the lower single, so just return the register.
|
||||
if (type == REG_LOWER_PAIR_SINGLE)
|
||||
if (type == RegType::LowerPairSingle)
|
||||
return host_reg;
|
||||
|
||||
// Else convert this register back to a double.
|
||||
m_float_emit->FCVT(64, 32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg));
|
||||
reg.Load(host_reg, REG_LOWER_PAIR);
|
||||
reg.Load(host_reg, RegType::LowerPair);
|
||||
[[fallthrough]];
|
||||
}
|
||||
case REG_LOWER_PAIR:
|
||||
case RegType::LowerPair:
|
||||
{
|
||||
if (type == REG_REG)
|
||||
if (type == RegType::Register)
|
||||
{
|
||||
// Load the high 64bits from the file and insert them in to the high 64bits of the host
|
||||
// register
|
||||
ARM64Reg tmp_reg = GetReg();
|
||||
const ARM64Reg tmp_reg = GetReg();
|
||||
m_float_emit->LDR(64, INDEX_UNSIGNED, tmp_reg, PPC_REG, u32(PPCSTATE_OFF(ps[preg].ps1)));
|
||||
m_float_emit->INS(64, host_reg, 1, tmp_reg, 0);
|
||||
UnlockRegister(tmp_reg);
|
||||
|
||||
// Change it over to a full 128bit register
|
||||
reg.Load(host_reg, REG_REG);
|
||||
reg.Load(host_reg, RegType::Register);
|
||||
}
|
||||
return host_reg;
|
||||
}
|
||||
case REG_DUP_SINGLE:
|
||||
case RegType::DuplicatedSingle:
|
||||
{
|
||||
if (type == REG_LOWER_PAIR_SINGLE)
|
||||
if (type == RegType::LowerPairSingle)
|
||||
return host_reg;
|
||||
|
||||
if (type == REG_REG_SINGLE)
|
||||
if (type == RegType::Single)
|
||||
{
|
||||
// Duplicate to the top and change over
|
||||
m_float_emit->INS(32, host_reg, 1, host_reg, 0);
|
||||
reg.Load(host_reg, REG_REG_SINGLE);
|
||||
reg.Load(host_reg, RegType::Single);
|
||||
return host_reg;
|
||||
}
|
||||
|
||||
m_float_emit->FCVT(64, 32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg));
|
||||
reg.Load(host_reg, REG_DUP);
|
||||
reg.Load(host_reg, RegType::Duplicated);
|
||||
[[fallthrough]];
|
||||
}
|
||||
case REG_DUP:
|
||||
case RegType::Duplicated:
|
||||
{
|
||||
if (type == REG_REG)
|
||||
if (type == RegType::Register)
|
||||
{
|
||||
// We are requesting a full 128bit register
|
||||
// but we are only available in the lower 64bits
|
||||
// Duplicate to the top and change over
|
||||
m_float_emit->INS(64, host_reg, 1, host_reg, 0);
|
||||
reg.Load(host_reg, REG_REG);
|
||||
reg.Load(host_reg, RegType::Register);
|
||||
}
|
||||
return host_reg;
|
||||
}
|
||||
case REG_NOTLOADED: // Register isn't loaded at /all/
|
||||
case RegType::NotLoaded: // Register isn't loaded at /all/
|
||||
{
|
||||
host_reg = GetReg();
|
||||
u32 load_size;
|
||||
if (type == REG_REG)
|
||||
if (type == RegType::Register)
|
||||
{
|
||||
load_size = 128;
|
||||
reg.Load(host_reg, REG_REG);
|
||||
reg.Load(host_reg, RegType::Register);
|
||||
}
|
||||
else
|
||||
{
|
||||
load_size = 64;
|
||||
reg.Load(host_reg, REG_LOWER_PAIR);
|
||||
reg.Load(host_reg, RegType::LowerPair);
|
||||
}
|
||||
reg.SetDirty(false);
|
||||
m_float_emit->LDR(load_size, INDEX_UNSIGNED, host_reg, PPC_REG,
|
||||
|
@ -515,14 +518,14 @@ ARM64Reg Arm64FPRCache::RW(size_t preg, RegType type)
|
|||
reg.SetDirty(true);
|
||||
|
||||
// If not loaded at all, just alloc a new one.
|
||||
if (reg.GetType() == REG_NOTLOADED)
|
||||
if (reg.GetType() == RegType::NotLoaded)
|
||||
{
|
||||
reg.Load(GetReg(), type);
|
||||
return reg.GetReg();
|
||||
}
|
||||
|
||||
// Only the lower value will be overwritten, so we must be extra careful to store PSR1 if dirty.
|
||||
if ((type == REG_LOWER_PAIR || type == REG_LOWER_PAIR_SINGLE) && was_dirty)
|
||||
if ((type == RegType::LowerPair || type == RegType::LowerPairSingle) && was_dirty)
|
||||
{
|
||||
// We must *not* change host_reg as this register might still be in use. So it's fine to
|
||||
// store this register, but it's *not* fine to convert it to double. So for double convertion,
|
||||
|
@ -532,21 +535,21 @@ ARM64Reg Arm64FPRCache::RW(size_t preg, RegType type)
|
|||
|
||||
switch (reg.GetType())
|
||||
{
|
||||
case REG_REG_SINGLE:
|
||||
case RegType::Single:
|
||||
flush_reg = GetReg();
|
||||
m_float_emit->FCVTL(64, EncodeRegToDouble(flush_reg), EncodeRegToDouble(host_reg));
|
||||
[[fallthrough]];
|
||||
case REG_REG:
|
||||
case RegType::Register:
|
||||
// We are doing a full 128bit store because it takes 2 cycles on a Cortex-A57 to do a 128bit
|
||||
// store.
|
||||
// It would take longer to do an insert to a temporary and a 64bit store than to just do this.
|
||||
m_float_emit->STR(128, INDEX_UNSIGNED, flush_reg, PPC_REG, u32(PPCSTATE_OFF(ps[preg].ps0)));
|
||||
break;
|
||||
case REG_DUP_SINGLE:
|
||||
case RegType::DuplicatedSingle:
|
||||
flush_reg = GetReg();
|
||||
m_float_emit->FCVT(64, 32, EncodeRegToDouble(flush_reg), EncodeRegToDouble(host_reg));
|
||||
[[fallthrough]];
|
||||
case REG_DUP:
|
||||
case RegType::Duplicated:
|
||||
// Store PSR1 (which is equal to PSR0) in memory.
|
||||
m_float_emit->STR(64, INDEX_UNSIGNED, flush_reg, PPC_REG, u32(PPCSTATE_OFF(ps[preg].ps1)));
|
||||
break;
|
||||
|
@ -614,7 +617,8 @@ void Arm64FPRCache::FlushByHost(ARM64Reg host_reg)
|
|||
const OpArg& reg = m_guest_registers[i];
|
||||
const RegType reg_type = reg.GetType();
|
||||
|
||||
if ((reg_type != REG_NOTLOADED && reg_type != REG_IMM) && reg.GetReg() == host_reg)
|
||||
if ((reg_type != RegType::NotLoaded && reg_type != RegType::Immediate) &&
|
||||
reg.GetReg() == host_reg)
|
||||
{
|
||||
FlushRegister(i, false);
|
||||
return;
|
||||
|
@ -622,7 +626,7 @@ void Arm64FPRCache::FlushByHost(ARM64Reg host_reg)
|
|||
}
|
||||
}
|
||||
|
||||
bool Arm64FPRCache::IsCalleeSaved(ARM64Reg reg)
|
||||
bool Arm64FPRCache::IsCalleeSaved(ARM64Reg reg) const
|
||||
{
|
||||
static constexpr std::array<ARM64Reg, 9> callee_regs{{
|
||||
Q8,
|
||||
|
@ -642,32 +646,32 @@ bool Arm64FPRCache::IsCalleeSaved(ARM64Reg reg)
|
|||
void Arm64FPRCache::FlushRegister(size_t preg, bool maintain_state)
|
||||
{
|
||||
OpArg& reg = m_guest_registers[preg];
|
||||
ARM64Reg host_reg = reg.GetReg();
|
||||
const ARM64Reg host_reg = reg.GetReg();
|
||||
const bool dirty = reg.IsDirty();
|
||||
RegType type = reg.GetType();
|
||||
bool dirty = reg.IsDirty();
|
||||
|
||||
// If we're in single mode, just convert it back to a double.
|
||||
if (type == REG_REG_SINGLE)
|
||||
if (type == RegType::Single)
|
||||
{
|
||||
if (dirty)
|
||||
m_float_emit->FCVTL(64, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg));
|
||||
type = REG_REG;
|
||||
type = RegType::Register;
|
||||
}
|
||||
if (type == REG_DUP_SINGLE || type == REG_LOWER_PAIR_SINGLE)
|
||||
if (type == RegType::DuplicatedSingle || type == RegType::LowerPairSingle)
|
||||
{
|
||||
if (dirty)
|
||||
m_float_emit->FCVT(64, 32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg));
|
||||
|
||||
if (type == REG_DUP_SINGLE)
|
||||
type = REG_DUP;
|
||||
if (type == RegType::DuplicatedSingle)
|
||||
type = RegType::Duplicated;
|
||||
else
|
||||
type = REG_LOWER_PAIR;
|
||||
type = RegType::LowerPair;
|
||||
}
|
||||
|
||||
if (type == REG_REG || type == REG_LOWER_PAIR)
|
||||
if (type == RegType::Register || type == RegType::LowerPair)
|
||||
{
|
||||
u32 store_size;
|
||||
if (type == REG_REG)
|
||||
if (type == RegType::Register)
|
||||
store_size = 128;
|
||||
else
|
||||
store_size = 64;
|
||||
|
@ -684,7 +688,7 @@ void Arm64FPRCache::FlushRegister(size_t preg, bool maintain_state)
|
|||
reg.Flush();
|
||||
}
|
||||
}
|
||||
else if (type == REG_DUP)
|
||||
else if (type == RegType::Duplicated)
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
|
@ -710,20 +714,22 @@ void Arm64FPRCache::FlushRegisters(BitSet32 regs, bool maintain_state)
|
|||
FlushRegister(j, maintain_state);
|
||||
}
|
||||
|
||||
BitSet32 Arm64FPRCache::GetCallerSavedUsed()
|
||||
BitSet32 Arm64FPRCache::GetCallerSavedUsed() const
|
||||
{
|
||||
BitSet32 registers(0);
|
||||
for (auto& it : m_host_registers)
|
||||
for (const auto& it : m_host_registers)
|
||||
{
|
||||
if (it.IsLocked())
|
||||
registers[it.GetReg() - Q0] = 1;
|
||||
registers[it.GetReg() - Q0] = true;
|
||||
}
|
||||
return registers;
|
||||
}
|
||||
|
||||
bool Arm64FPRCache::IsSingle(size_t preg, bool lower_only)
|
||||
bool Arm64FPRCache::IsSingle(size_t preg, bool lower_only) const
|
||||
{
|
||||
RegType type = m_guest_registers[preg].GetType();
|
||||
return type == REG_REG_SINGLE || type == REG_DUP_SINGLE ||
|
||||
(lower_only && type == REG_LOWER_PAIR_SINGLE);
|
||||
const RegType type = m_guest_registers[preg].GetType();
|
||||
return type == RegType::Single || type == RegType::DuplicatedSingle ||
|
||||
(lower_only && type == RegType::LowerPairSingle);
|
||||
}
|
||||
|
||||
void Arm64FPRCache::FixSinglePrecision(size_t preg)
|
||||
|
@ -732,13 +738,13 @@ void Arm64FPRCache::FixSinglePrecision(size_t preg)
|
|||
ARM64Reg host_reg = reg.GetReg();
|
||||
switch (reg.GetType())
|
||||
{
|
||||
case REG_DUP: // only PS0 needs to be converted
|
||||
case RegType::Duplicated: // only PS0 needs to be converted
|
||||
m_float_emit->FCVT(32, 64, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg));
|
||||
reg.Load(host_reg, REG_DUP_SINGLE);
|
||||
reg.Load(host_reg, RegType::DuplicatedSingle);
|
||||
break;
|
||||
case REG_REG: // PS0 and PS1 needs to be converted
|
||||
case RegType::Register: // PS0 and PS1 needs to be converted
|
||||
m_float_emit->FCVTN(32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg));
|
||||
reg.Load(host_reg, REG_REG_SINGLE);
|
||||
reg.Load(host_reg, RegType::Single);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -15,10 +15,13 @@
|
|||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
// Dedicated host registers
|
||||
static const Arm64Gen::ARM64Reg MEM_REG = Arm64Gen::X28; // memory base register
|
||||
static const Arm64Gen::ARM64Reg PPC_REG = Arm64Gen::X29; // ppcState pointer
|
||||
static const Arm64Gen::ARM64Reg DISPATCHER_PC =
|
||||
Arm64Gen::W26; // PC register when calling the dispatcher
|
||||
|
||||
// memory base register
|
||||
constexpr Arm64Gen::ARM64Reg MEM_REG = Arm64Gen::X28;
|
||||
// ppcState pointer
|
||||
constexpr Arm64Gen::ARM64Reg PPC_REG = Arm64Gen::X29;
|
||||
// PC register when calling the dispatcher
|
||||
constexpr Arm64Gen::ARM64Reg DISPATCHER_PC = Arm64Gen::W26;
|
||||
|
||||
#define PPCSTATE_OFF(elem) (offsetof(PowerPC::PowerPCState, elem))
|
||||
|
||||
|
@ -29,43 +32,44 @@ static_assert((PPCSTATE_OFF(ps[0].ps0) % 8) == 0,
|
|||
static_assert(PPCSTATE_OFF(xer_ca) < 4096, "STRB can't store xer_ca!");
|
||||
static_assert(PPCSTATE_OFF(xer_so_ov) < 4096, "STRB can't store xer_so_ov!");
|
||||
|
||||
enum RegType
|
||||
enum class RegType
|
||||
{
|
||||
REG_NOTLOADED = 0,
|
||||
REG_REG, // Reg type is register
|
||||
REG_IMM, // Reg is really a IMM
|
||||
REG_LOWER_PAIR, // Only the lower pair of a paired register
|
||||
REG_DUP, // The lower reg is the same as the upper one (physical upper doesn't actually have the
|
||||
// duplicated value)
|
||||
REG_REG_SINGLE, // Both registers are loaded as single
|
||||
REG_LOWER_PAIR_SINGLE, // Only the lower pair of a paired register, as single
|
||||
REG_DUP_SINGLE, // The lower one contains both registers, as single
|
||||
NotLoaded,
|
||||
Register, // Reg type is register
|
||||
Immediate, // Reg is really a IMM
|
||||
LowerPair, // Only the lower pair of a paired register
|
||||
Duplicated, // The lower reg is the same as the upper one (physical upper doesn't actually have
|
||||
// the duplicated value)
|
||||
Single, // Both registers are loaded as single
|
||||
LowerPairSingle, // Only the lower pair of a paired register, as single
|
||||
DuplicatedSingle, // The lower one contains both registers, as single
|
||||
};
|
||||
|
||||
enum FlushMode
|
||||
enum class FlushMode
|
||||
{
|
||||
// Flushes all registers, no exceptions
|
||||
FLUSH_ALL = 0,
|
||||
All,
|
||||
// Flushes registers in a conditional branch
|
||||
// Doesn't wipe the state of the registers from the cache
|
||||
FLUSH_MAINTAIN_STATE,
|
||||
MaintainState,
|
||||
};
|
||||
|
||||
class OpArg
|
||||
{
|
||||
public:
|
||||
OpArg() : m_type(REG_NOTLOADED), m_reg(Arm64Gen::INVALID_REG), m_value(0), m_last_used(0) {}
|
||||
OpArg() = default;
|
||||
|
||||
RegType GetType() const { return m_type; }
|
||||
Arm64Gen::ARM64Reg GetReg() const { return m_reg; }
|
||||
u32 GetImm() const { return m_value; }
|
||||
void Load(Arm64Gen::ARM64Reg reg, RegType type = REG_REG)
|
||||
void Load(Arm64Gen::ARM64Reg reg, RegType type = RegType::Register)
|
||||
{
|
||||
m_type = type;
|
||||
m_reg = reg;
|
||||
}
|
||||
void LoadToImm(u32 imm)
|
||||
{
|
||||
m_type = REG_IMM;
|
||||
m_type = RegType::Immediate;
|
||||
m_value = imm;
|
||||
|
||||
m_reg = Arm64Gen::INVALID_REG;
|
||||
|
@ -73,7 +77,7 @@ public:
|
|||
void Flush()
|
||||
{
|
||||
// Invalidate any previous information
|
||||
m_type = REG_NOTLOADED;
|
||||
m_type = RegType::NotLoaded;
|
||||
m_reg = Arm64Gen::INVALID_REG;
|
||||
|
||||
// Arbitrarily large value that won't roll over on a lot of increments
|
||||
|
@ -88,40 +92,41 @@ public:
|
|||
|
||||
private:
|
||||
// For REG_REG
|
||||
RegType m_type; // store type
|
||||
Arm64Gen::ARM64Reg m_reg; // host register we are in
|
||||
RegType m_type = RegType::NotLoaded; // store type
|
||||
Arm64Gen::ARM64Reg m_reg = Arm64Gen::INVALID_REG; // host register we are in
|
||||
|
||||
// For REG_IMM
|
||||
u32 m_value; // IMM value
|
||||
u32 m_value = 0; // IMM value
|
||||
|
||||
u32 m_last_used;
|
||||
u32 m_last_used = 0;
|
||||
|
||||
bool m_dirty;
|
||||
bool m_dirty = false;
|
||||
};
|
||||
|
||||
class HostReg
|
||||
{
|
||||
public:
|
||||
HostReg() : m_reg(Arm64Gen::INVALID_REG), m_locked(false) {}
|
||||
HostReg(Arm64Gen::ARM64Reg reg) : m_reg(reg), m_locked(false) {}
|
||||
HostReg() = default;
|
||||
HostReg(Arm64Gen::ARM64Reg reg) : m_reg(reg) {}
|
||||
|
||||
bool IsLocked() const { return m_locked; }
|
||||
void Lock() { m_locked = true; }
|
||||
void Unlock() { m_locked = false; }
|
||||
Arm64Gen::ARM64Reg GetReg() const { return m_reg; }
|
||||
bool operator==(const Arm64Gen::ARM64Reg& reg) { return reg == m_reg; }
|
||||
|
||||
bool operator==(Arm64Gen::ARM64Reg reg) const { return reg == m_reg; }
|
||||
bool operator!=(Arm64Gen::ARM64Reg reg) const { return !operator==(reg); }
|
||||
|
||||
private:
|
||||
Arm64Gen::ARM64Reg m_reg;
|
||||
bool m_locked;
|
||||
Arm64Gen::ARM64Reg m_reg = Arm64Gen::INVALID_REG;
|
||||
bool m_locked = false;
|
||||
};
|
||||
|
||||
class Arm64RegCache
|
||||
{
|
||||
public:
|
||||
explicit Arm64RegCache(size_t guest_reg_count)
|
||||
: m_emit(nullptr), m_float_emit(nullptr), m_guest_registers(guest_reg_count),
|
||||
m_reg_stats(nullptr){};
|
||||
virtual ~Arm64RegCache(){};
|
||||
explicit Arm64RegCache(size_t guest_reg_count) : m_guest_registers(guest_reg_count) {}
|
||||
virtual ~Arm64RegCache() = default;
|
||||
|
||||
void Init(Arm64Gen::ARM64XEmitter* emitter);
|
||||
|
||||
|
@ -129,7 +134,7 @@ public:
|
|||
// Flushes the register cache in different ways depending on the mode
|
||||
virtual void Flush(FlushMode mode, PPCAnalyst::CodeOp* op) = 0;
|
||||
|
||||
virtual BitSet32 GetCallerSavedUsed() = 0;
|
||||
virtual BitSet32 GetCallerSavedUsed() const = 0;
|
||||
|
||||
// Returns a temporary register for use
|
||||
// Requires unlocking after done
|
||||
|
@ -178,7 +183,7 @@ protected:
|
|||
virtual void FlushRegister(size_t preg, bool maintain_state) = 0;
|
||||
|
||||
// Get available host registers
|
||||
u32 GetUnlockedRegisterCount();
|
||||
u32 GetUnlockedRegisterCount() const;
|
||||
|
||||
void IncrementAllUsed()
|
||||
{
|
||||
|
@ -187,7 +192,7 @@ protected:
|
|||
}
|
||||
|
||||
// Code emitter
|
||||
Arm64Gen::ARM64XEmitter* m_emit;
|
||||
Arm64Gen::ARM64XEmitter* m_emit = nullptr;
|
||||
|
||||
// Float emitter
|
||||
std::unique_ptr<Arm64Gen::ARM64FloatEmitter> m_float_emit;
|
||||
|
@ -201,14 +206,14 @@ protected:
|
|||
std::vector<OpArg> m_guest_registers;
|
||||
|
||||
// Register stats for the current block
|
||||
PPCAnalyst::BlockRegStats* m_reg_stats;
|
||||
PPCAnalyst::BlockRegStats* m_reg_stats = nullptr;
|
||||
};
|
||||
|
||||
class Arm64GPRCache : public Arm64RegCache
|
||||
{
|
||||
public:
|
||||
Arm64GPRCache();
|
||||
~Arm64GPRCache() {}
|
||||
|
||||
void Start(PPCAnalyst::BlockRegStats& stats) override;
|
||||
|
||||
// Flushes the register cache in different ways depending on the mode
|
||||
|
@ -222,14 +227,14 @@ public:
|
|||
// Set a register to an immediate, only valid for guest GPRs
|
||||
void SetImmediate(size_t preg, u32 imm) { SetImmediate(GetGuestGPR(preg), imm); }
|
||||
// Returns if a register is set as an immediate, only valid for guest GPRs
|
||||
bool IsImm(size_t preg) const { return GetGuestGPROpArg(preg).GetType() == REG_IMM; }
|
||||
bool IsImm(size_t preg) const { return GetGuestGPROpArg(preg).GetType() == RegType::Immediate; }
|
||||
// Gets the immediate that a register is set to, only valid for guest GPRs
|
||||
u32 GetImm(size_t preg) const { return GetGuestGPROpArg(preg).GetImm(); }
|
||||
// Binds a guest GPR to a host register, optionally loading its value
|
||||
void BindToRegister(size_t preg, bool do_load) { BindToRegister(GetGuestGPR(preg), do_load); }
|
||||
// Binds a guest CR to a host register, optionally loading its value
|
||||
void BindCRToRegister(size_t preg, bool do_load) { BindToRegister(GetGuestCR(preg), do_load); }
|
||||
BitSet32 GetCallerSavedUsed() override;
|
||||
BitSet32 GetCallerSavedUsed() const override;
|
||||
|
||||
void StoreRegisters(BitSet32 regs) { FlushRegisters(regs, false); }
|
||||
void StoreCRRegisters(BitSet32 regs) { FlushCRRegisters(regs, false); }
|
||||
|
@ -244,7 +249,7 @@ protected:
|
|||
void FlushRegister(size_t index, bool maintain_state) override;
|
||||
|
||||
private:
|
||||
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg);
|
||||
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg) const;
|
||||
|
||||
struct GuestRegInfo
|
||||
{
|
||||
|
@ -270,19 +275,19 @@ class Arm64FPRCache : public Arm64RegCache
|
|||
{
|
||||
public:
|
||||
Arm64FPRCache();
|
||||
~Arm64FPRCache() {}
|
||||
|
||||
// Flushes the register cache in different ways depending on the mode
|
||||
void Flush(FlushMode mode, PPCAnalyst::CodeOp* op = nullptr) override;
|
||||
|
||||
// Returns a guest register inside of a host register
|
||||
// Will dump an immediate to the host register as well
|
||||
Arm64Gen::ARM64Reg R(size_t preg, RegType type = REG_LOWER_PAIR);
|
||||
Arm64Gen::ARM64Reg R(size_t preg, RegType type = RegType::LowerPair);
|
||||
|
||||
Arm64Gen::ARM64Reg RW(size_t preg, RegType type = REG_LOWER_PAIR);
|
||||
Arm64Gen::ARM64Reg RW(size_t preg, RegType type = RegType::LowerPair);
|
||||
|
||||
BitSet32 GetCallerSavedUsed() override;
|
||||
BitSet32 GetCallerSavedUsed() const override;
|
||||
|
||||
bool IsSingle(size_t preg, bool lower_only = false);
|
||||
bool IsSingle(size_t preg, bool lower_only = false) const;
|
||||
|
||||
void FixSinglePrecision(size_t preg);
|
||||
|
||||
|
@ -298,7 +303,7 @@ protected:
|
|||
void FlushRegister(size_t preg, bool maintain_state) override;
|
||||
|
||||
private:
|
||||
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg);
|
||||
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg) const;
|
||||
|
||||
void FlushRegisters(BitSet32 regs, bool maintain_state);
|
||||
};
|
||||
|
|
|
@ -44,8 +44,8 @@ void JitArm64::mtmsr(UGeckoInstruction inst)
|
|||
gpr.BindToRegister(inst.RS, true);
|
||||
STR(INDEX_UNSIGNED, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(msr));
|
||||
|
||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
|
||||
// Our jit cache also stores some MSR bits, as they have changed, we either
|
||||
// have to validate them in the BLR/RET check, or just flush the stack here.
|
||||
|
@ -201,8 +201,8 @@ void JitArm64::twx(UGeckoInstruction inst)
|
|||
SwitchToFarCode();
|
||||
SetJumpTarget(far_addr);
|
||||
|
||||
gpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE);
|
||||
fpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE);
|
||||
gpr.Flush(FlushMode::MaintainState);
|
||||
fpr.Flush(FlushMode::MaintainState);
|
||||
|
||||
LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
|
||||
ORR(WA, WA, 24, 0); // Same as WA | EXCEPTION_PROGRAM
|
||||
|
@ -217,8 +217,8 @@ void JitArm64::twx(UGeckoInstruction inst)
|
|||
|
||||
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
|
||||
{
|
||||
gpr.Flush(FlushMode::FLUSH_ALL);
|
||||
fpr.Flush(FlushMode::FLUSH_ALL);
|
||||
gpr.Flush(FlushMode::All);
|
||||
fpr.Flush(FlushMode::All);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue