JitArm64: Update registers last used before start of instruction

Let's reset m_last_used for each register that will be used
in an instruction before we start allocating any of them,
so that one of the earlier allocations doesn't spill a
register that we want in a later allocation. (We must still
also increment/reset m_last_used in R and RW, otherwise we
end up in trouble when emulating lmw/stmw since those access
more guest registers than there are available host registers.)

This should ensure that the asserts added earlier in this
pull request are never triggered.
This commit is contained in:
JosJuice 2021-01-24 14:56:38 +01:00
parent f17cd3750a
commit d00430470b
3 changed files with 24 additions and 1 deletions

View File

@ -694,6 +694,15 @@ void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
if (!SConfig::GetInstance().bEnableDebugging)
js.downcountAmount += PatchEngine::GetSpeedhackCycles(js.compilerPC);
// Skip calling UpdateLastUsed for lmw/stmw - it usually hurts more than it helps
if (op.inst.OPCD != 46 && op.inst.OPCD != 47)
gpr.UpdateLastUsed(op.regsIn | op.regsOut);
BitSet32 fpr_used = op.fregsIn;
if (op.fregOut >= 0)
fpr_used[op.fregOut] = true;
fpr.UpdateLastUsed(fpr_used);
// Gather pipe writes using a non-immediate address are discovered by profiling.
bool gatherPipeIntCheck = js.fifoWriteAddresses.find(op.address) != js.fifoWriteAddresses.end();

View File

@ -41,10 +41,22 @@ ARM64Reg Arm64RegCache::GetReg()
// Holy cow, how did you run out of registers?
// We can't return anything reasonable in this case. Return INVALID_REG and watch the failure
// happen
WARN_LOG_FMT(DYNA_REC, "All available registers are locked dumb dumb");
ASSERT_MSG(DYNA_REC, 0, "All available registers are locked!");
return INVALID_REG;
}
void Arm64RegCache::UpdateLastUsed(BitSet32 regs_used)
{
for (size_t i = 0; i < m_guest_registers.size(); ++i)
{
OpArg& reg = m_guest_registers[i];
if (i < 32 && regs_used[i])
reg.ResetLastUsed();
else
reg.IncrementLastUsed();
}
}
u32 Arm64RegCache::GetUnlockedRegisterCount() const
{
u32 unlocked_registers = 0;

View File

@ -140,6 +140,8 @@ public:
// Requires unlocking after done
Arm64Gen::ARM64Reg GetReg();
void UpdateLastUsed(BitSet32 regs_used);
// Locks a register so a cache cannot use it
// Useful for function calls
template <typename T = Arm64Gen::ARM64Reg, typename... Args>