181ad6265SDimitry Andric //===- SPIRVModuleAnalysis.h - analysis of global instrs & regs -*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // The analysis collects instructions that should be output at the module level 1081ad6265SDimitry Andric // and performs the global register numbering. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H 1581ad6265SDimitry Andric #define LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H 1681ad6265SDimitry Andric 1781ad6265SDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h" 18*bdd1243dSDimitry Andric #include "SPIRVGlobalRegistry.h" 19*bdd1243dSDimitry Andric #include "SPIRVUtils.h" 2081ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h" 21*bdd1243dSDimitry Andric #include "llvm/ADT/SmallSet.h" 2281ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 2381ad6265SDimitry Andric #include "llvm/ADT/StringMap.h" 2481ad6265SDimitry Andric 2581ad6265SDimitry Andric namespace llvm { 26*bdd1243dSDimitry Andric class SPIRVSubtarget; 2781ad6265SDimitry Andric class MachineFunction; 2881ad6265SDimitry Andric class MachineModuleInfo; 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric namespace SPIRV { 3181ad6265SDimitry Andric // The enum contains logical module sections for the instruction collection. 3281ad6265SDimitry Andric enum ModuleSectionType { 3381ad6265SDimitry Andric // MB_Capabilities, MB_Extensions, MB_ExtInstImports, MB_MemoryModel, 3481ad6265SDimitry Andric MB_EntryPoints, // All OpEntryPoint instructions (if any). 3581ad6265SDimitry Andric // MB_ExecutionModes, MB_DebugSourceAndStrings, 3681ad6265SDimitry Andric MB_DebugNames, // All OpName and OpMemberName intrs. 3781ad6265SDimitry Andric MB_DebugModuleProcessed, // All OpModuleProcessed instructions. 3881ad6265SDimitry Andric MB_Annotations, // OpDecorate, OpMemberDecorate etc. 3981ad6265SDimitry Andric MB_TypeConstVars, // OpTypeXXX, OpConstantXXX, and global OpVariables. 4081ad6265SDimitry Andric MB_ExtFuncDecls, // OpFunction etc. to declare for external funcs. 4181ad6265SDimitry Andric NUM_MODULE_SECTIONS // Total number of sections requiring basic blocks. 4281ad6265SDimitry Andric }; 4381ad6265SDimitry Andric 44*bdd1243dSDimitry Andric struct Requirements { 45*bdd1243dSDimitry Andric const bool IsSatisfiable; 46*bdd1243dSDimitry Andric const std::optional<Capability::Capability> Cap; 47*bdd1243dSDimitry Andric const ExtensionList Exts; 48*bdd1243dSDimitry Andric const unsigned MinVer; // 0 if no min version is required. 49*bdd1243dSDimitry Andric const unsigned MaxVer; // 0 if no max version is required. 50*bdd1243dSDimitry Andric 51*bdd1243dSDimitry Andric Requirements(bool IsSatisfiable = false, 52*bdd1243dSDimitry Andric std::optional<Capability::Capability> Cap = {}, 53*bdd1243dSDimitry Andric ExtensionList Exts = {}, unsigned MinVer = 0, 54*bdd1243dSDimitry Andric unsigned MaxVer = 0) 55*bdd1243dSDimitry Andric : IsSatisfiable(IsSatisfiable), Cap(Cap), Exts(Exts), MinVer(MinVer), 56*bdd1243dSDimitry Andric MaxVer(MaxVer) {} 57*bdd1243dSDimitry Andric Requirements(Capability::Capability Cap) : Requirements(true, {Cap}) {} 58*bdd1243dSDimitry Andric }; 59*bdd1243dSDimitry Andric 60*bdd1243dSDimitry Andric struct RequirementHandler { 61*bdd1243dSDimitry Andric private: 62*bdd1243dSDimitry Andric CapabilityList MinimalCaps; 63*bdd1243dSDimitry Andric SmallSet<Capability::Capability, 8> AllCaps; 64*bdd1243dSDimitry Andric SmallSet<Extension::Extension, 4> AllExtensions; 65*bdd1243dSDimitry Andric unsigned MinVersion; // 0 if no min version is defined. 66*bdd1243dSDimitry Andric unsigned MaxVersion; // 0 if no max version is defined. 67*bdd1243dSDimitry Andric DenseSet<unsigned> AvailableCaps; 68*bdd1243dSDimitry Andric // Remove a list of capabilities from dedupedCaps and add them to AllCaps, 69*bdd1243dSDimitry Andric // recursing through their implicitly declared capabilities too. 70*bdd1243dSDimitry Andric void pruneCapabilities(const CapabilityList &ToPrune); 71*bdd1243dSDimitry Andric 72*bdd1243dSDimitry Andric public: 73*bdd1243dSDimitry Andric RequirementHandler() : MinVersion(0), MaxVersion(0) {} 74*bdd1243dSDimitry Andric void clear() { 75*bdd1243dSDimitry Andric MinimalCaps.clear(); 76*bdd1243dSDimitry Andric AllCaps.clear(); 77*bdd1243dSDimitry Andric AvailableCaps.clear(); 78*bdd1243dSDimitry Andric AllExtensions.clear(); 79*bdd1243dSDimitry Andric MinVersion = 0; 80*bdd1243dSDimitry Andric MaxVersion = 0; 81*bdd1243dSDimitry Andric } 82*bdd1243dSDimitry Andric unsigned getMinVersion() const { return MinVersion; } 83*bdd1243dSDimitry Andric unsigned getMaxVersion() const { return MaxVersion; } 84*bdd1243dSDimitry Andric const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; } 85*bdd1243dSDimitry Andric const SmallSet<Extension::Extension, 4> &getExtensions() const { 86*bdd1243dSDimitry Andric return AllExtensions; 87*bdd1243dSDimitry Andric } 88*bdd1243dSDimitry Andric // Add a list of capabilities, ensuring AllCaps captures all the implicitly 89*bdd1243dSDimitry Andric // declared capabilities, and MinimalCaps has the minimal set of required 90*bdd1243dSDimitry Andric // capabilities (so all implicitly declared ones are removed). 91*bdd1243dSDimitry Andric void addCapabilities(const CapabilityList &ToAdd); 92*bdd1243dSDimitry Andric void addCapability(Capability::Capability ToAdd) { addCapabilities({ToAdd}); } 93*bdd1243dSDimitry Andric void addExtensions(const ExtensionList &ToAdd) { 94*bdd1243dSDimitry Andric AllExtensions.insert(ToAdd.begin(), ToAdd.end()); 95*bdd1243dSDimitry Andric } 96*bdd1243dSDimitry Andric void addExtension(Extension::Extension ToAdd) { AllExtensions.insert(ToAdd); } 97*bdd1243dSDimitry Andric // Add the given requirements to the lists. If constraints conflict, or these 98*bdd1243dSDimitry Andric // requirements cannot be satisfied, then abort the compilation. 99*bdd1243dSDimitry Andric void addRequirements(const Requirements &Req); 100*bdd1243dSDimitry Andric // Get requirement and add it to the list. 101*bdd1243dSDimitry Andric void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category, 102*bdd1243dSDimitry Andric uint32_t i, const SPIRVSubtarget &ST); 103*bdd1243dSDimitry Andric // Check if all the requirements can be satisfied for the given subtarget, and 104*bdd1243dSDimitry Andric // if not abort compilation. 105*bdd1243dSDimitry Andric void checkSatisfiable(const SPIRVSubtarget &ST) const; 106*bdd1243dSDimitry Andric void initAvailableCapabilities(const SPIRVSubtarget &ST); 107*bdd1243dSDimitry Andric // Add the given capabilities to available and all their implicitly defined 108*bdd1243dSDimitry Andric // capabilities too. 109*bdd1243dSDimitry Andric void addAvailableCaps(const CapabilityList &ToAdd); 110*bdd1243dSDimitry Andric bool isCapabilityAvailable(Capability::Capability Cap) const { 111*bdd1243dSDimitry Andric return AvailableCaps.contains(Cap); 112*bdd1243dSDimitry Andric } 113*bdd1243dSDimitry Andric }; 114*bdd1243dSDimitry Andric 11581ad6265SDimitry Andric using InstrList = SmallVector<MachineInstr *>; 11681ad6265SDimitry Andric // Maps a local register to the corresponding global alias. 11781ad6265SDimitry Andric using LocalToGlobalRegTable = std::map<Register, Register>; 11881ad6265SDimitry Andric using RegisterAliasMapTy = 11981ad6265SDimitry Andric std::map<const MachineFunction *, LocalToGlobalRegTable>; 12081ad6265SDimitry Andric 12181ad6265SDimitry Andric // The struct contains results of the module analysis and methods 12281ad6265SDimitry Andric // to access them. 12381ad6265SDimitry Andric struct ModuleAnalysisInfo { 124*bdd1243dSDimitry Andric RequirementHandler Reqs; 125*bdd1243dSDimitry Andric MemoryModel::MemoryModel Mem; 126*bdd1243dSDimitry Andric AddressingModel::AddressingModel Addr; 127*bdd1243dSDimitry Andric SourceLanguage::SourceLanguage SrcLang; 12881ad6265SDimitry Andric unsigned SrcLangVersion; 129fcaf7f86SDimitry Andric StringSet<> SrcExt; 130fcaf7f86SDimitry Andric // Maps ExtInstSet to corresponding ID register. 131fcaf7f86SDimitry Andric DenseMap<unsigned, Register> ExtInstSetMap; 13281ad6265SDimitry Andric // Contains the list of all global OpVariables in the module. 13381ad6265SDimitry Andric SmallVector<MachineInstr *, 4> GlobalVarList; 134*bdd1243dSDimitry Andric // Maps functions to corresponding function ID registers. 135*bdd1243dSDimitry Andric DenseMap<const Function *, Register> FuncMap; 13681ad6265SDimitry Andric // The set contains machine instructions which are necessary 13781ad6265SDimitry Andric // for correct MIR but will not be emitted in function bodies. 13881ad6265SDimitry Andric DenseSet<MachineInstr *> InstrsToDelete; 139fcaf7f86SDimitry Andric // The set contains machine basic blocks which are necessary 140fcaf7f86SDimitry Andric // for correct MIR but will not be emitted. 141fcaf7f86SDimitry Andric DenseSet<MachineBasicBlock *> MBBsToSkip; 14281ad6265SDimitry Andric // The table contains global aliases of local registers for each machine 14381ad6265SDimitry Andric // function. The aliases are used to substitute local registers during 14481ad6265SDimitry Andric // code emission. 14581ad6265SDimitry Andric RegisterAliasMapTy RegisterAliasTable; 14681ad6265SDimitry Andric // The counter holds the maximum ID we have in the module. 14781ad6265SDimitry Andric unsigned MaxID; 14881ad6265SDimitry Andric // The array contains lists of MIs for each module section. 14981ad6265SDimitry Andric InstrList MS[NUM_MODULE_SECTIONS]; 15081ad6265SDimitry Andric // The table maps MBB number to SPIR-V unique ID register. 15181ad6265SDimitry Andric DenseMap<int, Register> BBNumToRegMap; 15281ad6265SDimitry Andric 153*bdd1243dSDimitry Andric Register getFuncReg(const Function *F) { 154*bdd1243dSDimitry Andric assert(F && "Function is null"); 155*bdd1243dSDimitry Andric auto FuncPtrRegPair = FuncMap.find(F); 156*bdd1243dSDimitry Andric assert(FuncPtrRegPair != FuncMap.end() && "Cannot find function ID"); 157*bdd1243dSDimitry Andric return FuncPtrRegPair->second; 15881ad6265SDimitry Andric } 159fcaf7f86SDimitry Andric Register getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; } 16081ad6265SDimitry Andric InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; } 16181ad6265SDimitry Andric void setSkipEmission(MachineInstr *MI) { InstrsToDelete.insert(MI); } 16281ad6265SDimitry Andric bool getSkipEmission(const MachineInstr *MI) { 16381ad6265SDimitry Andric return InstrsToDelete.contains(MI); 16481ad6265SDimitry Andric } 16581ad6265SDimitry Andric void setRegisterAlias(const MachineFunction *MF, Register Reg, 16681ad6265SDimitry Andric Register AliasReg) { 16781ad6265SDimitry Andric RegisterAliasTable[MF][Reg] = AliasReg; 16881ad6265SDimitry Andric } 16981ad6265SDimitry Andric Register getRegisterAlias(const MachineFunction *MF, Register Reg) { 17081ad6265SDimitry Andric auto RI = RegisterAliasTable[MF].find(Reg); 17181ad6265SDimitry Andric if (RI == RegisterAliasTable[MF].end()) { 17281ad6265SDimitry Andric return Register(0); 17381ad6265SDimitry Andric } 17481ad6265SDimitry Andric return RegisterAliasTable[MF][Reg]; 17581ad6265SDimitry Andric } 17681ad6265SDimitry Andric bool hasRegisterAlias(const MachineFunction *MF, Register Reg) { 17781ad6265SDimitry Andric return RegisterAliasTable.find(MF) != RegisterAliasTable.end() && 17881ad6265SDimitry Andric RegisterAliasTable[MF].find(Reg) != RegisterAliasTable[MF].end(); 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric unsigned getNextID() { return MaxID++; } 18181ad6265SDimitry Andric bool hasMBBRegister(const MachineBasicBlock &MBB) { 18281ad6265SDimitry Andric return BBNumToRegMap.find(MBB.getNumber()) != BBNumToRegMap.end(); 18381ad6265SDimitry Andric } 18481ad6265SDimitry Andric // Convert MBB's number to corresponding ID register. 18581ad6265SDimitry Andric Register getOrCreateMBBRegister(const MachineBasicBlock &MBB) { 18681ad6265SDimitry Andric auto f = BBNumToRegMap.find(MBB.getNumber()); 18781ad6265SDimitry Andric if (f != BBNumToRegMap.end()) 18881ad6265SDimitry Andric return f->second; 18981ad6265SDimitry Andric Register NewReg = Register::index2VirtReg(getNextID()); 19081ad6265SDimitry Andric BBNumToRegMap[MBB.getNumber()] = NewReg; 19181ad6265SDimitry Andric return NewReg; 19281ad6265SDimitry Andric } 19381ad6265SDimitry Andric }; 19481ad6265SDimitry Andric } // namespace SPIRV 19581ad6265SDimitry Andric 19681ad6265SDimitry Andric struct SPIRVModuleAnalysis : public ModulePass { 19781ad6265SDimitry Andric static char ID; 19881ad6265SDimitry Andric 19981ad6265SDimitry Andric public: 20081ad6265SDimitry Andric SPIRVModuleAnalysis() : ModulePass(ID) {} 20181ad6265SDimitry Andric 20281ad6265SDimitry Andric bool runOnModule(Module &M) override; 20381ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 20481ad6265SDimitry Andric static struct SPIRV::ModuleAnalysisInfo MAI; 20581ad6265SDimitry Andric 20681ad6265SDimitry Andric private: 20781ad6265SDimitry Andric void setBaseInfo(const Module &M); 208753f127fSDimitry Andric void collectGlobalEntities( 209753f127fSDimitry Andric const std::vector<SPIRV::DTSortableEntry *> &DepsGraph, 210753f127fSDimitry Andric SPIRV::ModuleSectionType MSType, 211753f127fSDimitry Andric std::function<bool(const SPIRV::DTSortableEntry *)> Pred, 212753f127fSDimitry Andric bool UsePreOrder); 21381ad6265SDimitry Andric void processDefInstrs(const Module &M); 214*bdd1243dSDimitry Andric void collectFuncNames(MachineInstr &MI, const Function *F); 21581ad6265SDimitry Andric void processOtherInstrs(const Module &M); 21681ad6265SDimitry Andric void numberRegistersGlobally(const Module &M); 21781ad6265SDimitry Andric 21881ad6265SDimitry Andric const SPIRVSubtarget *ST; 21981ad6265SDimitry Andric SPIRVGlobalRegistry *GR; 22081ad6265SDimitry Andric const SPIRVInstrInfo *TII; 22181ad6265SDimitry Andric MachineModuleInfo *MMI; 22281ad6265SDimitry Andric }; 22381ad6265SDimitry Andric } // namespace llvm 22481ad6265SDimitry Andric #endif // LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H 225