summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2021-04-25 13:20:41 +0200
committerGitHub <noreply@github.com>2021-04-25 13:20:41 +0200
commitaa3a96f048a889cc77445a320397e377baff2ba4 (patch)
tree79025bb37e56d290e102449be4e52037d0b6c3a0 /Source/Core
parent0f563ffd59857424fd6281e4630d5564c9a7164e (diff)
parentb3b5016f54ff3f8a4ef2285436734f36ab8112e0 (diff)
Merge pull request #9644 from JosJuice/jit-fallback-discard
Jits: Fix interpreter fallback handling of discarded registers
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/PowerPC/Jit64/Jit.cpp8
-rw-r--r--Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp10
-rw-r--r--Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h1
-rw-r--r--Source/Core/Core/PowerPC/JitArm64/Jit.cpp5
-rw-r--r--Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp17
-rw-r--r--Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h1
-rw-r--r--Source/Core/Core/PowerPC/PPCAnalyst.cpp3
-rw-r--r--Source/Core/Core/PowerPC/PPCAnalyst.h10
8 files changed, 51 insertions, 4 deletions
diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp
index 5e436cb13e..ac8b60afee 100644
--- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp
+++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp
@@ -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)
diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp
index b9ac55f210..3ca3e9f36e 100644
--- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp
+++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp
@@ -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());
diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h
index 291e18018f..b3a0bbd2c7 100644
--- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h
+++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h
@@ -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();
diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp
index 49ce26c3dc..9c1b98d2f0 100644
--- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp
+++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp
@@ -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)
diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp
index 5ce941da21..e41ffdbfa8 100644
--- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp
+++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp
@@ -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()
diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h
index ca7917e197..edee9f2a85 100644
--- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h
+++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h
@@ -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;
diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp
index 833f5f476a..0017d636e7 100644
--- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp
+++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp
@@ -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))
diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.h b/Source/Core/Core/PowerPC/PPCAnalyst.h
index 3b82618978..d1154baee6 100644
--- a/Source/Core/Core/PowerPC/PPCAnalyst.h
+++ b/Source/Core/Core/PowerPC/PPCAnalyst.h
@@ -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