Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #9644 from JosJuice/jit-fallback-discard
Jits: Fix interpreter fallback handling of discarded registers
  • Loading branch information
leoetlino committed Apr 25, 2021
2 parents 0f563ff + b3b5016 commit aa3a96f
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 4 deletions.
8 changes: 8 additions & 0 deletions Source/Core/Core/PowerPC/Jit64/Jit.cpp
Expand Up @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp
Expand Up @@ -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());
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h
Expand Up @@ -171,6 +171,7 @@ class RegCache
RCForkGuard Fork();
void Discard(BitSet32 pregs);
void Flush(BitSet32 pregs = BitSet32::AllTrue(32));
void Reset(BitSet32 pregs);
void Revert();
void Commit();

Expand Down
5 changes: 5 additions & 0 deletions Source/Core/Core/PowerPC/JitArm64/Jit.cpp
Expand Up @@ -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)
Expand Down
17 changes: 15 additions & 2 deletions Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp
Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h
Expand Up @@ -154,6 +154,7 @@ class Arm64RegCache

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;

Expand Down
3 changes: 1 addition & 2 deletions Source/Core/Core/PowerPC/PPCAnalyst.cpp
Expand Up @@ -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))
Expand Down
10 changes: 10 additions & 0 deletions Source/Core/Core/PowerPC/PPCAnalyst.h
Expand Up @@ -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
Expand Down

0 comments on commit aa3a96f

Please sign in to comment.