mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #4535 from lioncash/regcache
Jit64: Make register caches not rely on the global jit variable
This commit is contained in:
@@ -196,6 +196,8 @@ if(_M_X86)
|
||||
PowerPC/Jit64IL/IR_X86.cpp
|
||||
PowerPC/Jit64IL/JitIL.cpp
|
||||
PowerPC/Jit64IL/JitIL_Tables.cpp
|
||||
PowerPC/Jit64/FPURegCache.cpp
|
||||
PowerPC/Jit64/GPRRegCache.cpp
|
||||
PowerPC/Jit64/Jit64_Tables.cpp
|
||||
PowerPC/Jit64/JitAsm.cpp
|
||||
PowerPC/Jit64/Jit_Branch.cpp
|
||||
|
||||
@@ -225,6 +225,8 @@
|
||||
<ClCompile Include="PowerPC\Jit64IL\IR_X86.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64IL\JitIL.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64IL\JitIL_Tables.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\FPURegCache.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\GPRRegCache.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\Jit.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\Jit64_Tables.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\JitAsm.cpp" />
|
||||
@@ -427,6 +429,8 @@
|
||||
<ClInclude Include="PowerPC\Interpreter\Interpreter_Tables.h" />
|
||||
<ClInclude Include="PowerPC\Jit64IL\JitIL.h" />
|
||||
<ClInclude Include="PowerPC\Jit64IL\JitIL_Tables.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\FPURegCache.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\GPRRegCache.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\Jit.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\Jit64_Tables.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\JitAsm.h" />
|
||||
|
||||
@@ -666,6 +666,12 @@
|
||||
<ClCompile Include="PowerPC\Jit64IL\JitIL_Tables.cpp">
|
||||
<Filter>PowerPC\JitIL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64\FPURegCache.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64\GPRRegCache.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64\Jit_Branch.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
@@ -1262,6 +1268,12 @@
|
||||
<ClInclude Include="PowerPC\Jit64IL\JitIL_Tables.h">
|
||||
<Filter>PowerPC\JitIL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64\FPURegCache.h">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64\GPRRegCache.h">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64\JitRegCache.h">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/Jit64/FPURegCache.h"
|
||||
|
||||
#include "Core/PowerPC/Jit64/Jit.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Base.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
FPURegCache::FPURegCache(Jit64& jit) : RegCache{jit}
|
||||
{
|
||||
}
|
||||
|
||||
void FPURegCache::StoreRegister(size_t preg, const OpArg& new_loc)
|
||||
{
|
||||
m_emitter->MOVAPD(new_loc, m_regs[preg].location.GetSimpleReg());
|
||||
}
|
||||
|
||||
void FPURegCache::LoadRegister(size_t preg, X64Reg new_loc)
|
||||
{
|
||||
m_emitter->MOVAPD(new_loc, m_regs[preg].location);
|
||||
}
|
||||
|
||||
const X64Reg* FPURegCache::GetAllocationOrder(size_t* count)
|
||||
{
|
||||
static const X64Reg allocation_order[] = {XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12,
|
||||
XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5};
|
||||
*count = sizeof(allocation_order) / sizeof(X64Reg);
|
||||
return allocation_order;
|
||||
}
|
||||
|
||||
OpArg FPURegCache::GetDefaultLocation(size_t reg) const
|
||||
{
|
||||
return PPCSTATE(ps[reg][0]);
|
||||
}
|
||||
|
||||
BitSet32 FPURegCache::GetRegUtilization()
|
||||
{
|
||||
return m_jit.js.op->gprInReg;
|
||||
}
|
||||
|
||||
BitSet32 FPURegCache::CountRegsIn(size_t preg, u32 lookahead)
|
||||
{
|
||||
BitSet32 regs_used;
|
||||
|
||||
for (u32 i = 1; i < lookahead; i++)
|
||||
{
|
||||
BitSet32 regs_in = m_jit.js.op[i].fregsIn;
|
||||
regs_used |= regs_in;
|
||||
if (regs_in[preg])
|
||||
return regs_used;
|
||||
}
|
||||
|
||||
return regs_used;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
|
||||
class Jit64;
|
||||
|
||||
class FPURegCache final : public RegCache
|
||||
{
|
||||
public:
|
||||
explicit FPURegCache(Jit64& jit);
|
||||
|
||||
void StoreRegister(size_t preg, const Gen::OpArg& newLoc) override;
|
||||
void LoadRegister(size_t preg, Gen::X64Reg newLoc) override;
|
||||
const Gen::X64Reg* GetAllocationOrder(size_t* count) override;
|
||||
Gen::OpArg GetDefaultLocation(size_t reg) const override;
|
||||
BitSet32 GetRegUtilization() override;
|
||||
BitSet32 CountRegsIn(size_t preg, u32 lookahead) override;
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/Jit64/GPRRegCache.h"
|
||||
|
||||
#include "Core/PowerPC/Jit64/Jit.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Base.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
GPRRegCache::GPRRegCache(Jit64& jit) : RegCache{jit}
|
||||
{
|
||||
}
|
||||
|
||||
void GPRRegCache::StoreRegister(size_t preg, const OpArg& new_loc)
|
||||
{
|
||||
m_emitter->MOV(32, new_loc, m_regs[preg].location);
|
||||
}
|
||||
|
||||
void GPRRegCache::LoadRegister(size_t preg, X64Reg new_loc)
|
||||
{
|
||||
m_emitter->MOV(32, ::Gen::R(new_loc), m_regs[preg].location);
|
||||
}
|
||||
|
||||
OpArg GPRRegCache::GetDefaultLocation(size_t reg) const
|
||||
{
|
||||
return PPCSTATE(gpr[reg]);
|
||||
}
|
||||
|
||||
const X64Reg* GPRRegCache::GetAllocationOrder(size_t* count)
|
||||
{
|
||||
static const X64Reg allocation_order[] = {
|
||||
// R12, when used as base register, for example in a LEA, can generate bad code! Need to look into
|
||||
// this.
|
||||
#ifdef _WIN32
|
||||
RSI, RDI, R13, R14, R15, R8,
|
||||
R9, R10, R11, R12, RCX
|
||||
#else
|
||||
R12, R13, R14, R15, RSI, RDI,
|
||||
R8, R9, R10, R11, RCX
|
||||
#endif
|
||||
};
|
||||
*count = sizeof(allocation_order) / sizeof(X64Reg);
|
||||
return allocation_order;
|
||||
}
|
||||
|
||||
void GPRRegCache::SetImmediate32(size_t preg, u32 imm_value, bool dirty)
|
||||
{
|
||||
// "dirty" can be false to avoid redundantly flushing an immediate when
|
||||
// processing speculative constants.
|
||||
DiscardRegContentsIfCached(preg);
|
||||
m_regs[preg].away |= dirty;
|
||||
m_regs[preg].location = Imm32(imm_value);
|
||||
}
|
||||
|
||||
BitSet32 GPRRegCache::GetRegUtilization()
|
||||
{
|
||||
return m_jit.js.op->gprInReg;
|
||||
}
|
||||
|
||||
BitSet32 GPRRegCache::CountRegsIn(size_t preg, u32 lookahead)
|
||||
{
|
||||
BitSet32 regs_used;
|
||||
|
||||
for (u32 i = 1; i < lookahead; i++)
|
||||
{
|
||||
BitSet32 regs_in = m_jit.js.op[i].regsIn;
|
||||
regs_used |= regs_in;
|
||||
if (regs_in[preg])
|
||||
return regs_used;
|
||||
}
|
||||
|
||||
return regs_used;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
|
||||
class Jit64;
|
||||
|
||||
class GPRRegCache final : public RegCache
|
||||
{
|
||||
public:
|
||||
explicit GPRRegCache(Jit64& jit);
|
||||
|
||||
void StoreRegister(size_t preg, const Gen::OpArg& new_loc) override;
|
||||
void LoadRegister(size_t preg, Gen::X64Reg new_loc) override;
|
||||
Gen::OpArg GetDefaultLocation(size_t reg) const override;
|
||||
const Gen::X64Reg* GetAllocationOrder(size_t* count) override;
|
||||
void SetImmediate32(size_t preg, u32 imm_value, bool dirty = true);
|
||||
BitSet32 GetRegUtilization() override;
|
||||
BitSet32 CountRegsIn(size_t preg, u32 lookahead) override;
|
||||
};
|
||||
@@ -950,7 +950,7 @@ BitSet8 Jit64::ComputeStaticGQRs(const PPCAnalyst::CodeBlock& cb) const
|
||||
BitSet32 Jit64::CallerSavedRegistersInUse() const
|
||||
{
|
||||
BitSet32 result;
|
||||
for (int i = 0; i < NUMXREGS; i++)
|
||||
for (size_t i = 0; i < RegCache::NUM_XREGS; i++)
|
||||
{
|
||||
if (!gpr.IsFreeX(i))
|
||||
result[i] = true;
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/x64ABI.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/Jit64/FPURegCache.h"
|
||||
#include "Core/PowerPC/Jit64/GPRRegCache.h"
|
||||
#include "Core/PowerPC/Jit64/JitAsm.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Base.h"
|
||||
@@ -33,8 +35,8 @@ private:
|
||||
void AllocStack();
|
||||
void FreeStack();
|
||||
|
||||
GPRRegCache gpr;
|
||||
FPURegCache fpr;
|
||||
GPRRegCache gpr{*this};
|
||||
FPURegCache fpr{*this};
|
||||
|
||||
// The default code buffer. We keep it around to not have to alloc/dealloc a
|
||||
// large chunk of memory for each recompiled block.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,8 @@
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
|
||||
class Jit64;
|
||||
|
||||
enum FlushMode
|
||||
{
|
||||
FLUSH_ALL,
|
||||
@@ -31,55 +33,31 @@ struct X64CachedReg
|
||||
bool locked;
|
||||
};
|
||||
|
||||
typedef int XReg;
|
||||
typedef int PReg;
|
||||
|
||||
#define NUMXREGS 16
|
||||
|
||||
class RegCache
|
||||
{
|
||||
protected:
|
||||
std::array<PPCCachedReg, 32> regs;
|
||||
std::array<X64CachedReg, NUMXREGS> xregs;
|
||||
|
||||
virtual const Gen::X64Reg* GetAllocationOrder(size_t* count) = 0;
|
||||
|
||||
virtual BitSet32 GetRegUtilization() = 0;
|
||||
virtual BitSet32 CountRegsIn(size_t preg, u32 lookahead) = 0;
|
||||
|
||||
Gen::XEmitter* emit;
|
||||
|
||||
float ScoreRegister(Gen::X64Reg xreg);
|
||||
|
||||
public:
|
||||
RegCache();
|
||||
virtual ~RegCache() {}
|
||||
static constexpr size_t NUM_XREGS = 16;
|
||||
|
||||
explicit RegCache(Jit64& jit);
|
||||
virtual ~RegCache() = default;
|
||||
|
||||
virtual void StoreRegister(size_t preg, const Gen::OpArg& new_loc) = 0;
|
||||
virtual void LoadRegister(size_t preg, Gen::X64Reg new_loc) = 0;
|
||||
virtual Gen::OpArg GetDefaultLocation(size_t reg) const = 0;
|
||||
|
||||
void Start();
|
||||
|
||||
void DiscardRegContentsIfCached(size_t preg);
|
||||
void SetEmitter(Gen::XEmitter* emitter) { emit = emitter; }
|
||||
void FlushR(Gen::X64Reg reg);
|
||||
void FlushR(Gen::X64Reg reg, Gen::X64Reg reg2)
|
||||
{
|
||||
FlushR(reg);
|
||||
FlushR(reg2);
|
||||
}
|
||||
|
||||
void FlushLockX(Gen::X64Reg reg)
|
||||
{
|
||||
FlushR(reg);
|
||||
LockX(reg);
|
||||
}
|
||||
void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2)
|
||||
{
|
||||
FlushR(reg1);
|
||||
FlushR(reg2);
|
||||
LockX(reg1);
|
||||
LockX(reg2);
|
||||
}
|
||||
void SetEmitter(Gen::XEmitter* emitter);
|
||||
|
||||
void Flush(FlushMode mode = FLUSH_ALL, BitSet32 regsToFlush = BitSet32::AllTrue(32));
|
||||
void Flush(PPCAnalyst::CodeOp* op) { Flush(); }
|
||||
|
||||
void FlushR(Gen::X64Reg reg);
|
||||
void FlushR(Gen::X64Reg reg, Gen::X64Reg reg2);
|
||||
|
||||
void FlushLockX(Gen::X64Reg reg);
|
||||
void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2);
|
||||
|
||||
int SanityCheck() const;
|
||||
void KillImmediate(size_t preg, bool doLoad, bool makeDirty);
|
||||
|
||||
@@ -87,19 +65,9 @@ public:
|
||||
// read only will not set dirty flag
|
||||
void BindToRegister(size_t preg, bool doLoad = true, bool makeDirty = true);
|
||||
void StoreFromRegister(size_t preg, FlushMode mode = FLUSH_ALL);
|
||||
virtual void StoreRegister(size_t preg, const Gen::OpArg& newLoc) = 0;
|
||||
virtual void LoadRegister(size_t preg, Gen::X64Reg newLoc) = 0;
|
||||
|
||||
const Gen::OpArg& R(size_t preg) const { return regs[preg].location; }
|
||||
Gen::X64Reg RX(size_t preg) const
|
||||
{
|
||||
if (IsBound(preg))
|
||||
return regs[preg].location.GetSimpleReg();
|
||||
|
||||
PanicAlert("Unbound register - %zu", preg);
|
||||
return Gen::INVALID_REG;
|
||||
}
|
||||
virtual Gen::OpArg GetDefaultLocation(size_t reg) const = 0;
|
||||
const Gen::OpArg& R(size_t preg) const;
|
||||
Gen::X64Reg RX(size_t preg) const;
|
||||
|
||||
// Register locking.
|
||||
|
||||
@@ -107,7 +75,7 @@ public:
|
||||
template <typename T>
|
||||
void Lock(T p)
|
||||
{
|
||||
regs[p].locked = true;
|
||||
m_regs[p].locked = true;
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
void Lock(T first, Args... args)
|
||||
@@ -120,9 +88,9 @@ public:
|
||||
template <typename T>
|
||||
void LockX(T x)
|
||||
{
|
||||
if (xregs[x].locked)
|
||||
if (m_xregs[x].locked)
|
||||
PanicAlert("RegCache: x %i already locked!", x);
|
||||
xregs[x].locked = true;
|
||||
m_xregs[x].locked = true;
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
void LockX(T first, Args... args)
|
||||
@@ -134,9 +102,9 @@ public:
|
||||
template <typename T>
|
||||
void UnlockX(T x)
|
||||
{
|
||||
if (!xregs[x].locked)
|
||||
if (!m_xregs[x].locked)
|
||||
PanicAlert("RegCache: x %i already unlocked!", x);
|
||||
xregs[x].locked = false;
|
||||
m_xregs[x].locked = false;
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
void UnlockX(T first, Args... args)
|
||||
@@ -148,31 +116,22 @@ public:
|
||||
void UnlockAll();
|
||||
void UnlockAllX();
|
||||
|
||||
bool IsFreeX(size_t xreg) const { return xregs[xreg].free && !xregs[xreg].locked; }
|
||||
bool IsBound(size_t preg) const { return regs[preg].away && regs[preg].location.IsSimpleReg(); }
|
||||
bool IsFreeX(size_t xreg) const;
|
||||
bool IsBound(size_t preg) const;
|
||||
|
||||
Gen::X64Reg GetFreeXReg();
|
||||
int NumFreeRegisters();
|
||||
};
|
||||
|
||||
class GPRRegCache final : public RegCache
|
||||
{
|
||||
public:
|
||||
void StoreRegister(size_t preg, const Gen::OpArg& newLoc) override;
|
||||
void LoadRegister(size_t preg, Gen::X64Reg newLoc) override;
|
||||
Gen::OpArg GetDefaultLocation(size_t reg) const override;
|
||||
const Gen::X64Reg* GetAllocationOrder(size_t* count) override;
|
||||
void SetImmediate32(size_t preg, u32 immValue, bool dirty = true);
|
||||
BitSet32 GetRegUtilization() override;
|
||||
BitSet32 CountRegsIn(size_t preg, u32 lookahead) override;
|
||||
};
|
||||
protected:
|
||||
virtual const Gen::X64Reg* GetAllocationOrder(size_t* count) = 0;
|
||||
|
||||
class FPURegCache final : public RegCache
|
||||
{
|
||||
public:
|
||||
void StoreRegister(size_t preg, const Gen::OpArg& newLoc) override;
|
||||
void LoadRegister(size_t preg, Gen::X64Reg newLoc) override;
|
||||
const Gen::X64Reg* GetAllocationOrder(size_t* count) override;
|
||||
Gen::OpArg GetDefaultLocation(size_t reg) const override;
|
||||
BitSet32 GetRegUtilization() override;
|
||||
BitSet32 CountRegsIn(size_t preg, u32 lookahead) override;
|
||||
virtual BitSet32 GetRegUtilization() = 0;
|
||||
virtual BitSet32 CountRegsIn(size_t preg, u32 lookahead) = 0;
|
||||
|
||||
float ScoreRegister(Gen::X64Reg xreg);
|
||||
|
||||
Jit64& m_jit;
|
||||
std::array<PPCCachedReg, 32> m_regs;
|
||||
std::array<X64CachedReg, NUM_XREGS> m_xregs;
|
||||
Gen::XEmitter* m_emitter = nullptr;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user