CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/MIPS/IR/IRRegCache.h
Views: 1401
// Copyright (c) 2023- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#pragma once1819// IRImmRegCache is only to perform pre-constant folding. This is worth it to get cleaner20// IR.2122#include "Common/CommonTypes.h"23#include "Core/MIPS/MIPS.h"24#include "Core/MIPS/IR/IRAnalysis.h"25#include "Core/MIPS/IR/IRInst.h"262728// Have to account for all of them due to temps, etc.29constexpr int TOTAL_MAPPABLE_IRREGS = 256;30// Arbitrary - increase if your backend has more.31constexpr int TOTAL_POSSIBLE_NATIVEREGS = 128;3233typedef int8_t IRNativeReg; // invalid value is -13435constexpr IRReg IRREG_INVALID = 255;3637class IRWriter;38class MIPSState;3940namespace MIPSComp {41class IRBlock;42class IRBlockCache;43struct JitOptions;44}4546// Transient47class IRImmRegCache {48public:49IRImmRegCache(IRWriter *ir);5051void SetImm(IRReg r, u32 immVal) {52isImm_[r] = true;53immVal_[r] = immVal;54}5556bool IsImm(IRReg r) const { return isImm_[r]; }57u32 GetImm(IRReg r) const { return immVal_[r]; }5859void FlushAll();6061void MapDirty(IRReg rd);62void MapIn(IRReg rd);63void MapInIn(IRReg rs, IRReg rt);64void MapInInIn(IRReg rd, IRReg rs, IRReg rt);65void MapDirtyIn(IRReg rd, IRReg rs);66void MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt);6768private:69void Flush(IRReg rd);70void Discard(IRReg rd);7172bool isImm_[TOTAL_MAPPABLE_IRREGS];73uint32_t immVal_[TOTAL_MAPPABLE_IRREGS];74IRWriter *ir_;75};7677// Initing is the default so the flag is reversed.78// 8 bits - upper 4 are reserved for backend purposes.79enum class MIPSMap : uint8_t {80INIT = 0,81DIRTY = 1,82NOINIT = 2 | DIRTY,8384BACKEND_MASK = 0xF0,85};86static inline MIPSMap operator |(const MIPSMap &lhs, const MIPSMap &rhs) {87return MIPSMap((uint8_t)lhs | (uint8_t)rhs);88}89static inline MIPSMap operator &(const MIPSMap &lhs, const MIPSMap &rhs) {90return MIPSMap((uint8_t)lhs & (uint8_t)rhs);91}9293class IRNativeRegCacheBase {94protected:95enum class MIPSLoc {96// Known immediate value (only in regcache.)97IMM,98// In a general reg.99REG,100// In a general reg, but an adjusted pointer (not pointerified - unaligned.)101REG_AS_PTR,102// In a general reg, but also has a known immediate value.103REG_IMM,104// In a native floating-point reg.105FREG,106// In a native vector reg. Note: if FREGs and VREGS overlap, just use FREG.107VREG,108// Away in memory (in the mips context struct.)109MEM,110};111112struct RegStatusMIPS {113// Where is this IR/MIPS register? Note: base reg if vector.114MIPSLoc loc = MIPSLoc::MEM;115// If in a register, what index (into nr array)?116IRNativeReg nReg = -1;117// If a known immediate value, what value?118uint32_t imm = 0;119// Locked from spilling (i.e. used by current instruction) as of what IR instruction?120int spillLockIRIndex = -1;121// If in a multipart reg (vector or HI/LO), which lane?122int lane = -1;123// Whether this reg is statically allocated.124bool isStatic = false;125};126struct RegStatusNative {127// Which IR/MIPS reg is this currently holding?128IRReg mipsReg = IRREG_INVALID;129// Locked either as temp or direct reg as of what IR instruction?130int tempLockIRIndex = -1;131// Should the register be written back?132bool isDirty = false;133// Upper part of the register is used for "pointerification".134// Depending on backend, this may not be used or some/all operations may work on the lower 32 bits.135bool pointerified = false;136// Upper part of the register has a normalized form (i.e. zero or sign extend.)137// Which this means or if it matters depends on the backend.138bool normalized32 = false;139};140141struct StaticAllocation {142IRReg mr;143IRNativeReg nr;144// Register type.145MIPSLoc loc;146// Whether the reg should be marked pointerified by default.147bool pointerified = false;148// Whether the reg should be considered always normalized at the start of a block.149bool normalized32 = false;150};151152public:153IRNativeRegCacheBase(MIPSComp::JitOptions *jo);154virtual ~IRNativeRegCacheBase() {}155156virtual void Start(MIPSComp::IRBlockCache *irBlockCache, int blockNum);157void SetIRIndex(int index) {158irIndex_ = index;159}160161bool IsGPRInRAM(IRReg gpr);162bool IsFPRInRAM(IRReg fpr);163bool IsGPRMapped(IRReg gpr);164bool IsFPRMapped(IRReg fpr);165bool IsGPRMappedAsPointer(IRReg gpr);166bool IsGPRMappedAsStaticPointer(IRReg gpr);167int GetFPRLane(IRReg fpr);168int GetFPRLaneCount(IRReg fpr);169170bool IsGPRImm(IRReg gpr);171bool IsGPR2Imm(IRReg base);172uint32_t GetGPRImm(IRReg gpr);173uint64_t GetGPR2Imm(IRReg first);174void SetGPRImm(IRReg gpr, uint32_t immval);175void SetGPR2Imm(IRReg first, uint64_t immval);176177// Protect the native registers containing register froms spilling, to ensure that178// it's being kept allocated.179void SpillLockGPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);180void SpillLockFPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);181void ReleaseSpillLockGPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);182void ReleaseSpillLockFPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);183184void MarkGPRDirty(IRReg gpr, bool andNormalized32 = false);185void MarkGPRAsPointerDirty(IRReg gpr);186187bool IsGPRClobbered(IRReg gpr) const;188bool IsFPRClobbered(IRReg gpr) const;189190struct Mapping {191char type = '?';192IRReg reg = IRREG_INVALID;193uint8_t lanes = 1;194MIPSMap flags = MIPSMap::INIT;195};196197void Map(const IRInst &inst);198void MapWithExtra(const IRInst &inst, std::vector<Mapping> extra);199virtual void FlushAll(bool gprs = true, bool fprs = true);200201protected:202virtual void SetupInitialRegs();203virtual const int *GetAllocationOrder(MIPSLoc type, MIPSMap flags, int &count, int &base) const = 0;204virtual const StaticAllocation *GetStaticAllocations(int &count) const {205count = 0;206return nullptr;207}208209IRNativeReg AllocateReg(MIPSLoc type, MIPSMap flags);210IRNativeReg FindFreeReg(MIPSLoc type, MIPSMap flags) const;211IRNativeReg FindBestToSpill(MIPSLoc type, MIPSMap flags, bool unusedOnly, bool *clobbered) const;212virtual bool IsNativeRegCompatible(IRNativeReg nreg, MIPSLoc type, MIPSMap flags, int lanes);213virtual void DiscardNativeReg(IRNativeReg nreg);214virtual void FlushNativeReg(IRNativeReg nreg);215virtual void DiscardReg(IRReg mreg);216virtual void FlushReg(IRReg mreg);217virtual void AdjustNativeRegAsPtr(IRNativeReg nreg, bool state);218virtual void MapNativeReg(MIPSLoc type, IRNativeReg nreg, IRReg first, int lanes, MIPSMap flags);219virtual bool TransferNativeReg(IRNativeReg nreg, IRNativeReg dest, MIPSLoc type, IRReg first, int lanes, MIPSMap flags);220virtual IRNativeReg MapNativeReg(MIPSLoc type, IRReg first, int lanes, MIPSMap flags);221IRNativeReg MapNativeRegAsPointer(IRReg gpr);222223IRNativeReg MapWithTemp(const IRInst &inst, MIPSLoc type);224225void MappingFromInst(const IRInst &inst, Mapping mapping[3]);226void ApplyMapping(const Mapping *mapping, int count);227void CleanupMapping(const Mapping *mapping, int count);228229// Load data from memory (possibly multiple lanes) into a native reg.230virtual void LoadNativeReg(IRNativeReg nreg, IRReg first, int lanes) = 0;231// Store data in a native reg back into memory.232virtual void StoreNativeReg(IRNativeReg nreg, IRReg first, int lanes) = 0;233// Set a native reg to a specific integer value.234virtual void SetNativeRegValue(IRNativeReg nreg, uint32_t imm) = 0;235// Store the imm value for a reg to memory (not currently in a native reg.)236virtual void StoreRegValue(IRReg mreg, uint32_t imm) = 0;237238void SetSpillLockIRIndex(IRReg reg, IRReg reg2, IRReg reg3, IRReg reg4, int offset, int index);239void SetSpillLockIRIndex(IRReg reg, int index);240int GetMipsRegOffset(IRReg r);241242bool IsRegClobbered(MIPSLoc type, IRReg r) const;243bool IsRegRead(MIPSLoc type, IRReg r) const;244IRUsage GetNextRegUsage(const IRSituation &info, MIPSLoc type, IRReg r) const;245246bool IsValidGPR(IRReg r) const;247bool IsValidGPRNoZero(IRReg r) const;248bool IsValidFPR(IRReg r) const;249250MIPSComp::JitOptions *jo_;251int irBlockNum_ = 0;252const MIPSComp::IRBlock *irBlock_ = nullptr;253const MIPSComp::IRBlockCache *irBlockCache_ = nullptr;254int irIndex_ = 0;255256struct {257int totalNativeRegs = 0;258bool mapFPUSIMD = false;259bool mapUseVRegs = false;260} config_;261262RegStatusNative nr[TOTAL_POSSIBLE_NATIVEREGS];263RegStatusMIPS mr[TOTAL_MAPPABLE_IRREGS];264RegStatusNative nrInitial_[TOTAL_POSSIBLE_NATIVEREGS];265RegStatusMIPS mrInitial_[TOTAL_MAPPABLE_IRREGS];266267bool initialReady_ = false;268};269270271