mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-14 00:09:24 +01:00
JitRegCache: Add revertable binds
This commit is contained in:
parent
16f8b7413d
commit
590ec866b0
@ -41,6 +41,8 @@ public:
|
|||||||
{
|
{
|
||||||
if (!away)
|
if (!away)
|
||||||
{
|
{
|
||||||
|
ASSERT(!revertable);
|
||||||
|
|
||||||
if (location.IsImm())
|
if (location.IsImm())
|
||||||
return LocationType::SpeculativeImmediate;
|
return LocationType::SpeculativeImmediate;
|
||||||
|
|
||||||
@ -63,6 +65,7 @@ public:
|
|||||||
|
|
||||||
void SetFlushed()
|
void SetFlushed()
|
||||||
{
|
{
|
||||||
|
ASSERT(!revertable);
|
||||||
away = false;
|
away = false;
|
||||||
location = default_location;
|
location = default_location;
|
||||||
}
|
}
|
||||||
@ -73,6 +76,24 @@ public:
|
|||||||
location = Gen::Imm32(imm32);
|
location = Gen::Imm32(imm32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsRevertable() const { return revertable; }
|
||||||
|
void SetRevertable()
|
||||||
|
{
|
||||||
|
ASSERT(IsBound());
|
||||||
|
revertable = true;
|
||||||
|
}
|
||||||
|
void SetRevert()
|
||||||
|
{
|
||||||
|
ASSERT(revertable);
|
||||||
|
revertable = false;
|
||||||
|
SetFlushed();
|
||||||
|
}
|
||||||
|
void SetCommit()
|
||||||
|
{
|
||||||
|
ASSERT(revertable);
|
||||||
|
revertable = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsLocked() const { return locked > 0; }
|
bool IsLocked() const { return locked > 0; }
|
||||||
void Lock() { locked++; }
|
void Lock() { locked++; }
|
||||||
void Unlock()
|
void Unlock()
|
||||||
@ -86,6 +107,7 @@ private:
|
|||||||
Gen::OpArg default_location{};
|
Gen::OpArg default_location{};
|
||||||
Gen::OpArg location{};
|
Gen::OpArg location{};
|
||||||
bool away = false; // value not in source register
|
bool away = false; // value not in source register
|
||||||
|
bool revertable = false;
|
||||||
size_t locked = 0;
|
size_t locked = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,6 +161,7 @@ public:
|
|||||||
bool ShouldLoad() const { return read; }
|
bool ShouldLoad() const { return read; }
|
||||||
bool ShouldDirty() const { return write; }
|
bool ShouldDirty() const { return write; }
|
||||||
bool ShouldKillImmediate() const { return kill_imm; }
|
bool ShouldKillImmediate() const { return kill_imm; }
|
||||||
|
bool ShouldBeRevertable() const { return revertable; }
|
||||||
|
|
||||||
void Realized() { realized = true; }
|
void Realized() { realized = true; }
|
||||||
void RealizedBound()
|
void RealizedBound()
|
||||||
@ -147,16 +170,17 @@ public:
|
|||||||
bind = true;
|
bind = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddUse(RCMode mode) { AddConstraint(false, mode, false); }
|
void AddUse(RCMode mode) { AddConstraint(false, mode, false, false); }
|
||||||
void AddUseNoImm(RCMode mode) { AddConstraint(false, mode, true); }
|
void AddUseNoImm(RCMode mode) { AddConstraint(false, mode, true, false); }
|
||||||
void AddBind(RCMode mode) { AddConstraint(true, mode, false); }
|
void AddBind(RCMode mode) { AddConstraint(true, mode, false, false); }
|
||||||
|
void AddRevertableBind(RCMode mode) { AddConstraint(true, mode, false, true); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AddConstraint(bool should_bind, RCMode mode, bool should_kill_imm)
|
void AddConstraint(bool should_bind, RCMode mode, bool should_kill_imm, bool should_revertable)
|
||||||
{
|
{
|
||||||
if (realized)
|
if (realized)
|
||||||
{
|
{
|
||||||
ASSERT(IsCompatible(should_bind, mode, should_kill_imm));
|
ASSERT(IsCompatible(should_bind, mode, should_kill_imm, should_revertable));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +190,9 @@ private:
|
|||||||
if (should_kill_imm)
|
if (should_kill_imm)
|
||||||
kill_imm = true;
|
kill_imm = true;
|
||||||
|
|
||||||
|
if (should_revertable)
|
||||||
|
revertable = true;
|
||||||
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case RCMode::Read:
|
case RCMode::Read:
|
||||||
@ -181,12 +208,14 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsCompatible(bool should_bind, RCMode mode, bool should_kill_imm)
|
bool IsCompatible(bool should_bind, RCMode mode, bool should_kill_imm, bool should_revertable)
|
||||||
{
|
{
|
||||||
if (should_bind && !bind)
|
if (should_bind && !bind)
|
||||||
return false;
|
return false;
|
||||||
if (should_kill_imm && !kill_imm)
|
if (should_kill_imm && !kill_imm)
|
||||||
return false;
|
return false;
|
||||||
|
if (should_revertable && !revertable)
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
@ -204,4 +233,5 @@ private:
|
|||||||
bool write = false;
|
bool write = false;
|
||||||
bool read = false;
|
bool read = false;
|
||||||
bool kill_imm = false;
|
bool kill_imm = false;
|
||||||
|
bool revertable = false;
|
||||||
};
|
};
|
||||||
|
@ -328,6 +328,7 @@ void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush)
|
|||||||
{
|
{
|
||||||
ASSERT_MSG(DYNA_REC, !m_regs[i].IsLocked(), "Someone forgot to unlock PPC reg %u (X64 reg %i).",
|
ASSERT_MSG(DYNA_REC, !m_regs[i].IsLocked(), "Someone forgot to unlock PPC reg %u (X64 reg %i).",
|
||||||
i, RX(i));
|
i, RX(i));
|
||||||
|
ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction is in progress!");
|
||||||
|
|
||||||
switch (m_regs[i].GetLocationType())
|
switch (m_regs[i].GetLocationType())
|
||||||
{
|
{
|
||||||
@ -373,7 +374,7 @@ bool RegCache::SanityCheck() const
|
|||||||
break;
|
break;
|
||||||
case PPCCachedReg::LocationType::Bound:
|
case PPCCachedReg::LocationType::Bound:
|
||||||
{
|
{
|
||||||
if (m_regs[i].IsLocked())
|
if (m_regs[i].IsLocked() || m_regs[i].IsRevertable())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Gen::X64Reg xr = m_regs[i].Location().GetSimpleReg();
|
Gen::X64Reg xr = m_regs[i].Location().GetSimpleReg();
|
||||||
@ -413,6 +414,7 @@ void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty)
|
|||||||
|
|
||||||
ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsDirty(), "Xreg %i already dirty", xr);
|
ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsDirty(), "Xreg %i already dirty", xr);
|
||||||
ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsLocked(), "GetFreeXReg returned locked register");
|
ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsLocked(), "GetFreeXReg returned locked register");
|
||||||
|
ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Invalid transaction state");
|
||||||
|
|
||||||
m_xregs[xr].SetBoundTo(i, makeDirty || m_regs[i].IsAway());
|
m_xregs[xr].SetBoundTo(i, makeDirty || m_regs[i].IsAway());
|
||||||
|
|
||||||
@ -441,6 +443,9 @@ void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty)
|
|||||||
|
|
||||||
void RegCache::StoreFromRegister(preg_t i, FlushMode mode)
|
void RegCache::StoreFromRegister(preg_t i, FlushMode mode)
|
||||||
{
|
{
|
||||||
|
// When a transaction is in progress, allowing the store would overwrite the old value.
|
||||||
|
ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction is in progress!");
|
||||||
|
|
||||||
bool doStore = false;
|
bool doStore = false;
|
||||||
|
|
||||||
switch (m_regs[i].GetLocationType())
|
switch (m_regs[i].GetLocationType())
|
||||||
@ -611,6 +616,18 @@ RCX64Reg RegCache::Bind(preg_t preg, RCMode mode)
|
|||||||
return RCX64Reg{this, preg};
|
return RCX64Reg{this, preg};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCX64Reg RegCache::BindOrImm(preg_t preg, RCMode mode)
|
||||||
|
{
|
||||||
|
m_constraints[preg].AddBindOrImm(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)
|
RCX64Reg RegCache::Scratch(X64Reg xr)
|
||||||
{
|
{
|
||||||
FlushX(xr);
|
FlushX(xr);
|
||||||
@ -622,6 +639,26 @@ RCForkGuard RegCache::Fork()
|
|||||||
return RCForkGuard{*this};
|
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
|
bool RegCache::IsAllUnlocked() const
|
||||||
{
|
{
|
||||||
return std::none_of(m_regs.begin(), m_regs.end(), [](const auto& r){ return r.IsLocked(); }) &&
|
return std::none_of(m_regs.begin(), m_regs.end(), [](const auto& r){ return r.IsLocked(); }) &&
|
||||||
@ -673,6 +710,14 @@ void RegCache::Realize(preg_t preg)
|
|||||||
m_constraints[preg].RealizedBound();
|
m_constraints[preg].RealizedBound();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (m_constraints[preg].ShouldBeRevertable())
|
||||||
|
{
|
||||||
|
StoreFromRegister(preg, FlushMode::MaintainState);
|
||||||
|
do_bind();
|
||||||
|
m_regs[preg].SetRevertable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_constraints[preg].ShouldBind())
|
if (m_constraints[preg].ShouldBind())
|
||||||
{
|
{
|
||||||
do_bind();
|
do_bind();
|
||||||
|
@ -235,9 +235,12 @@ public:
|
|||||||
RCOpArg Use(preg_t preg, RCMode mode);
|
RCOpArg Use(preg_t preg, RCMode mode);
|
||||||
RCOpArg UseNoImm(preg_t preg, RCMode mode);
|
RCOpArg UseNoImm(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 Scratch(Gen::X64Reg xr);
|
RCX64Reg Scratch(Gen::X64Reg xr);
|
||||||
|
|
||||||
RCForkGuard Fork();
|
RCForkGuard Fork();
|
||||||
|
void Revert();
|
||||||
|
void Commit();
|
||||||
|
|
||||||
bool IsAllUnlocked() const;
|
bool IsAllUnlocked() const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user