|
|
|
@ -14,12 +14,11 @@
|
|
|
|
|
#include "Core/PowerPC/PPCAnalyst.h"
|
|
|
|
|
#include "Core/PowerPC/PowerPC.h"
|
|
|
|
|
|
|
|
|
|
using namespace Arm64Gen;
|
|
|
|
|
|
|
|
|
|
// Dedicated host registers
|
|
|
|
|
static const ARM64Reg MEM_REG = X28; // memory base register
|
|
|
|
|
static const ARM64Reg PPC_REG = X29; // ppcState pointer
|
|
|
|
|
static const ARM64Reg DISPATCHER_PC = W26; // register for PC when calling the dispatcher
|
|
|
|
|
static const Arm64Gen::ARM64Reg MEM_REG = Arm64Gen::X28; // memory base register
|
|
|
|
|
static const Arm64Gen::ARM64Reg PPC_REG = Arm64Gen::X29; // ppcState pointer
|
|
|
|
|
static const Arm64Gen::ARM64Reg DISPATCHER_PC =
|
|
|
|
|
Arm64Gen::W26; // PC register when calling the dispatcher
|
|
|
|
|
|
|
|
|
|
#define PPCSTATE_OFF(elem) (offsetof(PowerPC::PowerPCState, elem))
|
|
|
|
|
|
|
|
|
@ -55,11 +54,11 @@ enum FlushMode
|
|
|
|
|
class OpArg
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
OpArg() : m_type(REG_NOTLOADED), m_reg(INVALID_REG), m_value(0), m_last_used(0) {}
|
|
|
|
|
OpArg() : m_type(REG_NOTLOADED), m_reg(Arm64Gen::INVALID_REG), m_value(0), m_last_used(0) {}
|
|
|
|
|
RegType GetType() const { return m_type; }
|
|
|
|
|
ARM64Reg GetReg() const { return m_reg; }
|
|
|
|
|
Arm64Gen::ARM64Reg GetReg() const { return m_reg; }
|
|
|
|
|
u32 GetImm() const { return m_value; }
|
|
|
|
|
void Load(ARM64Reg reg, RegType type = REG_REG)
|
|
|
|
|
void Load(Arm64Gen::ARM64Reg reg, RegType type = REG_REG)
|
|
|
|
|
{
|
|
|
|
|
m_type = type;
|
|
|
|
|
m_reg = reg;
|
|
|
|
@ -69,13 +68,13 @@ public:
|
|
|
|
|
m_type = REG_IMM;
|
|
|
|
|
m_value = imm;
|
|
|
|
|
|
|
|
|
|
m_reg = INVALID_REG;
|
|
|
|
|
m_reg = Arm64Gen::INVALID_REG;
|
|
|
|
|
}
|
|
|
|
|
void Flush()
|
|
|
|
|
{
|
|
|
|
|
// Invalidate any previous information
|
|
|
|
|
m_type = REG_NOTLOADED;
|
|
|
|
|
m_reg = INVALID_REG;
|
|
|
|
|
m_reg = Arm64Gen::INVALID_REG;
|
|
|
|
|
|
|
|
|
|
// Arbitrarily large value that won't roll over on a lot of increments
|
|
|
|
|
m_last_used = 0xFFFF;
|
|
|
|
@ -88,8 +87,8 @@ public:
|
|
|
|
|
bool IsDirty() const { return m_dirty; }
|
|
|
|
|
private:
|
|
|
|
|
// For REG_REG
|
|
|
|
|
RegType m_type; // store type
|
|
|
|
|
ARM64Reg m_reg; // host register we are in
|
|
|
|
|
RegType m_type; // store type
|
|
|
|
|
Arm64Gen::ARM64Reg m_reg; // host register we are in
|
|
|
|
|
|
|
|
|
|
// For REG_IMM
|
|
|
|
|
u32 m_value; // IMM value
|
|
|
|
@ -102,15 +101,15 @@ private:
|
|
|
|
|
class HostReg
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
HostReg() : m_reg(INVALID_REG), m_locked(false) {}
|
|
|
|
|
HostReg(ARM64Reg reg) : m_reg(reg), m_locked(false) {}
|
|
|
|
|
HostReg() : m_reg(Arm64Gen::INVALID_REG), m_locked(false) {}
|
|
|
|
|
HostReg(Arm64Gen::ARM64Reg reg) : m_reg(reg), m_locked(false) {}
|
|
|
|
|
bool IsLocked() const { return m_locked; }
|
|
|
|
|
void Lock() { m_locked = true; }
|
|
|
|
|
void Unlock() { m_locked = false; }
|
|
|
|
|
ARM64Reg GetReg() const { return m_reg; }
|
|
|
|
|
bool operator==(const ARM64Reg& reg) { return reg == m_reg; }
|
|
|
|
|
Arm64Gen::ARM64Reg GetReg() const { return m_reg; }
|
|
|
|
|
bool operator==(const Arm64Gen::ARM64Reg& reg) { return reg == m_reg; }
|
|
|
|
|
private:
|
|
|
|
|
ARM64Reg m_reg;
|
|
|
|
|
Arm64Gen::ARM64Reg m_reg;
|
|
|
|
|
bool m_locked;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -122,7 +121,7 @@ public:
|
|
|
|
|
m_reg_stats(nullptr){};
|
|
|
|
|
virtual ~Arm64RegCache(){};
|
|
|
|
|
|
|
|
|
|
void Init(ARM64XEmitter* emitter);
|
|
|
|
|
void Init(Arm64Gen::ARM64XEmitter* emitter);
|
|
|
|
|
|
|
|
|
|
virtual void Start(PPCAnalyst::BlockRegStats& stats) {}
|
|
|
|
|
// Flushes the register cache in different ways depending on the mode
|
|
|
|
@ -132,11 +131,11 @@ public:
|
|
|
|
|
|
|
|
|
|
// Returns a temporary register for use
|
|
|
|
|
// Requires unlocking after done
|
|
|
|
|
ARM64Reg GetReg();
|
|
|
|
|
Arm64Gen::ARM64Reg GetReg();
|
|
|
|
|
|
|
|
|
|
// Locks a register so a cache cannot use it
|
|
|
|
|
// Useful for function calls
|
|
|
|
|
template <typename T = ARM64Reg, typename... Args>
|
|
|
|
|
template <typename T = Arm64Gen::ARM64Reg, typename... Args>
|
|
|
|
|
void Lock(Args... args)
|
|
|
|
|
{
|
|
|
|
|
for (T reg : {args...})
|
|
|
|
@ -148,7 +147,7 @@ public:
|
|
|
|
|
|
|
|
|
|
// Unlocks a locked register
|
|
|
|
|
// Unlocks registers locked with both GetReg and LockRegister
|
|
|
|
|
template <typename T = ARM64Reg, typename... Args>
|
|
|
|
|
template <typename T = Arm64Gen::ARM64Reg, typename... Args>
|
|
|
|
|
void Unlock(Args... args)
|
|
|
|
|
{
|
|
|
|
|
for (T reg : {args...})
|
|
|
|
@ -166,13 +165,13 @@ protected:
|
|
|
|
|
void FlushMostStaleRegister();
|
|
|
|
|
|
|
|
|
|
// Lock a register
|
|
|
|
|
void LockRegister(ARM64Reg host_reg);
|
|
|
|
|
void LockRegister(Arm64Gen::ARM64Reg host_reg);
|
|
|
|
|
|
|
|
|
|
// Unlock a register
|
|
|
|
|
void UnlockRegister(ARM64Reg host_reg);
|
|
|
|
|
void UnlockRegister(Arm64Gen::ARM64Reg host_reg);
|
|
|
|
|
|
|
|
|
|
// Flushes a guest register by host provided
|
|
|
|
|
virtual void FlushByHost(ARM64Reg host_reg) = 0;
|
|
|
|
|
virtual void FlushByHost(Arm64Gen::ARM64Reg host_reg) = 0;
|
|
|
|
|
|
|
|
|
|
virtual void FlushRegister(size_t preg, bool maintain_state) = 0;
|
|
|
|
|
|
|
|
|
@ -186,10 +185,10 @@ protected:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Code emitter
|
|
|
|
|
ARM64XEmitter* m_emit;
|
|
|
|
|
Arm64Gen::ARM64XEmitter* m_emit;
|
|
|
|
|
|
|
|
|
|
// Float emitter
|
|
|
|
|
std::unique_ptr<ARM64FloatEmitter> m_float_emit;
|
|
|
|
|
std::unique_ptr<Arm64Gen::ARM64FloatEmitter> m_float_emit;
|
|
|
|
|
|
|
|
|
|
// Host side registers that hold the host registers in order of use
|
|
|
|
|
std::vector<HostReg> m_host_registers;
|
|
|
|
@ -215,9 +214,9 @@ public:
|
|
|
|
|
|
|
|
|
|
// Returns a guest GPR inside of a host register
|
|
|
|
|
// Will dump an immediate to the host register as well
|
|
|
|
|
ARM64Reg R(size_t preg) { return R(GetGuestGPR(preg)); }
|
|
|
|
|
Arm64Gen::ARM64Reg R(size_t preg) { return R(GetGuestGPR(preg)); }
|
|
|
|
|
// Returns a guest CR inside of a host register
|
|
|
|
|
ARM64Reg CR(size_t preg) { return R(GetGuestCR(preg)); }
|
|
|
|
|
Arm64Gen::ARM64Reg CR(size_t preg) { return R(GetGuestCR(preg)); }
|
|
|
|
|
// Set a register to an immediate, only valid for guest GPRs
|
|
|
|
|
void SetImmediate(size_t preg, u32 imm) { SetImmediate(GetGuestGPR(preg), imm); }
|
|
|
|
|
// Returns if a register is set as an immediate, only valid for guest GPRs
|
|
|
|
@ -237,12 +236,12 @@ protected:
|
|
|
|
|
void GetAllocationOrder() override;
|
|
|
|
|
|
|
|
|
|
// Flushes a guest register by host provided
|
|
|
|
|
void FlushByHost(ARM64Reg host_reg) override;
|
|
|
|
|
void FlushByHost(Arm64Gen::ARM64Reg host_reg) override;
|
|
|
|
|
|
|
|
|
|
void FlushRegister(size_t index, bool maintain_state) override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
bool IsCalleeSaved(ARM64Reg reg);
|
|
|
|
|
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg);
|
|
|
|
|
|
|
|
|
|
struct GuestRegInfo
|
|
|
|
|
{
|
|
|
|
@ -256,7 +255,7 @@ private:
|
|
|
|
|
GuestRegInfo GetGuestCR(size_t preg);
|
|
|
|
|
GuestRegInfo GetGuestByIndex(size_t index);
|
|
|
|
|
|
|
|
|
|
ARM64Reg R(const GuestRegInfo& guest_reg);
|
|
|
|
|
Arm64Gen::ARM64Reg R(const GuestRegInfo& guest_reg);
|
|
|
|
|
void SetImmediate(const GuestRegInfo& guest_reg, u32 imm);
|
|
|
|
|
void BindToRegister(const GuestRegInfo& guest_reg, bool do_load);
|
|
|
|
|
|
|
|
|
@ -274,9 +273,9 @@ public:
|
|
|
|
|
|
|
|
|
|
// Returns a guest register inside of a host register
|
|
|
|
|
// Will dump an immediate to the host register as well
|
|
|
|
|
ARM64Reg R(size_t preg, RegType type = REG_LOWER_PAIR);
|
|
|
|
|
Arm64Gen::ARM64Reg R(size_t preg, RegType type = REG_LOWER_PAIR);
|
|
|
|
|
|
|
|
|
|
ARM64Reg RW(size_t preg, RegType type = REG_LOWER_PAIR);
|
|
|
|
|
Arm64Gen::ARM64Reg RW(size_t preg, RegType type = REG_LOWER_PAIR);
|
|
|
|
|
|
|
|
|
|
BitSet32 GetCallerSavedUsed() override;
|
|
|
|
|
|
|
|
|
@ -290,12 +289,12 @@ protected:
|
|
|
|
|
void GetAllocationOrder() override;
|
|
|
|
|
|
|
|
|
|
// Flushes a guest register by host provided
|
|
|
|
|
void FlushByHost(ARM64Reg host_reg) override;
|
|
|
|
|
void FlushByHost(Arm64Gen::ARM64Reg host_reg) override;
|
|
|
|
|
|
|
|
|
|
void FlushRegister(size_t preg, bool maintain_state) override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
bool IsCalleeSaved(ARM64Reg reg);
|
|
|
|
|
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg);
|
|
|
|
|
|
|
|
|
|
void FlushRegisters(BitSet32 regs, bool maintain_state);
|
|
|
|
|
};
|
|
|
|
|