Jits: Fix interpreter fallback handling of discarded registers
When the interpreter writes to a discarded register, its type
must be changed so that it is no longer considered discarded.
Fixes a 62ce1c7
regression.
This commit is contained in:
parent
5322256065
commit
b3b5016f54
|
@ -419,15 +419,23 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst)
|
|||
{
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
|
||||
if (js.op->opinfo->flags & FL_ENDBLOCK)
|
||||
{
|
||||
MOV(32, PPCSTATE(pc), Imm32(js.compilerPC));
|
||||
MOV(32, PPCSTATE(npc), Imm32(js.compilerPC + 4));
|
||||
}
|
||||
|
||||
Interpreter::Instruction instr = PPCTables::GetInterpreterOp(inst);
|
||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||
ABI_CallFunctionC(instr, inst.hex);
|
||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||
|
||||
// If the instruction wrote to any registers which were marked as discarded,
|
||||
// we must mark them as no longer discarded
|
||||
gpr.Reset(js.op->regsOut);
|
||||
fpr.Reset(js.op->GetFregsOut());
|
||||
|
||||
if (js.op->opinfo->flags & FL_ENDBLOCK)
|
||||
{
|
||||
if (js.isLastInstruction)
|
||||
|
|
|
@ -436,6 +436,16 @@ void RegCache::Flush(BitSet32 pregs)
|
|||
}
|
||||
}
|
||||
|
||||
void RegCache::Reset(BitSet32 pregs)
|
||||
{
|
||||
for (preg_t i : pregs)
|
||||
{
|
||||
ASSERT_MSG(DYNAREC, !m_regs[i].IsAway(),
|
||||
"Attempted to reset a loaded register (did you mean to flush it?)");
|
||||
m_regs[i].SetFlushed();
|
||||
}
|
||||
}
|
||||
|
||||
void RegCache::Revert()
|
||||
{
|
||||
ASSERT(IsAllUnlocked());
|
||||
|
|
|
@ -171,6 +171,7 @@ public:
|
|||
RCForkGuard Fork();
|
||||
void Discard(BitSet32 pregs);
|
||||
void Flush(BitSet32 pregs = BitSet32::AllTrue(32));
|
||||
void Reset(BitSet32 pregs);
|
||||
void Revert();
|
||||
void Commit();
|
||||
|
||||
|
|
|
@ -161,6 +161,11 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
|
|||
MOVI2R(ARM64Reg::W0, inst.hex);
|
||||
BLR(ARM64Reg::X8);
|
||||
|
||||
// If the instruction wrote to any registers which were marked as discarded,
|
||||
// we must mark them as no longer discarded
|
||||
gpr.ResetRegisters(js.op->regsOut);
|
||||
fpr.ResetRegisters(js.op->GetFregsOut());
|
||||
|
||||
if (js.op->opinfo->flags & FL_ENDBLOCK)
|
||||
{
|
||||
if (js.isLastInstruction)
|
||||
|
|
|
@ -26,8 +26,21 @@ void Arm64RegCache::Init(ARM64XEmitter* emitter)
|
|||
|
||||
void Arm64RegCache::DiscardRegisters(BitSet32 regs)
|
||||
{
|
||||
for (int j : regs)
|
||||
DiscardRegister(j);
|
||||
for (int i : regs)
|
||||
DiscardRegister(i);
|
||||
}
|
||||
|
||||
void Arm64RegCache::ResetRegisters(BitSet32 regs)
|
||||
{
|
||||
for (int i : regs)
|
||||
{
|
||||
OpArg& reg = m_guest_registers[i];
|
||||
ARM64Reg host_reg = reg.GetReg();
|
||||
|
||||
ASSERT_MSG(DYNAREC, host_reg == ARM64Reg::INVALID_REG,
|
||||
"Attempted to reset a loaded register (did you mean to flush it?)");
|
||||
reg.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
ARM64Reg Arm64RegCache::GetReg()
|
||||
|
|
|
@ -154,6 +154,7 @@ public:
|
|||
|
||||
virtual void Start(PPCAnalyst::BlockRegStats& stats) {}
|
||||
void DiscardRegisters(BitSet32 regs);
|
||||
void ResetRegisters(BitSet32 regs);
|
||||
// Flushes the register cache in different ways depending on the mode
|
||||
virtual void Flush(FlushMode mode, PPCAnalyst::CodeOp* op) = 0;
|
||||
|
||||
|
|
|
@ -957,8 +957,7 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer, std:
|
|||
{
|
||||
gprDiscardable |= op.regsOut;
|
||||
gprDiscardable &= ~op.regsIn;
|
||||
if (op.fregOut >= 0)
|
||||
fprDiscardable[op.fregOut] = true;
|
||||
fprDiscardable |= op.GetFregsOut();
|
||||
fprDiscardable &= ~op.fregsIn;
|
||||
}
|
||||
if (strncmp(op.opinfo->opname, "stfd", 4))
|
||||
|
|
|
@ -67,6 +67,16 @@ struct CodeOp // 16B
|
|||
// (The reason why we can't always do this is because some games rely on the exact bits of
|
||||
// denormals and SNaNs being preserved as long as no arithmetic operation is performed on them.)
|
||||
BitSet32 fprIsStoreSafe;
|
||||
|
||||
BitSet32 GetFregsOut() const
|
||||
{
|
||||
BitSet32 result;
|
||||
|
||||
if (fregOut >= 0)
|
||||
result[fregOut] = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct BlockStats
|
||||
|
|
Loading…
Reference in New Issue