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();
|
fpr.Commit();
|
||||||
|
|
||||||
// If we have a register that will never be used again, flush it.
|
// If we have a register that will never be used again, flush it.
|
||||||
for (int j : ~op.gprInUse)
|
gpr.Flush(~op.gprInUse);
|
||||||
gpr.StoreFromRegister(j);
|
fpr.Flush(~op.fprInUse);
|
||||||
for (int j : ~op.fprInUse)
|
|
||||||
fpr.StoreFromRegister(j);
|
|
||||||
|
|
||||||
if (opinfo->flags & FL_LOADSTORE)
|
if (opinfo->flags & FL_LOADSTORE)
|
||||||
++js.numLoadStoreInst;
|
++js.numLoadStoreInst;
|
||||||
|
|
|
@ -116,7 +116,7 @@ void Jit64::HandleNaNs(UGeckoInstruction inst, X64Reg xmm_out, X64Reg xmm, X64Re
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// SSE2 fallback
|
// SSE2 fallback
|
||||||
RCX64Reg tmp = fpr.Scratch(fpr.GetFreeXReg());
|
RCX64Reg tmp = fpr.Scratch();
|
||||||
RegCache::Realize(tmp);
|
RegCache::Realize(tmp);
|
||||||
MOVAPD(clobber, R(xmm));
|
MOVAPD(clobber, R(xmm));
|
||||||
CMPPD(clobber, R(clobber), CMP_UNORD);
|
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)
|
if (needs_test)
|
||||||
{
|
{
|
||||||
TEST(32, arg, arg);
|
TEST(32, arg, arg);
|
||||||
|
arg.Unlock();
|
||||||
}
|
}
|
||||||
else
|
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.
|
// 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
|
// We don't want to do this if a test is needed though, because it would interrupt macro-op
|
||||||
// fusion.
|
// fusion.
|
||||||
for (int j : ~js.op->gprInUse)
|
|
||||||
gpr.StoreFromRegister(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
arg.Unlock();
|
arg.Unlock();
|
||||||
|
gpr.Flush(~js.op->gprInUse);
|
||||||
|
}
|
||||||
DoMergedBranchCondition();
|
DoMergedBranchCondition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -271,7 +271,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
|
||||||
X64Reg value = RSCRATCH2;
|
X64Reg value = RSCRATCH2;
|
||||||
RCOpArg Ra = inst.RA ? gpr.Use(inst.RA, RCMode::Read) : RCOpArg::Imm32(0);
|
RCOpArg Ra = inst.RA ? gpr.Use(inst.RA, RCMode::Read) : RCOpArg::Imm32(0);
|
||||||
RCOpArg Rb = gpr.Use(inst.RB, RCMode::Read);
|
RCOpArg Rb = gpr.Use(inst.RB, RCMode::Read);
|
||||||
RCX64Reg tmp = gpr.Scratch(gpr.GetFreeXReg());
|
RCX64Reg tmp = gpr.Scratch();
|
||||||
RegCache::Realize(Ra, Rb, tmp);
|
RegCache::Realize(Ra, Rb, tmp);
|
||||||
|
|
||||||
MOV_sum(32, addr, Ra, Rb);
|
MOV_sum(32, addr, Ra, Rb);
|
||||||
|
|
|
@ -101,7 +101,6 @@ public:
|
||||||
ASSERT(IsLocked());
|
ASSERT(IsLocked());
|
||||||
locked--;
|
locked--;
|
||||||
}
|
}
|
||||||
void UnlockAll() { locked = 0; } // TODO: Remove from final version
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Gen::OpArg default_location{};
|
Gen::OpArg default_location{};
|
||||||
|
@ -142,7 +141,6 @@ public:
|
||||||
ASSERT(IsLocked());
|
ASSERT(IsLocked());
|
||||||
locked--;
|
locked--;
|
||||||
}
|
}
|
||||||
void UnlockAll() { locked = 0; } // TODO: Remove from final version
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
preg_t ppcReg = static_cast<preg_t>(Gen::INVALID_REG);
|
preg_t ppcReg = static_cast<preg_t>(Gen::INVALID_REG);
|
||||||
|
|
|
@ -12,9 +12,9 @@ class FPURegCache final : public RegCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit FPURegCache(Jit64& jit);
|
explicit FPURegCache(Jit64& jit);
|
||||||
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
|
||||||
void StoreRegister(preg_t preg, const Gen::OpArg& newLoc) override;
|
void StoreRegister(preg_t preg, const Gen::OpArg& newLoc) override;
|
||||||
void LoadRegister(preg_t preg, Gen::X64Reg newLoc) override;
|
void LoadRegister(preg_t preg, Gen::X64Reg newLoc) override;
|
||||||
const Gen::X64Reg* GetAllocationOrder(size_t* count) const override;
|
const Gen::X64Reg* GetAllocationOrder(size_t* count) const override;
|
||||||
|
|
|
@ -12,10 +12,10 @@ class GPRRegCache final : public RegCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit GPRRegCache(Jit64& jit);
|
explicit GPRRegCache(Jit64& jit);
|
||||||
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
|
|
||||||
void SetImmediate32(preg_t preg, u32 imm_value, bool dirty = true);
|
void SetImmediate32(preg_t preg, u32 imm_value, bool dirty = true);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
|
||||||
void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) override;
|
void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) override;
|
||||||
void LoadRegister(preg_t preg, Gen::X64Reg new_loc) override;
|
void LoadRegister(preg_t preg, Gen::X64Reg new_loc) override;
|
||||||
const Gen::X64Reg* GetAllocationOrder(size_t* count) const 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)
|
RCOpArg::RCOpArg(RegCache* rc_, preg_t preg) : rc(rc_), contents(preg)
|
||||||
{
|
{
|
||||||
rc->NewLock(preg);
|
rc->Lock(preg);
|
||||||
}
|
}
|
||||||
|
|
||||||
RCOpArg::~RCOpArg()
|
RCOpArg::~RCOpArg()
|
||||||
|
@ -128,14 +128,14 @@ void RCOpArg::Unlock()
|
||||||
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
{
|
{
|
||||||
ASSERT(rc);
|
ASSERT(rc);
|
||||||
rc->NewUnlock(*preg);
|
rc->Unlock(*preg);
|
||||||
}
|
}
|
||||||
else if (const X64Reg* xr = std::get_if<X64Reg>(&contents))
|
else if (const X64Reg* xr = std::get_if<X64Reg>(&contents))
|
||||||
{
|
{
|
||||||
// If rc, we got this from an RCX64Reg.
|
// If rc, we got this from an RCX64Reg.
|
||||||
// If !rc, we got this from RCOpArg::R.
|
// If !rc, we got this from RCOpArg::R.
|
||||||
if (rc)
|
if (rc)
|
||||||
rc->NewUnlockX(*xr);
|
rc->UnlockX(*xr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -191,12 +191,12 @@ RCX64Reg::RCX64Reg() = default;
|
||||||
|
|
||||||
RCX64Reg::RCX64Reg(RegCache* rc_, preg_t preg) : rc(rc_), contents(preg)
|
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)
|
RCX64Reg::RCX64Reg(RegCache* rc_, X64Reg xr) : rc(rc_), contents(xr)
|
||||||
{
|
{
|
||||||
rc->NewLockX(xr);
|
rc->LockX(xr);
|
||||||
}
|
}
|
||||||
|
|
||||||
RCX64Reg::~RCX64Reg()
|
RCX64Reg::~RCX64Reg()
|
||||||
|
@ -251,12 +251,12 @@ void RCX64Reg::Unlock()
|
||||||
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
{
|
{
|
||||||
ASSERT(rc);
|
ASSERT(rc);
|
||||||
rc->NewUnlock(*preg);
|
rc->Unlock(*preg);
|
||||||
}
|
}
|
||||||
else if (const X64Reg* xr = std::get_if<X64Reg>(&contents))
|
else if (const X64Reg* xr = std::get_if<X64Reg>(&contents))
|
||||||
{
|
{
|
||||||
ASSERT(rc);
|
ASSERT(rc);
|
||||||
rc->NewUnlockX(*xr);
|
rc->UnlockX(*xr);
|
||||||
}
|
}
|
||||||
else
|
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)
|
void RegCache::SetEmitter(XEmitter* emitter)
|
||||||
{
|
{
|
||||||
m_emitter = 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
|
bool RegCache::SanityCheck() const
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_regs.size(); i++)
|
for (size_t i = 0; i < m_regs.size(); i++)
|
||||||
|
@ -389,21 +334,150 @@ bool RegCache::SanityCheck() const
|
||||||
return true;
|
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:
|
case PPCCachedReg::LocationType::Default:
|
||||||
|
break;
|
||||||
case PPCCachedReg::LocationType::SpeculativeImmediate:
|
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;
|
break;
|
||||||
case PPCCachedReg::LocationType::Bound:
|
case PPCCachedReg::LocationType::Bound:
|
||||||
if (makeDirty)
|
|
||||||
m_xregs[RX(preg)].MakeDirty();
|
|
||||||
break;
|
|
||||||
case PPCCachedReg::LocationType::Immediate:
|
case PPCCachedReg::LocationType::Immediate:
|
||||||
BindToRegister(preg, doLoad, makeDirty);
|
StoreFromRegister(i);
|
||||||
break;
|
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)
|
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);
|
X64Reg xr = RX(i);
|
||||||
doStore = m_xregs[xr].IsDirty();
|
doStore = m_xregs[xr].IsDirty();
|
||||||
if (mode == FlushMode::All)
|
if (mode == FlushMode::Full)
|
||||||
m_xregs[xr].SetFlushed();
|
m_xregs[xr].SetFlushed();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -468,39 +542,10 @@ void RegCache::StoreFromRegister(preg_t i, FlushMode mode)
|
||||||
|
|
||||||
if (doStore)
|
if (doStore)
|
||||||
StoreRegister(i, GetDefaultLocation(i));
|
StoreRegister(i, GetDefaultLocation(i));
|
||||||
if (mode == FlushMode::All)
|
if (mode == FlushMode::Full)
|
||||||
m_regs[i].SetFlushed();
|
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()
|
X64Reg RegCache::GetFreeXReg()
|
||||||
{
|
{
|
||||||
size_t aCount;
|
size_t aCount;
|
||||||
|
@ -556,16 +601,6 @@ int RegCache::NumFreeRegisters() const
|
||||||
return count;
|
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
|
// Estimate roughly how bad it would be to de-allocate this register. Higher score
|
||||||
// means more bad.
|
// means more bad.
|
||||||
float RegCache::ScoreRegister(X64Reg xreg) const
|
float RegCache::ScoreRegister(X64Reg xreg) const
|
||||||
|
@ -598,102 +633,23 @@ float RegCache::ScoreRegister(X64Reg xreg) const
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
RCOpArg RegCache::Use(preg_t preg, RCMode mode)
|
const OpArg& RegCache::R(preg_t preg) const
|
||||||
{
|
{
|
||||||
m_constraints[preg].AddUse(mode);
|
return m_regs[preg].Location();
|
||||||
return RCOpArg{this, preg};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RCOpArg RegCache::UseNoImm(preg_t preg, RCMode mode)
|
X64Reg RegCache::RX(preg_t preg) const
|
||||||
{
|
{
|
||||||
m_constraints[preg].AddUseNoImm(mode);
|
ASSERT_MSG(DYNA_REC, m_regs[preg].IsBound(), "Unbound register - %zu", preg);
|
||||||
return RCOpArg{this, preg};
|
return m_regs[preg].Location().GetSimpleReg();
|
||||||
}
|
}
|
||||||
|
|
||||||
RCOpArg RegCache::BindOrImm(preg_t preg, RCMode mode)
|
void RegCache::Lock(preg_t preg)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
m_regs[preg].Lock();
|
m_regs[preg].Lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::NewUnlock(preg_t preg)
|
void RegCache::Unlock(preg_t preg)
|
||||||
{
|
{
|
||||||
m_regs[preg].Unlock();
|
m_regs[preg].Unlock();
|
||||||
if (!m_regs[preg].IsLocked())
|
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();
|
m_xregs[xr].Lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::NewUnlockX(X64Reg xr)
|
void RegCache::UnlockX(X64Reg xr)
|
||||||
{
|
{
|
||||||
m_xregs[xr].Unlock();
|
m_xregs[xr].Unlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,89 +126,16 @@ class RegCache
|
||||||
public:
|
public:
|
||||||
enum class FlushMode
|
enum class FlushMode
|
||||||
{
|
{
|
||||||
All,
|
Full,
|
||||||
MaintainState,
|
MaintainState,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit RegCache(Jit64& jit);
|
explicit RegCache(Jit64& jit);
|
||||||
virtual ~RegCache() = default;
|
virtual ~RegCache() = default;
|
||||||
|
|
||||||
virtual Gen::OpArg GetDefaultLocation(preg_t preg) const = 0;
|
|
||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
void DiscardRegContentsIfCached(preg_t preg);
|
|
||||||
void SetEmitter(Gen::XEmitter* emitter);
|
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;
|
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>
|
template <typename... Ts>
|
||||||
static void Realize(Ts&... rc)
|
static void Realize(Ts&... rc)
|
||||||
|
@ -238,15 +165,17 @@ public:
|
||||||
RCOpArg BindOrImm(preg_t preg, RCMode mode);
|
RCOpArg BindOrImm(preg_t preg, RCMode mode);
|
||||||
RCX64Reg Bind(preg_t preg, RCMode mode);
|
RCX64Reg Bind(preg_t preg, RCMode mode);
|
||||||
RCX64Reg RevertableBind(preg_t preg, RCMode mode);
|
RCX64Reg RevertableBind(preg_t preg, RCMode mode);
|
||||||
|
RCX64Reg Scratch();
|
||||||
RCX64Reg Scratch(Gen::X64Reg xr);
|
RCX64Reg Scratch(Gen::X64Reg xr);
|
||||||
|
|
||||||
RCForkGuard Fork();
|
RCForkGuard Fork();
|
||||||
|
void Flush(BitSet32 pregs = BitSet32::AllTrue(32));
|
||||||
void Revert();
|
void Revert();
|
||||||
void Commit();
|
void Commit();
|
||||||
|
|
||||||
bool IsAllUnlocked() const;
|
bool IsAllUnlocked() const;
|
||||||
|
|
||||||
void PreloadRegisters(BitSet32 regs);
|
void PreloadRegisters(BitSet32 pregs);
|
||||||
BitSet32 RegistersInUse() const;
|
BitSet32 RegistersInUse() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -254,6 +183,7 @@ protected:
|
||||||
friend class RCX64Reg;
|
friend class RCX64Reg;
|
||||||
friend class RCForkGuard;
|
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 StoreRegister(preg_t preg, const Gen::OpArg& new_loc) = 0;
|
||||||
virtual void LoadRegister(preg_t preg, Gen::X64Reg 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;
|
virtual BitSet32 CountRegsIn(preg_t preg, u32 lookahead) const = 0;
|
||||||
|
|
||||||
void FlushX(Gen::X64Reg reg);
|
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;
|
float ScoreRegister(Gen::X64Reg xreg) const;
|
||||||
|
|
||||||
// New interface
|
const Gen::OpArg& R(preg_t preg) const;
|
||||||
void NewLock(preg_t preg);
|
Gen::X64Reg RX(preg_t preg) const;
|
||||||
void NewUnlock(preg_t preg);
|
|
||||||
void NewLockX(Gen::X64Reg xr);
|
void Lock(preg_t preg);
|
||||||
void NewUnlockX(Gen::X64Reg xr);
|
void Unlock(preg_t preg);
|
||||||
|
void LockX(Gen::X64Reg xr);
|
||||||
|
void UnlockX(Gen::X64Reg xr);
|
||||||
bool IsRealized(preg_t preg) const;
|
bool IsRealized(preg_t preg) const;
|
||||||
void Realize(preg_t preg);
|
void Realize(preg_t preg);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue