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" 18bdd1243dSDimitry Andric #include "SPIRVGlobalRegistry.h" 19bdd1243dSDimitry Andric #include "SPIRVUtils.h" 2081ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h" 21bdd1243dSDimitry 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 { 26bdd1243dSDimitry 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 44bdd1243dSDimitry Andric struct Requirements { 45bdd1243dSDimitry Andric const bool IsSatisfiable; 46bdd1243dSDimitry Andric const std::optional<Capability::Capability> Cap; 47bdd1243dSDimitry Andric const ExtensionList Exts; 48*0fca6ea1SDimitry Andric const VersionTuple MinVer; // 0 if no min version is required. 49*0fca6ea1SDimitry Andric const VersionTuple MaxVer; // 0 if no max version is required. 50bdd1243dSDimitry Andric 51bdd1243dSDimitry Andric Requirements(bool IsSatisfiable = false, 52bdd1243dSDimitry Andric std::optional<Capability::Capability> Cap = {}, 53*0fca6ea1SDimitry Andric ExtensionList Exts = {}, VersionTuple MinVer = VersionTuple(), 54*0fca6ea1SDimitry Andric VersionTuple MaxVer = VersionTuple()) 55bdd1243dSDimitry Andric : IsSatisfiable(IsSatisfiable), Cap(Cap), Exts(Exts), MinVer(MinVer), 56bdd1243dSDimitry Andric MaxVer(MaxVer) {} 57bdd1243dSDimitry Andric Requirements(Capability::Capability Cap) : Requirements(true, {Cap}) {} 58bdd1243dSDimitry Andric }; 59bdd1243dSDimitry Andric 60bdd1243dSDimitry Andric struct RequirementHandler { 61bdd1243dSDimitry Andric private: 62bdd1243dSDimitry Andric CapabilityList MinimalCaps; 635f757f3fSDimitry Andric 645f757f3fSDimitry Andric // AllCaps and AvailableCaps are related but different. AllCaps is a subset of 655f757f3fSDimitry Andric // AvailableCaps. AvailableCaps is the complete set of capabilities that are 665f757f3fSDimitry Andric // available to the current target. AllCaps is the set of capabilities that 675f757f3fSDimitry Andric // are required by the current module. 68bdd1243dSDimitry Andric SmallSet<Capability::Capability, 8> AllCaps; 695f757f3fSDimitry Andric DenseSet<unsigned> AvailableCaps; 705f757f3fSDimitry Andric 71bdd1243dSDimitry Andric SmallSet<Extension::Extension, 4> AllExtensions; 72*0fca6ea1SDimitry Andric VersionTuple MinVersion; // 0 if no min version is defined. 73*0fca6ea1SDimitry Andric VersionTuple MaxVersion; // 0 if no max version is defined. 74*0fca6ea1SDimitry Andric // Add capabilities to AllCaps, recursing through their implicitly declared 75*0fca6ea1SDimitry Andric // capabilities too. 76*0fca6ea1SDimitry Andric void recursiveAddCapabilities(const CapabilityList &ToPrune); 77bdd1243dSDimitry Andric 785f757f3fSDimitry Andric void initAvailableCapabilitiesForOpenCL(const SPIRVSubtarget &ST); 795f757f3fSDimitry Andric void initAvailableCapabilitiesForVulkan(const SPIRVSubtarget &ST); 805f757f3fSDimitry Andric 81bdd1243dSDimitry Andric public: 82*0fca6ea1SDimitry Andric RequirementHandler() {} 83bdd1243dSDimitry Andric void clear() { 84bdd1243dSDimitry Andric MinimalCaps.clear(); 85bdd1243dSDimitry Andric AllCaps.clear(); 86bdd1243dSDimitry Andric AvailableCaps.clear(); 87bdd1243dSDimitry Andric AllExtensions.clear(); 88*0fca6ea1SDimitry Andric MinVersion = VersionTuple(); 89*0fca6ea1SDimitry Andric MaxVersion = VersionTuple(); 90bdd1243dSDimitry Andric } 91bdd1243dSDimitry Andric const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; } 92bdd1243dSDimitry Andric const SmallSet<Extension::Extension, 4> &getExtensions() const { 93bdd1243dSDimitry Andric return AllExtensions; 94bdd1243dSDimitry Andric } 95bdd1243dSDimitry Andric // Add a list of capabilities, ensuring AllCaps captures all the implicitly 96bdd1243dSDimitry Andric // declared capabilities, and MinimalCaps has the minimal set of required 97bdd1243dSDimitry Andric // capabilities (so all implicitly declared ones are removed). 98bdd1243dSDimitry Andric void addCapabilities(const CapabilityList &ToAdd); 99bdd1243dSDimitry Andric void addCapability(Capability::Capability ToAdd) { addCapabilities({ToAdd}); } 100bdd1243dSDimitry Andric void addExtensions(const ExtensionList &ToAdd) { 101bdd1243dSDimitry Andric AllExtensions.insert(ToAdd.begin(), ToAdd.end()); 102bdd1243dSDimitry Andric } 103bdd1243dSDimitry Andric void addExtension(Extension::Extension ToAdd) { AllExtensions.insert(ToAdd); } 104bdd1243dSDimitry Andric // Add the given requirements to the lists. If constraints conflict, or these 105bdd1243dSDimitry Andric // requirements cannot be satisfied, then abort the compilation. 106bdd1243dSDimitry Andric void addRequirements(const Requirements &Req); 107bdd1243dSDimitry Andric // Get requirement and add it to the list. 108bdd1243dSDimitry Andric void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category, 109bdd1243dSDimitry Andric uint32_t i, const SPIRVSubtarget &ST); 110bdd1243dSDimitry Andric // Check if all the requirements can be satisfied for the given subtarget, and 111bdd1243dSDimitry Andric // if not abort compilation. 112bdd1243dSDimitry Andric void checkSatisfiable(const SPIRVSubtarget &ST) const; 113bdd1243dSDimitry Andric void initAvailableCapabilities(const SPIRVSubtarget &ST); 114bdd1243dSDimitry Andric // Add the given capabilities to available and all their implicitly defined 115bdd1243dSDimitry Andric // capabilities too. 116bdd1243dSDimitry Andric void addAvailableCaps(const CapabilityList &ToAdd); 117bdd1243dSDimitry Andric bool isCapabilityAvailable(Capability::Capability Cap) const { 118bdd1243dSDimitry Andric return AvailableCaps.contains(Cap); 119bdd1243dSDimitry Andric } 1205f757f3fSDimitry Andric 1215f757f3fSDimitry Andric // Remove capability ToRemove, but only if IfPresent is present. 1225f757f3fSDimitry Andric void removeCapabilityIf(const Capability::Capability ToRemove, 1235f757f3fSDimitry Andric const Capability::Capability IfPresent); 124bdd1243dSDimitry Andric }; 125bdd1243dSDimitry Andric 12681ad6265SDimitry Andric using InstrList = SmallVector<MachineInstr *>; 12781ad6265SDimitry Andric // Maps a local register to the corresponding global alias. 12881ad6265SDimitry Andric using LocalToGlobalRegTable = std::map<Register, Register>; 12981ad6265SDimitry Andric using RegisterAliasMapTy = 13081ad6265SDimitry Andric std::map<const MachineFunction *, LocalToGlobalRegTable>; 13181ad6265SDimitry Andric 13281ad6265SDimitry Andric // The struct contains results of the module analysis and methods 13381ad6265SDimitry Andric // to access them. 13481ad6265SDimitry Andric struct ModuleAnalysisInfo { 135bdd1243dSDimitry Andric RequirementHandler Reqs; 136bdd1243dSDimitry Andric MemoryModel::MemoryModel Mem; 137bdd1243dSDimitry Andric AddressingModel::AddressingModel Addr; 138bdd1243dSDimitry Andric SourceLanguage::SourceLanguage SrcLang; 13981ad6265SDimitry Andric unsigned SrcLangVersion; 140fcaf7f86SDimitry Andric StringSet<> SrcExt; 141fcaf7f86SDimitry Andric // Maps ExtInstSet to corresponding ID register. 142fcaf7f86SDimitry Andric DenseMap<unsigned, Register> ExtInstSetMap; 14381ad6265SDimitry Andric // Contains the list of all global OpVariables in the module. 14481ad6265SDimitry Andric SmallVector<MachineInstr *, 4> GlobalVarList; 145bdd1243dSDimitry Andric // Maps functions to corresponding function ID registers. 146bdd1243dSDimitry Andric DenseMap<const Function *, Register> FuncMap; 14781ad6265SDimitry Andric // The set contains machine instructions which are necessary 14881ad6265SDimitry Andric // for correct MIR but will not be emitted in function bodies. 14981ad6265SDimitry Andric DenseSet<MachineInstr *> InstrsToDelete; 15081ad6265SDimitry Andric // The table contains global aliases of local registers for each machine 15181ad6265SDimitry Andric // function. The aliases are used to substitute local registers during 15281ad6265SDimitry Andric // code emission. 15381ad6265SDimitry Andric RegisterAliasMapTy RegisterAliasTable; 15481ad6265SDimitry Andric // The counter holds the maximum ID we have in the module. 15581ad6265SDimitry Andric unsigned MaxID; 15681ad6265SDimitry Andric // The array contains lists of MIs for each module section. 15781ad6265SDimitry Andric InstrList MS[NUM_MODULE_SECTIONS]; 15881ad6265SDimitry Andric // The table maps MBB number to SPIR-V unique ID register. 15981ad6265SDimitry Andric DenseMap<int, Register> BBNumToRegMap; 16081ad6265SDimitry Andric 161bdd1243dSDimitry Andric Register getFuncReg(const Function *F) { 162bdd1243dSDimitry Andric assert(F && "Function is null"); 163bdd1243dSDimitry Andric auto FuncPtrRegPair = FuncMap.find(F); 164*0fca6ea1SDimitry Andric return FuncPtrRegPair == FuncMap.end() ? Register(0) 165*0fca6ea1SDimitry Andric : FuncPtrRegPair->second; 16681ad6265SDimitry Andric } 167fcaf7f86SDimitry Andric Register getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; } 16881ad6265SDimitry Andric InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; } 16981ad6265SDimitry Andric void setSkipEmission(MachineInstr *MI) { InstrsToDelete.insert(MI); } 17081ad6265SDimitry Andric bool getSkipEmission(const MachineInstr *MI) { 17181ad6265SDimitry Andric return InstrsToDelete.contains(MI); 17281ad6265SDimitry Andric } 17381ad6265SDimitry Andric void setRegisterAlias(const MachineFunction *MF, Register Reg, 17481ad6265SDimitry Andric Register AliasReg) { 17581ad6265SDimitry Andric RegisterAliasTable[MF][Reg] = AliasReg; 17681ad6265SDimitry Andric } 17781ad6265SDimitry Andric Register getRegisterAlias(const MachineFunction *MF, Register Reg) { 17881ad6265SDimitry Andric auto RI = RegisterAliasTable[MF].find(Reg); 17981ad6265SDimitry Andric if (RI == RegisterAliasTable[MF].end()) { 18081ad6265SDimitry Andric return Register(0); 18181ad6265SDimitry Andric } 18281ad6265SDimitry Andric return RegisterAliasTable[MF][Reg]; 18381ad6265SDimitry Andric } 18481ad6265SDimitry Andric bool hasRegisterAlias(const MachineFunction *MF, Register Reg) { 18581ad6265SDimitry Andric return RegisterAliasTable.find(MF) != RegisterAliasTable.end() && 18681ad6265SDimitry Andric RegisterAliasTable[MF].find(Reg) != RegisterAliasTable[MF].end(); 18781ad6265SDimitry Andric } 18881ad6265SDimitry Andric unsigned getNextID() { return MaxID++; } 18981ad6265SDimitry Andric bool hasMBBRegister(const MachineBasicBlock &MBB) { 190cb14a3feSDimitry Andric return BBNumToRegMap.contains(MBB.getNumber()); 19181ad6265SDimitry Andric } 19281ad6265SDimitry Andric // Convert MBB's number to corresponding ID register. 19381ad6265SDimitry Andric Register getOrCreateMBBRegister(const MachineBasicBlock &MBB) { 19481ad6265SDimitry Andric auto f = BBNumToRegMap.find(MBB.getNumber()); 19581ad6265SDimitry Andric if (f != BBNumToRegMap.end()) 19681ad6265SDimitry Andric return f->second; 19781ad6265SDimitry Andric Register NewReg = Register::index2VirtReg(getNextID()); 19881ad6265SDimitry Andric BBNumToRegMap[MBB.getNumber()] = NewReg; 19981ad6265SDimitry Andric return NewReg; 20081ad6265SDimitry Andric } 20181ad6265SDimitry Andric }; 20281ad6265SDimitry Andric } // namespace SPIRV 20381ad6265SDimitry Andric 20481ad6265SDimitry Andric struct SPIRVModuleAnalysis : public ModulePass { 20581ad6265SDimitry Andric static char ID; 20681ad6265SDimitry Andric 20781ad6265SDimitry Andric public: 20881ad6265SDimitry Andric SPIRVModuleAnalysis() : ModulePass(ID) {} 20981ad6265SDimitry Andric 21081ad6265SDimitry Andric bool runOnModule(Module &M) override; 21181ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 21281ad6265SDimitry Andric static struct SPIRV::ModuleAnalysisInfo MAI; 21381ad6265SDimitry Andric 21481ad6265SDimitry Andric private: 21581ad6265SDimitry Andric void setBaseInfo(const Module &M); 216753f127fSDimitry Andric void collectGlobalEntities( 217753f127fSDimitry Andric const std::vector<SPIRV::DTSortableEntry *> &DepsGraph, 218753f127fSDimitry Andric SPIRV::ModuleSectionType MSType, 219753f127fSDimitry Andric std::function<bool(const SPIRV::DTSortableEntry *)> Pred, 220753f127fSDimitry Andric bool UsePreOrder); 22181ad6265SDimitry Andric void processDefInstrs(const Module &M); 222bdd1243dSDimitry Andric void collectFuncNames(MachineInstr &MI, const Function *F); 22381ad6265SDimitry Andric void processOtherInstrs(const Module &M); 22481ad6265SDimitry Andric void numberRegistersGlobally(const Module &M); 225*0fca6ea1SDimitry Andric void collectFuncPtrs(); 226*0fca6ea1SDimitry Andric void collectFuncPtrs(MachineInstr *MI); 22781ad6265SDimitry Andric 22881ad6265SDimitry Andric const SPIRVSubtarget *ST; 22981ad6265SDimitry Andric SPIRVGlobalRegistry *GR; 23081ad6265SDimitry Andric const SPIRVInstrInfo *TII; 23181ad6265SDimitry Andric MachineModuleInfo *MMI; 23281ad6265SDimitry Andric }; 23381ad6265SDimitry Andric } // namespace llvm 23481ad6265SDimitry Andric #endif // LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H 235