JitRegCache: Remove old interface
This commit is contained in:
parent
08c41090b2
commit
342067abfa
|
@ -920,10 +920,8 @@ u8* Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||
fpr.Commit();
|
||||
|
||||
// If we have a register that will never be used again, flush it.
|
||||
for (int j : ~op.gprInUse)
|
||||
gpr.StoreFromRegister(j);
|
||||
for (int j : ~op.fprInUse)
|
||||
fpr.StoreFromRegister(j);
|
||||
gpr.Flush(~op.gprInUse);
|
||||
fpr.Flush(~op.fprInUse);
|
||||
|
||||
if (opinfo->flags & FL_LOADSTORE)
|
||||
++js.numLoadStoreInst;
|
||||
|
|
|
@ -116,7 +116,7 @@ void Jit64::HandleNaNs(UGeckoInstruction inst, X64Reg xmm_out, X64Reg xmm, X64Re
|
|||
else
|
||||
{
|
||||
// SSE2 fallback
|
||||
RCX64Reg tmp = fpr.Scratch(fpr.GetFreeXReg());
|
||||
RCX64Reg tmp = fpr.Scratch();
|
||||
RegCache::Realize(tmp);
|
||||
MOVAPD(clobber, R(xmm));
|
||||
CMPPD(clobber, R(clobber), CMP_UNORD);
|
||||
|
|
|
@ -173,6 +173,7 @@ void Jit64::ComputeRC(preg_t preg, bool needs_test, bool needs_sext)
|
|||
if (needs_test)
|
||||
{
|
||||
TEST(32, arg, arg);
|
||||
arg.Unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -180,11 +181,9 @@ void Jit64::ComputeRC(preg_t preg, bool needs_test, bool needs_sext)
|
|||
// better to flush it here so that we don't have to flush it on both sides of the branch.
|
||||
// We don't want to do this if a test is needed though, because it would interrupt macro-op
|
||||
// fusion.
|
||||
for (int j : ~js.op->gprInUse)
|
||||
gpr.StoreFromRegister(j);
|
||||
}
|
||||
|
||||
arg.Unlock();
|
||||
gpr.Flush(~js.op->gprInUse);
|
||||
}
|
||||
DoMergedBranchCondition();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,7 +271,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
|
|||
X64Reg value = RSCRATCH2;
|
||||
RCOpArg Ra = inst.RA ? gpr.Use(inst.RA, RCMode::Read) : RCOpArg::Imm32(0);
|
||||
RCOpArg Rb = gpr.Use(inst.RB, RCMode::Read);
|
||||
RCX64Reg tmp = gpr.Scratch(gpr.GetFreeXReg());
|
||||
RCX64Reg tmp = gpr.Scratch();
|
||||
RegCache::Realize(Ra, Rb, tmp);
|
||||
|
||||
MOV_sum(32, addr, Ra, Rb);
|
||||
|
|
|
@ -101,7 +101,6 @@ public:
|
|||
ASSERT(IsLocked());
|
||||
locked--;
|
||||
}
|
||||
void UnlockAll() { locked = 0; } // TODO: Remove from final version
|
||||
|
||||
private:
|
||||
Gen::OpArg default_location{};
|
||||
|
@ -142,7 +141,6 @@ public:
|
|||
ASSERT(IsLocked());
|
||||
locked--;
|
||||
}
|
||||
void UnlockAll() { locked = 0; } // TODO: Remove from final version
|
||||
|
||||
private:
|
||||
preg_t ppcReg = static_cast<preg_t>(Gen::INVALID_REG);
|
||||
|
|
|
@ -12,9 +12,9 @@ class FPURegCache final : public RegCache
|
|||
{
|
||||
public:
|
||||
explicit FPURegCache(Jit64& jit);
|
||||
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
|
||||
|
||||
protected:
|
||||
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
|
||||
void StoreRegister(preg_t preg, const Gen::OpArg& newLoc) override;
|
||||
void LoadRegister(preg_t preg, Gen::X64Reg newLoc) override;
|
||||
const Gen::X64Reg* GetAllocationOrder(size_t* count) const override;
|
||||
|
|
|
@ -12,10 +12,10 @@ class GPRRegCache final : public RegCache
|
|||
{
|
||||
public:
|
||||
explicit GPRRegCache(Jit64& jit);
|
||||
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
|
||||
void SetImmediate32(preg_t preg, u32 imm_value, bool dirty = true);
|
||||
|
||||
protected:
|
||||
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
|
||||
void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) override;
|
||||
void LoadRegister(preg_t preg, Gen::X64Reg new_loc) override;
|
||||
const Gen::X64Reg* GetAllocationOrder(size_t* count) const override;
|
||||
|
|
|
@ -47,7 +47,7 @@ RCOpArg::RCOpArg(X64Reg xr) : rc(nullptr), contents(xr)
|
|||
|
||||
RCOpArg::RCOpArg(RegCache* rc_, preg_t preg) : rc(rc_), contents(preg)
|
||||
{
|
||||
rc->NewLock(preg);
|
||||
rc->Lock(preg);
|
||||
}
|
||||
|
||||
RCOpArg::~RCOpArg()
|
||||
|
@ -128,14 +128,14 @@ void RCOpArg::Unlock()
|
|||
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||
{
|
||||
ASSERT(rc);
|
||||
rc->NewUnlock(*preg);
|
||||
rc->Unlock(*preg);
|
||||
}
|
||||
else if (const X64Reg* xr = std::get_if<X64Reg>(&contents))
|
||||
{
|
||||
// If rc, we got this from an RCX64Reg.
|
||||
// If !rc, we got this from RCOpArg::R.
|
||||
if (rc)
|
||||
rc->NewUnlockX(*xr);
|
||||
rc->UnlockX(*xr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -191,12 +191,12 @@ RCX64Reg::RCX64Reg() = default;
|
|||
|
||||
RCX64Reg::RCX64Reg(RegCache* rc_, preg_t preg) : rc(rc_), contents(preg)
|
||||
{
|
||||
rc->NewLock(preg);
|
||||
rc->Lock(preg);
|
||||
}
|
||||
|
||||
RCX64Reg::RCX64Reg(RegCache* rc_, X64Reg xr) : rc(rc_), contents(xr)
|
||||
{
|
||||
rc->NewLockX(xr);
|
||||
rc->LockX(xr);
|
||||
}
|
||||
|
||||
RCX64Reg::~RCX64Reg()
|
||||
|
@ -251,12 +251,12 @@ void RCX64Reg::Unlock()
|
|||
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||
{
|
||||
ASSERT(rc);
|
||||
rc->NewUnlock(*preg);
|
||||
rc->Unlock(*preg);
|
||||
}
|
||||
else if (const X64Reg* xr = std::get_if<X64Reg>(&contents))
|
||||
{
|
||||
ASSERT(rc);
|
||||
rc->NewUnlockX(*xr);
|
||||
rc->UnlockX(*xr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -302,66 +302,11 @@ void RegCache::Start()
|
|||
}
|
||||
}
|
||||
|
||||
void RegCache::DiscardRegContentsIfCached(preg_t preg)
|
||||
{
|
||||
if (m_regs[preg].IsBound())
|
||||
{
|
||||
X64Reg xr = m_regs[preg].Location().GetSimpleReg();
|
||||
m_xregs[xr].SetFlushed();
|
||||
m_regs[preg].SetFlushed();
|
||||
}
|
||||
}
|
||||
|
||||
void RegCache::SetEmitter(XEmitter* emitter)
|
||||
{
|
||||
m_emitter = emitter;
|
||||
}
|
||||
|
||||
void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush)
|
||||
{
|
||||
ASSERT_MSG(
|
||||
DYNA_REC,
|
||||
std::none_of(m_xregs.begin(), m_xregs.end(), [](const auto& x) { return x.IsLocked(); }),
|
||||
"Someone forgot to unlock a X64 reg");
|
||||
|
||||
for (unsigned int i : regsToFlush)
|
||||
{
|
||||
ASSERT_MSG(DYNA_REC, !m_regs[i].IsLocked(), "Someone forgot to unlock PPC reg %u (X64 reg %i).",
|
||||
i, RX(i));
|
||||
ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction is in progress!");
|
||||
|
||||
switch (m_regs[i].GetLocationType())
|
||||
{
|
||||
case PPCCachedReg::LocationType::Default:
|
||||
break;
|
||||
case PPCCachedReg::LocationType::SpeculativeImmediate:
|
||||
// We can have a cached value without a host register through speculative constants.
|
||||
// It must be cleared when flushing, otherwise it may be out of sync with PPCSTATE,
|
||||
// if PPCSTATE is modified externally (e.g. fallback to interpreter).
|
||||
m_regs[i].SetFlushed();
|
||||
break;
|
||||
case PPCCachedReg::LocationType::Bound:
|
||||
case PPCCachedReg::LocationType::Immediate:
|
||||
StoreFromRegister(i, mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegCache::FlushLockX(X64Reg reg)
|
||||
{
|
||||
FlushX(reg);
|
||||
LockX(reg);
|
||||
}
|
||||
|
||||
void RegCache::FlushLockX(X64Reg reg1, X64Reg reg2)
|
||||
{
|
||||
FlushX(reg1);
|
||||
FlushX(reg2);
|
||||
LockX(reg1);
|
||||
LockX(reg2);
|
||||
}
|
||||
|
||||
bool RegCache::SanityCheck() const
|
||||
{
|
||||
for (size_t i = 0; i < m_regs.size(); i++)
|
||||
|
@ -389,21 +334,150 @@ bool RegCache::SanityCheck() const
|
|||
return true;
|
||||
}
|
||||
|
||||
void RegCache::KillImmediate(preg_t preg, bool doLoad, bool makeDirty)
|
||||
RCOpArg RegCache::Use(preg_t preg, RCMode mode)
|
||||
{
|
||||
switch (m_regs[preg].GetLocationType())
|
||||
m_constraints[preg].AddUse(mode);
|
||||
return RCOpArg{this, preg};
|
||||
}
|
||||
|
||||
RCOpArg RegCache::UseNoImm(preg_t preg, RCMode mode)
|
||||
{
|
||||
m_constraints[preg].AddUseNoImm(mode);
|
||||
return RCOpArg{this, preg};
|
||||
}
|
||||
|
||||
RCOpArg RegCache::BindOrImm(preg_t preg, RCMode mode)
|
||||
{
|
||||
m_constraints[preg].AddBindOrImm(mode);
|
||||
return RCOpArg{this, preg};
|
||||
}
|
||||
|
||||
RCX64Reg RegCache::Bind(preg_t preg, RCMode mode)
|
||||
{
|
||||
m_constraints[preg].AddBind(mode);
|
||||
return RCX64Reg{this, preg};
|
||||
}
|
||||
|
||||
RCX64Reg RegCache::RevertableBind(preg_t preg, RCMode mode)
|
||||
{
|
||||
m_constraints[preg].AddRevertableBind(mode);
|
||||
return RCX64Reg{this, preg};
|
||||
}
|
||||
|
||||
RCX64Reg RegCache::Scratch()
|
||||
{
|
||||
return Scratch(GetFreeXReg());
|
||||
}
|
||||
|
||||
RCX64Reg RegCache::Scratch(X64Reg xr)
|
||||
{
|
||||
FlushX(xr);
|
||||
return RCX64Reg{this, xr};
|
||||
}
|
||||
|
||||
RCForkGuard RegCache::Fork()
|
||||
{
|
||||
return RCForkGuard{*this};
|
||||
}
|
||||
|
||||
void RegCache::Flush(BitSet32 pregs)
|
||||
{
|
||||
ASSERT_MSG(
|
||||
DYNA_REC,
|
||||
std::none_of(m_xregs.begin(), m_xregs.end(), [](const auto& x) { return x.IsLocked(); }),
|
||||
"Someone forgot to unlock a X64 reg");
|
||||
|
||||
for (preg_t i : pregs)
|
||||
{
|
||||
ASSERT_MSG(DYNA_REC, !m_regs[i].IsLocked(),
|
||||
"Someone forgot to unlock PPC reg %zu (X64 reg %i).", i, RX(i));
|
||||
ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction is in progress!");
|
||||
|
||||
switch (m_regs[i].GetLocationType())
|
||||
{
|
||||
case PPCCachedReg::LocationType::Default:
|
||||
break;
|
||||
case PPCCachedReg::LocationType::SpeculativeImmediate:
|
||||
// We can have a cached value without a host register through speculative constants.
|
||||
// It must be cleared when flushing, otherwise it may be out of sync with PPCSTATE,
|
||||
// if PPCSTATE is modified externally (e.g. fallback to interpreter).
|
||||
m_regs[i].SetFlushed();
|
||||
break;
|
||||
case PPCCachedReg::LocationType::Bound:
|
||||
if (makeDirty)
|
||||
m_xregs[RX(preg)].MakeDirty();
|
||||
break;
|
||||
case PPCCachedReg::LocationType::Immediate:
|
||||
BindToRegister(preg, doLoad, makeDirty);
|
||||
StoreFromRegister(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegCache::Revert()
|
||||
{
|
||||
ASSERT(IsAllUnlocked());
|
||||
for (auto& reg : m_regs)
|
||||
{
|
||||
if (reg.IsRevertable())
|
||||
reg.SetRevert();
|
||||
}
|
||||
}
|
||||
|
||||
void RegCache::Commit()
|
||||
{
|
||||
ASSERT(IsAllUnlocked());
|
||||
for (auto& reg : m_regs)
|
||||
{
|
||||
if (reg.IsRevertable())
|
||||
reg.SetCommit();
|
||||
}
|
||||
}
|
||||
|
||||
bool RegCache::IsAllUnlocked() const
|
||||
{
|
||||
return std::none_of(m_regs.begin(), m_regs.end(), [](const auto& r) { return r.IsLocked(); }) &&
|
||||
std::none_of(m_xregs.begin(), m_xregs.end(), [](const auto& x) { return x.IsLocked(); }) &&
|
||||
!IsAnyConstraintActive();
|
||||
}
|
||||
|
||||
void RegCache::PreloadRegisters(BitSet32 to_preload)
|
||||
{
|
||||
for (preg_t preg : to_preload)
|
||||
{
|
||||
if (NumFreeRegisters() < 2)
|
||||
return;
|
||||
if (!R(preg).IsImm())
|
||||
BindToRegister(preg, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
BitSet32 RegCache::RegistersInUse() const
|
||||
{
|
||||
BitSet32 result;
|
||||
for (size_t i = 0; i < m_xregs.size(); i++)
|
||||
{
|
||||
if (!m_xregs[i].IsFree())
|
||||
result[i] = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void RegCache::FlushX(X64Reg reg)
|
||||
{
|
||||
ASSERT_MSG(DYNA_REC, reg < m_xregs.size(), "Flushing non-existent reg %i", reg);
|
||||
ASSERT(!m_xregs[reg].IsLocked());
|
||||
if (!m_xregs[reg].IsFree())
|
||||
{
|
||||
StoreFromRegister(m_xregs[reg].Contents());
|
||||
}
|
||||
}
|
||||
|
||||
void RegCache::DiscardRegContentsIfCached(preg_t preg)
|
||||
{
|
||||
if (m_regs[preg].IsBound())
|
||||
{
|
||||
X64Reg xr = m_regs[preg].Location().GetSimpleReg();
|
||||
m_xregs[xr].SetFlushed();
|
||||
m_regs[preg].SetFlushed();
|
||||
}
|
||||
}
|
||||
|
||||
void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty)
|
||||
|
@ -457,7 +531,7 @@ void RegCache::StoreFromRegister(preg_t i, FlushMode mode)
|
|||
{
|
||||
X64Reg xr = RX(i);
|
||||
doStore = m_xregs[xr].IsDirty();
|
||||
if (mode == FlushMode::All)
|
||||
if (mode == FlushMode::Full)
|
||||
m_xregs[xr].SetFlushed();
|
||||
break;
|
||||
}
|
||||
|
@ -468,39 +542,10 @@ void RegCache::StoreFromRegister(preg_t i, FlushMode mode)
|
|||
|
||||
if (doStore)
|
||||
StoreRegister(i, GetDefaultLocation(i));
|
||||
if (mode == FlushMode::All)
|
||||
if (mode == FlushMode::Full)
|
||||
m_regs[i].SetFlushed();
|
||||
}
|
||||
|
||||
const OpArg& RegCache::R(preg_t preg) const
|
||||
{
|
||||
return m_regs[preg].Location();
|
||||
}
|
||||
|
||||
X64Reg RegCache::RX(preg_t preg) const
|
||||
{
|
||||
ASSERT_MSG(DYNA_REC, m_regs[preg].IsBound(), "Unbound register - %zu", preg);
|
||||
return m_regs[preg].Location().GetSimpleReg();
|
||||
}
|
||||
|
||||
void RegCache::UnlockAll()
|
||||
{
|
||||
for (auto& reg : m_regs)
|
||||
reg.UnlockAll();
|
||||
m_constraints.fill({});
|
||||
}
|
||||
|
||||
void RegCache::UnlockAllX()
|
||||
{
|
||||
for (auto& xreg : m_xregs)
|
||||
xreg.UnlockAll();
|
||||
}
|
||||
|
||||
bool RegCache::IsFreeX(size_t xreg) const
|
||||
{
|
||||
return m_xregs[xreg].IsFree();
|
||||
}
|
||||
|
||||
X64Reg RegCache::GetFreeXReg()
|
||||
{
|
||||
size_t aCount;
|
||||
|
@ -556,16 +601,6 @@ int RegCache::NumFreeRegisters() const
|
|||
return count;
|
||||
}
|
||||
|
||||
void RegCache::FlushX(X64Reg reg)
|
||||
{
|
||||
ASSERT_MSG(DYNA_REC, reg < m_xregs.size(), "Flushing non-existent reg %i", reg);
|
||||
ASSERT(!m_xregs[reg].IsLocked());
|
||||
if (!m_xregs[reg].IsFree())
|
||||
{
|
||||
StoreFromRegister(m_xregs[reg].Contents());
|
||||
}
|
||||
}
|
||||
|
||||
// Estimate roughly how bad it would be to de-allocate this register. Higher score
|
||||
// means more bad.
|
||||
float RegCache::ScoreRegister(X64Reg xreg) const
|
||||
|
@ -598,102 +633,23 @@ float RegCache::ScoreRegister(X64Reg xreg) const
|
|||
return score;
|
||||
}
|
||||
|
||||
RCOpArg RegCache::Use(preg_t preg, RCMode mode)
|
||||
const OpArg& RegCache::R(preg_t preg) const
|
||||
{
|
||||
m_constraints[preg].AddUse(mode);
|
||||
return RCOpArg{this, preg};
|
||||
return m_regs[preg].Location();
|
||||
}
|
||||
|
||||
RCOpArg RegCache::UseNoImm(preg_t preg, RCMode mode)
|
||||
X64Reg RegCache::RX(preg_t preg) const
|
||||
{
|
||||
m_constraints[preg].AddUseNoImm(mode);
|
||||
return RCOpArg{this, preg};
|
||||
ASSERT_MSG(DYNA_REC, m_regs[preg].IsBound(), "Unbound register - %zu", preg);
|
||||
return m_regs[preg].Location().GetSimpleReg();
|
||||
}
|
||||
|
||||
RCOpArg RegCache::BindOrImm(preg_t preg, RCMode mode)
|
||||
{
|
||||
m_constraints[preg].AddBindOrImm(mode);
|
||||
return RCOpArg{this, preg};
|
||||
}
|
||||
|
||||
RCX64Reg RegCache::Bind(preg_t preg, RCMode mode)
|
||||
{
|
||||
m_constraints[preg].AddBind(mode);
|
||||
return RCX64Reg{this, preg};
|
||||
}
|
||||
|
||||
RCX64Reg RegCache::RevertableBind(preg_t preg, RCMode mode)
|
||||
{
|
||||
m_constraints[preg].AddRevertableBind(mode);
|
||||
return RCX64Reg{this, preg};
|
||||
}
|
||||
|
||||
RCX64Reg RegCache::Scratch(X64Reg xr)
|
||||
{
|
||||
FlushX(xr);
|
||||
return RCX64Reg{this, xr};
|
||||
}
|
||||
|
||||
RCForkGuard RegCache::Fork()
|
||||
{
|
||||
return RCForkGuard{*this};
|
||||
}
|
||||
|
||||
void RegCache::Revert()
|
||||
{
|
||||
ASSERT(IsAllUnlocked());
|
||||
for (auto& reg : m_regs)
|
||||
{
|
||||
if (reg.IsRevertable())
|
||||
reg.SetRevert();
|
||||
}
|
||||
}
|
||||
|
||||
void RegCache::Commit()
|
||||
{
|
||||
ASSERT(IsAllUnlocked());
|
||||
for (auto& reg : m_regs)
|
||||
{
|
||||
if (reg.IsRevertable())
|
||||
reg.SetCommit();
|
||||
}
|
||||
}
|
||||
|
||||
bool RegCache::IsAllUnlocked() const
|
||||
{
|
||||
return std::none_of(m_regs.begin(), m_regs.end(), [](const auto& r){ return r.IsLocked(); }) &&
|
||||
std::none_of(m_xregs.begin(), m_xregs.end(), [](const auto& x){ return x.IsLocked(); }) &&
|
||||
!IsAnyConstraintActive();
|
||||
}
|
||||
|
||||
void RegCache::PreloadRegisters(BitSet32 to_preload)
|
||||
{
|
||||
for (preg_t preg : to_preload)
|
||||
{
|
||||
if (NumFreeRegisters() < 2)
|
||||
return;
|
||||
if (!R(preg).IsImm())
|
||||
BindToRegister(preg, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
BitSet32 RegCache::RegistersInUse() const
|
||||
{
|
||||
BitSet32 result;
|
||||
for (size_t i = 0; i < m_xregs.size(); i++)
|
||||
{
|
||||
if (!m_xregs[i].IsFree())
|
||||
result[i] = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void RegCache::NewLock(preg_t preg)
|
||||
void RegCache::Lock(preg_t preg)
|
||||
{
|
||||
m_regs[preg].Lock();
|
||||
}
|
||||
|
||||
void RegCache::NewUnlock(preg_t preg)
|
||||
void RegCache::Unlock(preg_t preg)
|
||||
{
|
||||
m_regs[preg].Unlock();
|
||||
if (!m_regs[preg].IsLocked())
|
||||
|
@ -703,12 +659,12 @@ void RegCache::NewUnlock(preg_t preg)
|
|||
}
|
||||
}
|
||||
|
||||
void RegCache::NewLockX(X64Reg xr)
|
||||
void RegCache::LockX(X64Reg xr)
|
||||
{
|
||||
m_xregs[xr].Lock();
|
||||
}
|
||||
|
||||
void RegCache::NewUnlockX(X64Reg xr)
|
||||
void RegCache::UnlockX(X64Reg xr)
|
||||
{
|
||||
m_xregs[xr].Unlock();
|
||||
}
|
||||
|
|
|
@ -126,89 +126,16 @@ class RegCache
|
|||
public:
|
||||
enum class FlushMode
|
||||
{
|
||||
All,
|
||||
Full,
|
||||
MaintainState,
|
||||
};
|
||||
|
||||
explicit RegCache(Jit64& jit);
|
||||
virtual ~RegCache() = default;
|
||||
|
||||
virtual Gen::OpArg GetDefaultLocation(preg_t preg) const = 0;
|
||||
|
||||
void Start();
|
||||
|
||||
void DiscardRegContentsIfCached(preg_t preg);
|
||||
void SetEmitter(Gen::XEmitter* emitter);
|
||||
|
||||
void Flush(FlushMode mode = FlushMode::All, BitSet32 regsToFlush = BitSet32::AllTrue(32));
|
||||
|
||||
void FlushLockX(Gen::X64Reg reg);
|
||||
void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2);
|
||||
|
||||
bool SanityCheck() const;
|
||||
void KillImmediate(preg_t preg, bool doLoad, bool makeDirty);
|
||||
|
||||
// TODO - instead of doload, use "read", "write"
|
||||
// read only will not set dirty flag
|
||||
void BindToRegister(preg_t preg, bool doLoad = true, bool makeDirty = true);
|
||||
void StoreFromRegister(preg_t preg, FlushMode mode = FlushMode::All);
|
||||
|
||||
const Gen::OpArg& R(preg_t preg) const;
|
||||
Gen::X64Reg RX(preg_t preg) const;
|
||||
|
||||
// Register locking.
|
||||
|
||||
// these are powerpc reg indices
|
||||
template <typename T>
|
||||
void Lock(T p) // TODO: Make private
|
||||
{
|
||||
m_regs[p].Lock();
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
void Lock(T first, Args... args)
|
||||
{
|
||||
Lock(first);
|
||||
Lock(args...);
|
||||
}
|
||||
|
||||
// these are x64 reg indices
|
||||
template <typename T>
|
||||
void LockX(T x)
|
||||
{
|
||||
if (m_xregs[x].IsLocked())
|
||||
PanicAlert("RegCache: x %i already locked!", x);
|
||||
m_xregs[x].Lock();
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
void LockX(T first, Args... args)
|
||||
{
|
||||
LockX(first);
|
||||
LockX(args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void UnlockX(T x)
|
||||
{
|
||||
if (!m_xregs[x].IsLocked())
|
||||
PanicAlert("RegCache: x %i already unlocked!", x);
|
||||
m_xregs[x].Unlock();
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
void UnlockX(T first, Args... args)
|
||||
{
|
||||
UnlockX(first);
|
||||
UnlockX(args...);
|
||||
}
|
||||
|
||||
void UnlockAll();
|
||||
void UnlockAllX();
|
||||
|
||||
bool IsFreeX(size_t xreg) const;
|
||||
|
||||
Gen::X64Reg GetFreeXReg();
|
||||
int NumFreeRegisters() const;
|
||||
|
||||
// New interface
|
||||
|
||||
template <typename... Ts>
|
||||
static void Realize(Ts&... rc)
|
||||
|
@ -238,15 +165,17 @@ public:
|
|||
RCOpArg BindOrImm(preg_t preg, RCMode mode);
|
||||
RCX64Reg Bind(preg_t preg, RCMode mode);
|
||||
RCX64Reg RevertableBind(preg_t preg, RCMode mode);
|
||||
RCX64Reg Scratch();
|
||||
RCX64Reg Scratch(Gen::X64Reg xr);
|
||||
|
||||
RCForkGuard Fork();
|
||||
void Flush(BitSet32 pregs = BitSet32::AllTrue(32));
|
||||
void Revert();
|
||||
void Commit();
|
||||
|
||||
bool IsAllUnlocked() const;
|
||||
|
||||
void PreloadRegisters(BitSet32 regs);
|
||||
void PreloadRegisters(BitSet32 pregs);
|
||||
BitSet32 RegistersInUse() const;
|
||||
|
||||
protected:
|
||||
|
@ -254,6 +183,7 @@ protected:
|
|||
friend class RCX64Reg;
|
||||
friend class RCForkGuard;
|
||||
|
||||
virtual Gen::OpArg GetDefaultLocation(preg_t preg) const = 0;
|
||||
virtual void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) = 0;
|
||||
virtual void LoadRegister(preg_t preg, Gen::X64Reg new_loc) = 0;
|
||||
|
||||
|
@ -263,14 +193,22 @@ protected:
|
|||
virtual BitSet32 CountRegsIn(preg_t preg, u32 lookahead) const = 0;
|
||||
|
||||
void FlushX(Gen::X64Reg reg);
|
||||
void DiscardRegContentsIfCached(preg_t preg);
|
||||
void BindToRegister(preg_t preg, bool doLoad = true, bool makeDirty = true);
|
||||
void StoreFromRegister(preg_t preg, FlushMode mode = FlushMode::Full);
|
||||
|
||||
Gen::X64Reg GetFreeXReg();
|
||||
|
||||
int NumFreeRegisters() const;
|
||||
float ScoreRegister(Gen::X64Reg xreg) const;
|
||||
|
||||
// New interface
|
||||
void NewLock(preg_t preg);
|
||||
void NewUnlock(preg_t preg);
|
||||
void NewLockX(Gen::X64Reg xr);
|
||||
void NewUnlockX(Gen::X64Reg xr);
|
||||
const Gen::OpArg& R(preg_t preg) const;
|
||||
Gen::X64Reg RX(preg_t preg) const;
|
||||
|
||||
void Lock(preg_t preg);
|
||||
void Unlock(preg_t preg);
|
||||
void LockX(Gen::X64Reg xr);
|
||||
void UnlockX(Gen::X64Reg xr);
|
||||
bool IsRealized(preg_t preg) const;
|
||||
void Realize(preg_t preg);
|
||||
|
||||
|
|
Loading…
Reference in New Issue