Merge pull request #12682 from JosJuice/jit-fallback-discard-assert
Jit: Skip discarded registers when flushing for interpreter fallback
This commit is contained in:
commit
ada646a795
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue