mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
JitRegCache: New interface
This commit is contained in:
@ -2,11 +2,14 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/x64Emitter.h"
|
#include "Common/x64Emitter.h"
|
||||||
|
#include "Core/PowerPC/Jit64/RegCache/RCMode.h"
|
||||||
|
|
||||||
using preg_t = size_t;
|
using preg_t = size_t;
|
||||||
|
|
||||||
@ -125,3 +128,79 @@ private:
|
|||||||
bool dirty = false;
|
bool dirty = false;
|
||||||
size_t locked = 0;
|
size_t locked = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RCConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool IsRealized() const { return realized; }
|
||||||
|
|
||||||
|
bool ShouldBind() const { return bind; }
|
||||||
|
bool ShouldLoad() const { return read; }
|
||||||
|
bool ShouldDirty() const { return write; }
|
||||||
|
bool ShouldKillImmediate() const { return kill_imm; }
|
||||||
|
|
||||||
|
void Realized() { realized = true; }
|
||||||
|
void RealizedBound()
|
||||||
|
{
|
||||||
|
realized = true;
|
||||||
|
bind = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddUse(RCMode mode) { AddConstraint(false, mode, false); }
|
||||||
|
void AddUseNoImm(RCMode mode) { AddConstraint(false, mode, true); }
|
||||||
|
void AddBind(RCMode mode) { AddConstraint(true, mode, false); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AddConstraint(bool should_bind, RCMode mode, bool should_kill_imm)
|
||||||
|
{
|
||||||
|
if (realized)
|
||||||
|
{
|
||||||
|
ASSERT(IsCompatible(should_bind, mode, should_kill_imm));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_bind)
|
||||||
|
bind = true;
|
||||||
|
|
||||||
|
if (should_kill_imm)
|
||||||
|
kill_imm = true;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case RCMode::Read:
|
||||||
|
read = true;
|
||||||
|
break;
|
||||||
|
case RCMode::Write:
|
||||||
|
write = true;
|
||||||
|
break;
|
||||||
|
case RCMode::ReadWrite:
|
||||||
|
read = true;
|
||||||
|
write = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsCompatible(bool should_bind, RCMode mode, bool should_kill_imm)
|
||||||
|
{
|
||||||
|
if (should_bind && !bind)
|
||||||
|
return false;
|
||||||
|
if (should_kill_imm && !kill_imm)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case RCMode::Read:
|
||||||
|
return read;
|
||||||
|
case RCMode::Write:
|
||||||
|
return write;
|
||||||
|
case RCMode::ReadWrite:
|
||||||
|
return read && write;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool realized = false;
|
||||||
|
bool bind = false;
|
||||||
|
bool write = false;
|
||||||
|
bool read = false;
|
||||||
|
bool kill_imm = false;
|
||||||
|
};
|
||||||
|
@ -8,19 +8,252 @@
|
|||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/BitSet.h"
|
#include "Common/BitSet.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
|
#include "Common/VariantUtil.h"
|
||||||
#include "Common/x64Emitter.h"
|
#include "Common/x64Emitter.h"
|
||||||
#include "Core/PowerPC/Jit64/Jit.h"
|
#include "Core/PowerPC/Jit64/Jit.h"
|
||||||
#include "Core/PowerPC/Jit64/RegCache/CachedReg.h"
|
#include "Core/PowerPC/Jit64/RegCache/CachedReg.h"
|
||||||
|
#include "Core/PowerPC/Jit64/RegCache/RCMode.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
using namespace PowerPC;
|
using namespace PowerPC;
|
||||||
|
|
||||||
|
RCOpArg RCOpArg::Imm32(u32 imm)
|
||||||
|
{
|
||||||
|
return RCOpArg{imm};
|
||||||
|
}
|
||||||
|
|
||||||
|
RCOpArg RCOpArg::R(X64Reg xr)
|
||||||
|
{
|
||||||
|
return RCOpArg{xr};
|
||||||
|
}
|
||||||
|
|
||||||
|
RCOpArg::RCOpArg() = default;
|
||||||
|
|
||||||
|
RCOpArg::RCOpArg(u32 imm) : rc(nullptr), contents(imm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RCOpArg::RCOpArg(X64Reg xr) : rc(nullptr), contents(xr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RCOpArg::RCOpArg(RegCache* rc_, preg_t preg) : rc(rc_), contents(preg)
|
||||||
|
{
|
||||||
|
rc->NewLock(preg);
|
||||||
|
}
|
||||||
|
|
||||||
|
RCOpArg::~RCOpArg()
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
RCOpArg::RCOpArg(RCOpArg&& other) noexcept
|
||||||
|
: rc(std::exchange(other.rc, nullptr)),
|
||||||
|
contents(std::exchange(other.contents, std::monostate{}))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RCOpArg& RCOpArg::operator=(RCOpArg&& other) noexcept
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
rc = std::exchange(other.rc, nullptr);
|
||||||
|
contents = std::exchange(other.contents, std::monostate{});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCOpArg::RCOpArg(RCX64Reg&& other) noexcept
|
||||||
|
: rc(std::exchange(other.rc, nullptr)),
|
||||||
|
contents(VariantCast(std::exchange(other.contents, std::monostate{})))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RCOpArg& RCOpArg::operator=(RCX64Reg&& other) noexcept
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
rc = std::exchange(other.rc, nullptr);
|
||||||
|
contents = VariantCast(std::exchange(other.contents, std::monostate{}));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCOpArg::Realize()
|
||||||
|
{
|
||||||
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
|
{
|
||||||
|
rc->Realize(*preg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpArg RCOpArg::Location() const
|
||||||
|
{
|
||||||
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
|
{
|
||||||
|
ASSERT(rc->IsRealized(*preg));
|
||||||
|
return rc->R(*preg);
|
||||||
|
}
|
||||||
|
else if (const X64Reg* xr = std::get_if<X64Reg>(&contents))
|
||||||
|
{
|
||||||
|
return Gen::R(*xr);
|
||||||
|
}
|
||||||
|
else if (const u32* imm = std::get_if<u32>(&contents))
|
||||||
|
{
|
||||||
|
return Gen::Imm32(*imm);
|
||||||
|
}
|
||||||
|
ASSERT(false);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCOpArg::Unlock()
|
||||||
|
{
|
||||||
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
|
{
|
||||||
|
ASSERT(rc);
|
||||||
|
rc->NewUnlock(*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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(!rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = nullptr;
|
||||||
|
contents = std::monostate{};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RCOpArg::IsImm() const
|
||||||
|
{
|
||||||
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
|
{
|
||||||
|
return rc->R(*preg).IsImm();
|
||||||
|
}
|
||||||
|
else if (std::holds_alternative<u32>(contents))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 RCOpArg::SImm32() const
|
||||||
|
{
|
||||||
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
|
{
|
||||||
|
return rc->R(*preg).SImm32();
|
||||||
|
}
|
||||||
|
else if (const u32* imm = std::get_if<u32>(&contents))
|
||||||
|
{
|
||||||
|
return static_cast<s32>(*imm);
|
||||||
|
}
|
||||||
|
ASSERT(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 RCOpArg::Imm32() const
|
||||||
|
{
|
||||||
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
|
{
|
||||||
|
return rc->R(*preg).Imm32();
|
||||||
|
}
|
||||||
|
else if (const u32* imm = std::get_if<u32>(&contents))
|
||||||
|
{
|
||||||
|
return *imm;
|
||||||
|
}
|
||||||
|
ASSERT(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCX64Reg::RCX64Reg() = default;
|
||||||
|
|
||||||
|
RCX64Reg::RCX64Reg(RegCache* rc_, preg_t preg) : rc(rc_), contents(preg)
|
||||||
|
{
|
||||||
|
rc->NewLock(preg);
|
||||||
|
}
|
||||||
|
|
||||||
|
RCX64Reg::RCX64Reg(RegCache* rc_, X64Reg xr) : rc(rc_), contents(xr)
|
||||||
|
{
|
||||||
|
rc->NewLockX(xr);
|
||||||
|
}
|
||||||
|
|
||||||
|
RCX64Reg::~RCX64Reg()
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
RCX64Reg::RCX64Reg(RCX64Reg&& other) noexcept
|
||||||
|
: rc(std::exchange(other.rc, nullptr)),
|
||||||
|
contents(std::exchange(other.contents, std::monostate{}))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RCX64Reg& RCX64Reg::operator=(RCX64Reg&& other) noexcept
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
rc = std::exchange(other.rc, nullptr);
|
||||||
|
contents = std::exchange(other.contents, std::monostate{});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCX64Reg::Realize()
|
||||||
|
{
|
||||||
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
|
{
|
||||||
|
rc->Realize(*preg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RCX64Reg::operator X64Reg() const &
|
||||||
|
{
|
||||||
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
|
{
|
||||||
|
ASSERT(rc->IsRealized(*preg));
|
||||||
|
return rc->RX(*preg);
|
||||||
|
}
|
||||||
|
else if (const X64Reg* xr = std::get_if<X64Reg>(&contents))
|
||||||
|
{
|
||||||
|
return *xr;
|
||||||
|
}
|
||||||
|
ASSERT(false);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
RCX64Reg::operator OpArg() const &
|
||||||
|
{
|
||||||
|
return Gen::R(RCX64Reg::operator X64Reg());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCX64Reg::Unlock()
|
||||||
|
{
|
||||||
|
if (const preg_t* preg = std::get_if<preg_t>(&contents))
|
||||||
|
{
|
||||||
|
ASSERT(rc);
|
||||||
|
rc->NewUnlock(*preg);
|
||||||
|
}
|
||||||
|
else if (const X64Reg* xr = std::get_if<X64Reg>(&contents))
|
||||||
|
{
|
||||||
|
ASSERT(rc);
|
||||||
|
rc->NewUnlockX(*xr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(!rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = nullptr;
|
||||||
|
contents = std::monostate{};
|
||||||
|
}
|
||||||
|
|
||||||
RegCache::RegCache(Jit64& jit) : m_jit{jit}
|
RegCache::RegCache(Jit64& jit) : m_jit{jit}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -214,6 +447,7 @@ void RegCache::UnlockAll()
|
|||||||
{
|
{
|
||||||
for (auto& reg : m_regs)
|
for (auto& reg : m_regs)
|
||||||
reg.UnlockAll();
|
reg.UnlockAll();
|
||||||
|
m_constraints.fill({});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::UnlockAllX()
|
void RegCache::UnlockAllX()
|
||||||
@ -323,3 +557,96 @@ float RegCache::ScoreRegister(X64Reg xreg) const
|
|||||||
|
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCOpArg RegCache::Use(preg_t preg, RCMode mode)
|
||||||
|
{
|
||||||
|
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};
|
||||||
|
}
|
||||||
|
|
||||||
|
RCX64Reg RegCache::Bind(preg_t preg, RCMode mode)
|
||||||
|
{
|
||||||
|
m_constraints[preg].AddBind(mode);
|
||||||
|
return RCX64Reg{this, preg};
|
||||||
|
}
|
||||||
|
|
||||||
|
RCX64Reg RegCache::Scratch(X64Reg xr)
|
||||||
|
{
|
||||||
|
FlushX(xr);
|
||||||
|
return RCX64Reg{this, xr};
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegCache::NewLock(preg_t preg)
|
||||||
|
{
|
||||||
|
m_regs[preg].Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegCache::NewUnlock(preg_t preg)
|
||||||
|
{
|
||||||
|
m_regs[preg].Unlock();
|
||||||
|
if (!m_regs[preg].IsLocked())
|
||||||
|
{
|
||||||
|
// Fully unlocked, reset realization state.
|
||||||
|
m_constraints[preg] = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegCache::NewLockX(X64Reg xr)
|
||||||
|
{
|
||||||
|
m_xregs[xr].Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegCache::NewUnlockX(X64Reg xr)
|
||||||
|
{
|
||||||
|
m_xregs[xr].Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RegCache::IsRealized(preg_t preg) const
|
||||||
|
{
|
||||||
|
return m_constraints[preg].IsRealized();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegCache::Realize(preg_t preg)
|
||||||
|
{
|
||||||
|
if (m_constraints[preg].IsRealized())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const bool load = m_constraints[preg].ShouldLoad();
|
||||||
|
const bool dirty = m_constraints[preg].ShouldDirty();
|
||||||
|
const bool kill_imm = m_constraints[preg].ShouldKillImmediate();
|
||||||
|
|
||||||
|
const auto do_bind = [&] {
|
||||||
|
BindToRegister(preg, load, dirty);
|
||||||
|
m_constraints[preg].RealizedBound();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (m_constraints[preg].ShouldBind())
|
||||||
|
{
|
||||||
|
do_bind();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_regs[preg].GetLocationType())
|
||||||
|
{
|
||||||
|
case PPCCachedReg::LocationType::Default:
|
||||||
|
break;
|
||||||
|
case PPCCachedReg::LocationType::Bound:
|
||||||
|
do_bind();
|
||||||
|
break;
|
||||||
|
case PPCCachedReg::LocationType::Immediate:
|
||||||
|
case PPCCachedReg::LocationType::SpeculativeImmediate:
|
||||||
|
if (dirty || kill_imm)
|
||||||
|
{
|
||||||
|
do_bind();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_constraints[preg].Realized();
|
||||||
|
}
|
||||||
|
@ -7,15 +7,93 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include "Common/x64Emitter.h"
|
#include "Common/x64Emitter.h"
|
||||||
#include "Core/PowerPC/PPCAnalyst.h"
|
|
||||||
#include "Core/PowerPC/Jit64/RegCache/CachedReg.h"
|
#include "Core/PowerPC/Jit64/RegCache/CachedReg.h"
|
||||||
|
#include "Core/PowerPC/PPCAnalyst.h"
|
||||||
|
|
||||||
class Jit64;
|
class Jit64;
|
||||||
|
enum class RCMode;
|
||||||
|
|
||||||
|
class RCOpArg;
|
||||||
|
class RCX64Reg;
|
||||||
|
class RegCache;
|
||||||
|
|
||||||
using preg_t = size_t;
|
using preg_t = size_t;
|
||||||
|
|
||||||
|
class RCOpArg
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static RCOpArg Imm32(u32 imm);
|
||||||
|
static RCOpArg R(Gen::X64Reg xr);
|
||||||
|
RCOpArg();
|
||||||
|
~RCOpArg();
|
||||||
|
RCOpArg(RCOpArg&&) noexcept;
|
||||||
|
RCOpArg& operator=(RCOpArg&&) noexcept;
|
||||||
|
|
||||||
|
RCOpArg(RCX64Reg&&) noexcept;
|
||||||
|
RCOpArg& operator=(RCX64Reg&&) noexcept;
|
||||||
|
|
||||||
|
RCOpArg(const RCOpArg&) = delete;
|
||||||
|
RCOpArg& operator=(const RCOpArg&) = delete;
|
||||||
|
|
||||||
|
void Realize();
|
||||||
|
Gen::OpArg Location() const;
|
||||||
|
operator Gen::OpArg() const & { return Location(); }
|
||||||
|
operator Gen::OpArg() const && = delete;
|
||||||
|
bool IsSimpleReg() const { return Location().IsSimpleReg(); }
|
||||||
|
bool IsSimpleReg(Gen::X64Reg reg) const { return Location().IsSimpleReg(reg); }
|
||||||
|
Gen::X64Reg GetSimpleReg() const { return Location().GetSimpleReg(); }
|
||||||
|
|
||||||
|
void Unlock();
|
||||||
|
|
||||||
|
bool IsImm() const;
|
||||||
|
s32 SImm32() const;
|
||||||
|
u32 Imm32() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class RegCache;
|
||||||
|
|
||||||
|
explicit RCOpArg(u32 imm);
|
||||||
|
explicit RCOpArg(Gen::X64Reg xr);
|
||||||
|
RCOpArg(RegCache* rc_, preg_t preg);
|
||||||
|
|
||||||
|
RegCache* rc = nullptr;
|
||||||
|
std::variant<std::monostate, Gen::X64Reg, u32, preg_t> contents;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RCX64Reg
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RCX64Reg();
|
||||||
|
~RCX64Reg();
|
||||||
|
RCX64Reg(RCX64Reg&&) noexcept;
|
||||||
|
RCX64Reg& operator=(RCX64Reg&&) noexcept;
|
||||||
|
|
||||||
|
RCX64Reg(const RCX64Reg&) = delete;
|
||||||
|
RCX64Reg& operator=(const RCX64Reg&) = delete;
|
||||||
|
|
||||||
|
void Realize();
|
||||||
|
operator Gen::OpArg() const &;
|
||||||
|
operator Gen::X64Reg() const &;
|
||||||
|
operator Gen::OpArg() const && = delete;
|
||||||
|
operator Gen::X64Reg() const && = delete;
|
||||||
|
|
||||||
|
void Unlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class RegCache;
|
||||||
|
friend class RCOpArg;
|
||||||
|
|
||||||
|
RCX64Reg(RegCache* rc_, preg_t preg);
|
||||||
|
RCX64Reg(RegCache* rc_, Gen::X64Reg xr);
|
||||||
|
|
||||||
|
RegCache* rc = nullptr;
|
||||||
|
std::variant<std::monostate, Gen::X64Reg, preg_t> contents;
|
||||||
|
};
|
||||||
|
|
||||||
class RegCache
|
class RegCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -57,7 +135,7 @@ public:
|
|||||||
|
|
||||||
// these are powerpc reg indices
|
// these are powerpc reg indices
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Lock(T p)
|
void Lock(T p) // TODO: Make private
|
||||||
{
|
{
|
||||||
m_regs[p].Lock();
|
m_regs[p].Lock();
|
||||||
}
|
}
|
||||||
@ -105,7 +183,40 @@ public:
|
|||||||
Gen::X64Reg GetFreeXReg();
|
Gen::X64Reg GetFreeXReg();
|
||||||
int NumFreeRegisters() const;
|
int NumFreeRegisters() const;
|
||||||
|
|
||||||
|
// New interface
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
static void Realize(Ts&... rc)
|
||||||
|
{
|
||||||
|
static_assert(((std::is_same<Ts, RCOpArg>() || std::is_same<Ts, RCX64Reg>()) && ...));
|
||||||
|
(rc.Realize(), ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
static void Unlock(Ts&... rc)
|
||||||
|
{
|
||||||
|
static_assert(((std::is_same<Ts, RCOpArg>() || std::is_same<Ts, RCX64Reg>()) && ...));
|
||||||
|
(rc.Unlock(), ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
bool IsImm(Args... pregs) const
|
||||||
|
{
|
||||||
|
static_assert(sizeof...(pregs) > 0);
|
||||||
|
return (R(pregs).IsImm() && ...);
|
||||||
|
}
|
||||||
|
u32 Imm32(preg_t preg) const { return R(preg).Imm32(); }
|
||||||
|
s32 SImm32(preg_t preg) const { return R(preg).SImm32(); }
|
||||||
|
|
||||||
|
RCOpArg Use(preg_t preg, RCMode mode);
|
||||||
|
RCOpArg UseNoImm(preg_t preg, RCMode mode);
|
||||||
|
RCX64Reg Bind(preg_t preg, RCMode mode);
|
||||||
|
RCX64Reg Scratch(Gen::X64Reg xr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class RCOpArg;
|
||||||
|
friend class RCX64Reg;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -118,8 +229,17 @@ protected:
|
|||||||
|
|
||||||
float ScoreRegister(Gen::X64Reg xreg) 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);
|
||||||
|
bool IsRealized(preg_t preg) const;
|
||||||
|
void Realize(preg_t preg);
|
||||||
|
|
||||||
Jit64& m_jit;
|
Jit64& m_jit;
|
||||||
std::array<PPCCachedReg, 32> m_regs;
|
std::array<PPCCachedReg, 32> m_regs;
|
||||||
std::array<X64CachedReg, NUM_XREGS> m_xregs;
|
std::array<X64CachedReg, NUM_XREGS> m_xregs;
|
||||||
|
std::array<RCConstraint, 32> m_constraints;
|
||||||
Gen::XEmitter* m_emitter = nullptr;
|
Gen::XEmitter* m_emitter = nullptr;
|
||||||
};
|
};
|
||||||
|
12
Source/Core/Core/PowerPC/Jit64/RegCache/RCMode.h
Normal file
12
Source/Core/Core/PowerPC/Jit64/RegCache/RCMode.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2018 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class RCMode
|
||||||
|
{
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
ReadWrite,
|
||||||
|
};
|
Reference in New Issue
Block a user