#pragma once
#include "ppsspp_config.h"
#include "Common/x64Emitter.h"
#include "Core/MIPS/MIPS.h"
namespace X64JitConstants {
#if PPSSPP_ARCH(AMD64)
const Gen::X64Reg MEMBASEREG = Gen::RBX;
const Gen::X64Reg CTXREG = Gen::R14;
const Gen::X64Reg JITBASEREG = Gen::R15;
#else
const Gen::X64Reg CTXREG = Gen::EBP;
#endif
const Gen::X64Reg TEMPREG = Gen::EAX;
const int NUM_MIPS_GPRS = 36;
#if PPSSPP_ARCH(AMD64)
const u32 NUM_X_REGS = 16;
#elif PPSSPP_ARCH(X86)
const u32 NUM_X_REGS = 8;
#endif
}
namespace MIPSAnalyst {
struct AnalysisResults;
};
struct MIPSCachedReg {
Gen::OpArg location;
bool away;
bool locked;
};
struct X64CachedReg {
MIPSGPReg mipsReg;
bool dirty;
bool free;
bool allocLocked;
};
struct GPRRegCacheState {
MIPSCachedReg regs[X64JitConstants::NUM_MIPS_GPRS];
X64CachedReg xregs[X64JitConstants::NUM_X_REGS];
};
namespace MIPSComp {
struct JitOptions;
struct JitState;
}
class GPRRegCache
{
public:
GPRRegCache();
~GPRRegCache() {}
void Start(MIPSState *mipsState, MIPSComp::JitState *js, MIPSComp::JitOptions *jo, MIPSAnalyst::AnalysisResults &stats);
void DiscardRegContentsIfCached(MIPSGPReg preg);
void DiscardR(MIPSGPReg preg);
void SetEmitter(Gen::XEmitter *emitter) {emit = emitter;}
void FlushR(Gen::X64Reg reg);
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 Flush();
void FlushBeforeCall();
void FlushRemap(MIPSGPReg oldreg, MIPSGPReg newreg);
int SanityCheck() const;
void KillImmediate(MIPSGPReg preg, bool doLoad, bool makeDirty);
void MapReg(MIPSGPReg preg, bool doLoad = true, bool makeDirty = true);
void StoreFromRegister(MIPSGPReg preg);
const Gen::OpArg &R(MIPSGPReg preg) const {return regs[preg].location;}
Gen::X64Reg RX(MIPSGPReg preg) const
{
if (regs[preg].away && regs[preg].location.IsSimpleReg())
return regs[preg].location.GetSimpleReg();
_assert_msg_(false, "Not so simple - %d", preg);
return (Gen::X64Reg)-1;
}
Gen::OpArg GetDefaultLocation(MIPSGPReg reg) const;
void Lock(MIPSGPReg p1, MIPSGPReg p2 = MIPS_REG_INVALID, MIPSGPReg p3 = MIPS_REG_INVALID, MIPSGPReg p4 = MIPS_REG_INVALID);
void LockX(int x1, int x2=0xff, int x3=0xff, int x4=0xff);
void UnlockAll();
void UnlockAllX();
void SetImm(MIPSGPReg preg, u32 immValue);
bool IsImm(MIPSGPReg preg) const;
u32 GetImm(MIPSGPReg preg) const;
void GetState(GPRRegCacheState &state) const;
void RestoreState(const GPRRegCacheState& state);
MIPSState *mips_ = nullptr;
private:
Gen::X64Reg GetFreeXReg();
Gen::X64Reg FindBestToSpill(bool unusedOnly, bool *clobbered);
const Gen::X64Reg *GetAllocationOrder(int &count);
MIPSCachedReg regs[X64JitConstants::NUM_MIPS_GPRS]{};
X64CachedReg xregs[X64JitConstants::NUM_X_REGS]{};
Gen::XEmitter *emit = nullptr;
MIPSComp::JitState *js_;
MIPSComp::JitOptions *jo_;
};