diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index de2def0dbf..b09279d458 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -350,8 +350,8 @@ void Jit64::Shutdown() void Jit64::FallBackToInterpreter(UGeckoInstruction inst) { - gpr.Flush(); - fpr.Flush(); + gpr.Flush(BitSet32(0xFFFFFFFF), RegCache::IgnoreDiscardedRegisters::Yes); + fpr.Flush(BitSet32(0xFFFFFFFF), RegCache::IgnoreDiscardedRegisters::Yes); if (js.op->canEndBlock) { diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp index c647ed32d6..f06423ce3e 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp @@ -391,7 +391,7 @@ void RegCache::Discard(BitSet32 pregs) } } -void RegCache::Flush(BitSet32 pregs) +void RegCache::Flush(BitSet32 pregs, IgnoreDiscardedRegisters ignore_discarded_registers) { ASSERT_MSG( DYNA_REC, @@ -410,7 +410,8 @@ void RegCache::Flush(BitSet32 pregs) case PPCCachedReg::LocationType::Default: break; case PPCCachedReg::LocationType::Discarded: - ASSERT_MSG(DYNA_REC, false, "Attempted to flush discarded PPC reg {}", i); + ASSERT_MSG(DYNA_REC, ignore_discarded_registers != IgnoreDiscardedRegisters::No, + "Attempted to flush discarded PPC reg {}", i); break; case PPCCachedReg::LocationType::SpeculativeImmediate: // We can have a cached value without a host register through speculative constants. diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h index f025190312..3677d2b42b 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h @@ -126,6 +126,12 @@ public: MaintainState, }; + enum class IgnoreDiscardedRegisters + { + No, + Yes, + }; + explicit RegCache(Jit64& jit); virtual ~RegCache() = default; @@ -168,7 +174,8 @@ public: RCForkGuard Fork(); void Discard(BitSet32 pregs); - void Flush(BitSet32 pregs = BitSet32::AllTrue(32)); + void Flush(BitSet32 pregs = BitSet32::AllTrue(32), + IgnoreDiscardedRegisters ignore_discarded_registers = IgnoreDiscardedRegisters::No); 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 b8f1d8cd73..51925d0d48 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -256,8 +256,8 @@ void JitArm64::Shutdown() void JitArm64::FallBackToInterpreter(UGeckoInstruction inst) { FlushCarry(); - gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG); - fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG); + gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG, IgnoreDiscardedRegisters::Yes); + fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG, IgnoreDiscardedRegisters::Yes); if (js.op->canEndBlock) { diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp index b93b30153f..465d0257af 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp @@ -241,12 +241,16 @@ void Arm64GPRCache::FlushRegister(size_t index, FlushMode mode, ARM64Reg tmp_reg } } -void Arm64GPRCache::FlushRegisters(BitSet32 regs, FlushMode mode, ARM64Reg tmp_reg) +void Arm64GPRCache::FlushRegisters(BitSet32 regs, FlushMode mode, ARM64Reg tmp_reg, + IgnoreDiscardedRegisters ignore_discarded_registers) { for (auto iter = regs.begin(); iter != regs.end(); ++iter) { const int i = *iter; - ASSERT_MSG(DYNA_REC, m_guest_registers[GUEST_GPR_OFFSET + i].GetType() != RegType::Discarded, + + ASSERT_MSG(DYNA_REC, + ignore_discarded_registers != IgnoreDiscardedRegisters::No || + m_guest_registers[GUEST_GPR_OFFSET + i].GetType() != RegType::Discarded, "Attempted to flush discarded register"); if (i + 1 < int(GUEST_GPR_COUNT) && regs[i + 1]) @@ -288,11 +292,14 @@ void Arm64GPRCache::FlushRegisters(BitSet32 regs, FlushMode mode, ARM64Reg tmp_r } } -void Arm64GPRCache::FlushCRRegisters(BitSet8 regs, FlushMode mode, ARM64Reg tmp_reg) +void Arm64GPRCache::FlushCRRegisters(BitSet8 regs, FlushMode mode, ARM64Reg tmp_reg, + IgnoreDiscardedRegisters ignore_discarded_registers) { for (int i : regs) { - ASSERT_MSG(DYNA_REC, m_guest_registers[GUEST_CR_OFFSET + i].GetType() != RegType::Discarded, + ASSERT_MSG(DYNA_REC, + ignore_discarded_registers != IgnoreDiscardedRegisters::No || + m_guest_registers[GUEST_CR_OFFSET + i].GetType() != RegType::Discarded, "Attempted to flush discarded register"); FlushRegister(GUEST_CR_OFFSET + i, mode, tmp_reg); @@ -318,10 +325,11 @@ void Arm64GPRCache::ResetCRRegisters(BitSet8 regs) } } -void Arm64GPRCache::Flush(FlushMode mode, ARM64Reg tmp_reg) +void Arm64GPRCache::Flush(FlushMode mode, ARM64Reg tmp_reg, + IgnoreDiscardedRegisters ignore_discarded_registers) { - FlushRegisters(BitSet32(0xFFFFFFFF), mode, tmp_reg); - FlushCRRegisters(BitSet8(0xFF), mode, tmp_reg); + FlushRegisters(BitSet32(0xFFFFFFFF), mode, tmp_reg, ignore_discarded_registers); + FlushCRRegisters(BitSet8(0xFF), mode, tmp_reg, ignore_discarded_registers); } ARM64Reg Arm64GPRCache::R(const GuestRegInfo& guest_reg) @@ -498,14 +506,19 @@ Arm64FPRCache::Arm64FPRCache() : Arm64RegCache(GUEST_FPR_COUNT) { } -void Arm64FPRCache::Flush(FlushMode mode, ARM64Reg tmp_reg) +void Arm64FPRCache::Flush(FlushMode mode, ARM64Reg tmp_reg, + IgnoreDiscardedRegisters ignore_discarded_registers) { for (size_t i = 0; i < m_guest_registers.size(); ++i) { const RegType reg_type = m_guest_registers[i].GetType(); - if (reg_type != RegType::NotLoaded && reg_type != RegType::Discarded && - reg_type != RegType::Immediate) + if (reg_type == RegType::Discarded) + { + ASSERT_MSG(DYNA_REC, ignore_discarded_registers != IgnoreDiscardedRegisters::No, + "Attempted to flush discarded register"); + } + else if (reg_type != RegType::NotLoaded && reg_type != RegType::Immediate) { FlushRegister(i, mode, tmp_reg); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h index 159cfb6836..b98e170531 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h @@ -81,6 +81,12 @@ enum class FlushMode : bool MaintainState, }; +enum class IgnoreDiscardedRegisters +{ + No, + Yes, +}; + class OpArg { public: @@ -169,7 +175,8 @@ public: // Flushes the register cache in different ways depending on the mode. // A temporary register must be supplied when flushing GPRs with FlushMode::MaintainState, // but in other cases it can be set to ARM64Reg::INVALID_REG when convenient for the caller. - virtual void Flush(FlushMode mode, Arm64Gen::ARM64Reg tmp_reg) = 0; + virtual void Flush(FlushMode mode, Arm64Gen::ARM64Reg tmp_reg, + IgnoreDiscardedRegisters ignore_discarded_registers) = 0; virtual BitSet32 GetCallerSavedUsed() const = 0; @@ -315,7 +322,9 @@ public: // Flushes the register cache in different ways depending on the mode. // A temporary register must be supplied when flushing GPRs with FlushMode::MaintainState, // but in other cases it can be set to ARM64Reg::INVALID_REG when convenient for the caller. - void Flush(FlushMode mode, Arm64Gen::ARM64Reg tmp_reg) override; + void Flush( + FlushMode mode, Arm64Gen::ARM64Reg tmp_reg, + IgnoreDiscardedRegisters ignore_discarded_registers = IgnoreDiscardedRegisters::No) override; // Returns a guest GPR inside of a host register. // Will dump an immediate to the host register as well. @@ -381,12 +390,12 @@ public: void StoreRegisters(BitSet32 regs, Arm64Gen::ARM64Reg tmp_reg = Arm64Gen::ARM64Reg::INVALID_REG) { - FlushRegisters(regs, FlushMode::All, tmp_reg); + FlushRegisters(regs, FlushMode::All, tmp_reg, IgnoreDiscardedRegisters::No); } void StoreCRRegisters(BitSet8 regs, Arm64Gen::ARM64Reg tmp_reg = Arm64Gen::ARM64Reg::INVALID_REG) { - FlushCRRegisters(regs, FlushMode::All, tmp_reg); + FlushCRRegisters(regs, FlushMode::All, tmp_reg, IgnoreDiscardedRegisters::No); } void DiscardCRRegisters(BitSet8 regs); @@ -421,8 +430,10 @@ private: void SetImmediate(const GuestRegInfo& guest_reg, u32 imm, bool dirty); void BindToRegister(const GuestRegInfo& guest_reg, bool will_read, bool will_write = true); - void FlushRegisters(BitSet32 regs, FlushMode mode, Arm64Gen::ARM64Reg tmp_reg); - void FlushCRRegisters(BitSet8 regs, FlushMode mode, Arm64Gen::ARM64Reg tmp_reg); + void FlushRegisters(BitSet32 regs, FlushMode mode, Arm64Gen::ARM64Reg tmp_reg, + IgnoreDiscardedRegisters ignore_discarded_registers); + void FlushCRRegisters(BitSet8 regs, FlushMode mode, Arm64Gen::ARM64Reg tmp_reg, + IgnoreDiscardedRegisters ignore_discarded_registers); }; class Arm64FPRCache : public Arm64RegCache @@ -432,7 +443,9 @@ public: // Flushes the register cache in different ways depending on the mode. // The temporary register can be set to ARM64Reg::INVALID_REG when convenient for the caller. - void Flush(FlushMode mode, Arm64Gen::ARM64Reg tmp_reg) override; + void Flush( + FlushMode mode, Arm64Gen::ARM64Reg tmp_reg, + IgnoreDiscardedRegisters ignore_discarded_registers = IgnoreDiscardedRegisters::No) override; // Returns a guest register inside of a host register // Will dump an immediate to the host register as well