#pragma once
#include "Common/CommonTypes.h"
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/IR/IRAnalysis.h"
#include "Core/MIPS/IR/IRInst.h"
constexpr int TOTAL_MAPPABLE_IRREGS = 256;
constexpr int TOTAL_POSSIBLE_NATIVEREGS = 128;
typedef int8_t IRNativeReg;
constexpr IRReg IRREG_INVALID = 255;
class IRWriter;
class MIPSState;
namespace MIPSComp {
class IRBlock;
class IRBlockCache;
struct JitOptions;
}
class IRImmRegCache {
public:
IRImmRegCache(IRWriter *ir);
void SetImm(IRReg r, u32 immVal) {
isImm_[r] = true;
immVal_[r] = immVal;
}
bool IsImm(IRReg r) const { return isImm_[r]; }
u32 GetImm(IRReg r) const { return immVal_[r]; }
void FlushAll();
void MapDirty(IRReg rd);
void MapIn(IRReg rd);
void MapInIn(IRReg rs, IRReg rt);
void MapInInIn(IRReg rd, IRReg rs, IRReg rt);
void MapDirtyIn(IRReg rd, IRReg rs);
void MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt);
private:
void Flush(IRReg rd);
void Discard(IRReg rd);
bool isImm_[TOTAL_MAPPABLE_IRREGS];
uint32_t immVal_[TOTAL_MAPPABLE_IRREGS];
IRWriter *ir_;
};
enum class MIPSMap : uint8_t {
INIT = 0,
DIRTY = 1,
NOINIT = 2 | DIRTY,
BACKEND_MASK = 0xF0,
};
static inline MIPSMap operator |(const MIPSMap &lhs, const MIPSMap &rhs) {
return MIPSMap((uint8_t)lhs | (uint8_t)rhs);
}
static inline MIPSMap operator &(const MIPSMap &lhs, const MIPSMap &rhs) {
return MIPSMap((uint8_t)lhs & (uint8_t)rhs);
}
class IRNativeRegCacheBase {
protected:
enum class MIPSLoc {
IMM,
REG,
REG_AS_PTR,
REG_IMM,
FREG,
VREG,
MEM,
};
struct RegStatusMIPS {
MIPSLoc loc = MIPSLoc::MEM;
IRNativeReg nReg = -1;
uint32_t imm = 0;
int spillLockIRIndex = -1;
int lane = -1;
bool isStatic = false;
};
struct RegStatusNative {
IRReg mipsReg = IRREG_INVALID;
int tempLockIRIndex = -1;
bool isDirty = false;
bool pointerified = false;
bool normalized32 = false;
};
struct StaticAllocation {
IRReg mr;
IRNativeReg nr;
MIPSLoc loc;
bool pointerified = false;
bool normalized32 = false;
};
public:
IRNativeRegCacheBase(MIPSComp::JitOptions *jo);
virtual ~IRNativeRegCacheBase() {}
virtual void Start(MIPSComp::IRBlockCache *irBlockCache, int blockNum);
void SetIRIndex(int index) {
irIndex_ = index;
}
bool IsGPRInRAM(IRReg gpr);
bool IsFPRInRAM(IRReg fpr);
bool IsGPRMapped(IRReg gpr);
bool IsFPRMapped(IRReg fpr);
bool IsGPRMappedAsPointer(IRReg gpr);
bool IsGPRMappedAsStaticPointer(IRReg gpr);
int GetFPRLane(IRReg fpr);
int GetFPRLaneCount(IRReg fpr);
bool IsGPRImm(IRReg gpr);
bool IsGPR2Imm(IRReg base);
uint32_t GetGPRImm(IRReg gpr);
uint64_t GetGPR2Imm(IRReg first);
void SetGPRImm(IRReg gpr, uint32_t immval);
void SetGPR2Imm(IRReg first, uint64_t immval);
void SpillLockGPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
void SpillLockFPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
void ReleaseSpillLockGPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
void ReleaseSpillLockFPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
void MarkGPRDirty(IRReg gpr, bool andNormalized32 = false);
void MarkGPRAsPointerDirty(IRReg gpr);
bool IsGPRClobbered(IRReg gpr) const;
bool IsFPRClobbered(IRReg gpr) const;
struct Mapping {
char type = '?';
IRReg reg = IRREG_INVALID;
uint8_t lanes = 1;
MIPSMap flags = MIPSMap::INIT;
};
void Map(const IRInst &inst);
void MapWithExtra(const IRInst &inst, std::vector<Mapping> extra);
virtual void FlushAll(bool gprs = true, bool fprs = true);
protected:
virtual void SetupInitialRegs();
virtual const int *GetAllocationOrder(MIPSLoc type, MIPSMap flags, int &count, int &base) const = 0;
virtual const StaticAllocation *GetStaticAllocations(int &count) const {
count = 0;
return nullptr;
}
IRNativeReg AllocateReg(MIPSLoc type, MIPSMap flags);
IRNativeReg FindFreeReg(MIPSLoc type, MIPSMap flags) const;
IRNativeReg FindBestToSpill(MIPSLoc type, MIPSMap flags, bool unusedOnly, bool *clobbered) const;
virtual bool IsNativeRegCompatible(IRNativeReg nreg, MIPSLoc type, MIPSMap flags, int lanes);
virtual void DiscardNativeReg(IRNativeReg nreg);
virtual void FlushNativeReg(IRNativeReg nreg);
virtual void DiscardReg(IRReg mreg);
virtual void FlushReg(IRReg mreg);
virtual void AdjustNativeRegAsPtr(IRNativeReg nreg, bool state);
virtual void MapNativeReg(MIPSLoc type, IRNativeReg nreg, IRReg first, int lanes, MIPSMap flags);
virtual bool TransferNativeReg(IRNativeReg nreg, IRNativeReg dest, MIPSLoc type, IRReg first, int lanes, MIPSMap flags);
virtual IRNativeReg MapNativeReg(MIPSLoc type, IRReg first, int lanes, MIPSMap flags);
IRNativeReg MapNativeRegAsPointer(IRReg gpr);
IRNativeReg MapWithTemp(const IRInst &inst, MIPSLoc type);
void MappingFromInst(const IRInst &inst, Mapping mapping[3]);
void ApplyMapping(const Mapping *mapping, int count);
void CleanupMapping(const Mapping *mapping, int count);
virtual void LoadNativeReg(IRNativeReg nreg, IRReg first, int lanes) = 0;
virtual void StoreNativeReg(IRNativeReg nreg, IRReg first, int lanes) = 0;
virtual void SetNativeRegValue(IRNativeReg nreg, uint32_t imm) = 0;
virtual void StoreRegValue(IRReg mreg, uint32_t imm) = 0;
void SetSpillLockIRIndex(IRReg reg, IRReg reg2, IRReg reg3, IRReg reg4, int offset, int index);
void SetSpillLockIRIndex(IRReg reg, int index);
int GetMipsRegOffset(IRReg r);
bool IsRegClobbered(MIPSLoc type, IRReg r) const;
bool IsRegRead(MIPSLoc type, IRReg r) const;
IRUsage GetNextRegUsage(const IRSituation &info, MIPSLoc type, IRReg r) const;
bool IsValidGPR(IRReg r) const;
bool IsValidGPRNoZero(IRReg r) const;
bool IsValidFPR(IRReg r) const;
MIPSComp::JitOptions *jo_;
int irBlockNum_ = 0;
const MIPSComp::IRBlock *irBlock_ = nullptr;
const MIPSComp::IRBlockCache *irBlockCache_ = nullptr;
int irIndex_ = 0;
struct {
int totalNativeRegs = 0;
bool mapFPUSIMD = false;
bool mapUseVRegs = false;
} config_;
RegStatusNative nr[TOTAL_POSSIBLE_NATIVEREGS];
RegStatusMIPS mr[TOTAL_MAPPABLE_IRREGS];
RegStatusNative nrInitial_[TOTAL_POSSIBLE_NATIVEREGS];
RegStatusMIPS mrInitial_[TOTAL_MAPPABLE_IRREGS];
bool initialReady_ = false;
};