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)
|
void Jit64::FallBackToInterpreter(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
gpr.Flush();
|
gpr.Flush(BitSet32(0xFFFFFFFF), RegCache::IgnoreDiscardedRegisters::Yes);
|
||||||
fpr.Flush();
|
fpr.Flush(BitSet32(0xFFFFFFFF), RegCache::IgnoreDiscardedRegisters::Yes);
|
||||||
|
|
||||||
if (js.op->canEndBlock)
|
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(
|
ASSERT_MSG(
|
||||||
DYNA_REC,
|
DYNA_REC,
|
||||||
|
@ -410,7 +410,8 @@ void RegCache::Flush(BitSet32 pregs)
|
||||||
case PPCCachedReg::LocationType::Default:
|
case PPCCachedReg::LocationType::Default:
|
||||||
break;
|
break;
|
||||||
case PPCCachedReg::LocationType::Discarded:
|
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;
|
break;
|
||||||
case PPCCachedReg::LocationType::SpeculativeImmediate:
|
case PPCCachedReg::LocationType::SpeculativeImmediate:
|
||||||
// We can have a cached value without a host register through speculative constants.
|
// We can have a cached value without a host register through speculative constants.
|
||||||
|
|
|
@ -126,6 +126,12 @@ public:
|
||||||
MaintainState,
|
MaintainState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class IgnoreDiscardedRegisters
|
||||||
|
{
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
|
||||||
explicit RegCache(Jit64& jit);
|
explicit RegCache(Jit64& jit);
|
||||||
virtual ~RegCache() = default;
|
virtual ~RegCache() = default;
|
||||||
|
|
||||||
|
@ -168,7 +174,8 @@ public:
|
||||||
|
|
||||||
RCForkGuard Fork();
|
RCForkGuard Fork();
|
||||||
void Discard(BitSet32 pregs);
|
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 Reset(BitSet32 pregs);
|
||||||
void Revert();
|
void Revert();
|
||||||
void Commit();
|
void Commit();
|
||||||
|
|
|
@ -256,8 +256,8 @@ void JitArm64::Shutdown()
|
||||||
void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
|
void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
FlushCarry();
|
FlushCarry();
|
||||||
gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
|
gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG, IgnoreDiscardedRegisters::Yes);
|
||||||
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
|
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG, IgnoreDiscardedRegisters::Yes);
|
||||||
|
|
||||||
if (js.op->canEndBlock)
|
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)
|
for (auto iter = regs.begin(); iter != regs.end(); ++iter)
|
||||||
{
|
{
|
||||||
const int i = *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");
|
"Attempted to flush discarded register");
|
||||||
|
|
||||||
if (i + 1 < int(GUEST_GPR_COUNT) && regs[i + 1])
|
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)
|
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");
|
"Attempted to flush discarded register");
|
||||||
|
|
||||||
FlushRegister(GUEST_CR_OFFSET + i, mode, tmp_reg);
|
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);
|
FlushRegisters(BitSet32(0xFFFFFFFF), mode, tmp_reg, ignore_discarded_registers);
|
||||||
FlushCRRegisters(BitSet8(0xFF), mode, tmp_reg);
|
FlushCRRegisters(BitSet8(0xFF), mode, tmp_reg, ignore_discarded_registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARM64Reg Arm64GPRCache::R(const GuestRegInfo& guest_reg)
|
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)
|
for (size_t i = 0; i < m_guest_registers.size(); ++i)
|
||||||
{
|
{
|
||||||
const RegType reg_type = m_guest_registers[i].GetType();
|
const RegType reg_type = m_guest_registers[i].GetType();
|
||||||
|
|
||||||
if (reg_type != RegType::NotLoaded && reg_type != RegType::Discarded &&
|
if (reg_type == RegType::Discarded)
|
||||||
reg_type != RegType::Immediate)
|
{
|
||||||
|
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);
|
FlushRegister(i, mode, tmp_reg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,12 @@ enum class FlushMode : bool
|
||||||
MaintainState,
|
MaintainState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class IgnoreDiscardedRegisters
|
||||||
|
{
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
|
||||||
class OpArg
|
class OpArg
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -169,7 +175,8 @@ public:
|
||||||
// Flushes the register cache in different ways depending on the mode.
|
// Flushes the register cache in different ways depending on the mode.
|
||||||
// A temporary register must be supplied when flushing GPRs with FlushMode::MaintainState,
|
// 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.
|
// 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;
|
virtual BitSet32 GetCallerSavedUsed() const = 0;
|
||||||
|
|
||||||
|
@ -315,7 +322,9 @@ public:
|
||||||
// Flushes the register cache in different ways depending on the mode.
|
// Flushes the register cache in different ways depending on the mode.
|
||||||
// A temporary register must be supplied when flushing GPRs with FlushMode::MaintainState,
|
// 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.
|
// 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.
|
// Returns a guest GPR inside of a host register.
|
||||||
// Will dump an immediate to the host register as well.
|
// 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)
|
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)
|
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);
|
void DiscardCRRegisters(BitSet8 regs);
|
||||||
|
@ -421,8 +430,10 @@ private:
|
||||||
void SetImmediate(const GuestRegInfo& guest_reg, u32 imm, bool dirty);
|
void SetImmediate(const GuestRegInfo& guest_reg, u32 imm, bool dirty);
|
||||||
void BindToRegister(const GuestRegInfo& guest_reg, bool will_read, bool will_write = true);
|
void BindToRegister(const GuestRegInfo& guest_reg, bool will_read, bool will_write = true);
|
||||||
|
|
||||||
void FlushRegisters(BitSet32 regs, FlushMode mode, Arm64Gen::ARM64Reg tmp_reg);
|
void FlushRegisters(BitSet32 regs, FlushMode mode, Arm64Gen::ARM64Reg tmp_reg,
|
||||||
void FlushCRRegisters(BitSet8 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
|
class Arm64FPRCache : public Arm64RegCache
|
||||||
|
@ -432,7 +443,9 @@ public:
|
||||||
|
|
||||||
// Flushes the register cache in different ways depending on the mode.
|
// 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.
|
// 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
|
// Returns a guest register inside of a host register
|
||||||
// Will dump an immediate to the host register as well
|
// Will dump an immediate to the host register as well
|
||||||
|
|
Loading…
Reference in New Issue