1 //===- SPIRVModuleAnalysis.h - analysis of global instrs & regs -*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // The analysis collects instructions that should be output at the module level 10 // and performs the global register numbering. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H 15 #define LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H 16 17 #include "MCTargetDesc/SPIRVBaseInfo.h" 18 #include "SPIRVGlobalRegistry.h" 19 #include "SPIRVUtils.h" 20 #include "llvm/ADT/DenseMap.h" 21 #include "llvm/ADT/SmallSet.h" 22 #include "llvm/ADT/SmallVector.h" 23 #include "llvm/ADT/StringMap.h" 24 25 namespace llvm { 26 class SPIRVSubtarget; 27 class MachineFunction; 28 class MachineModuleInfo; 29 30 namespace SPIRV { 31 // The enum contains logical module sections for the instruction collection. 32 enum ModuleSectionType { 33 // MB_Capabilities, MB_Extensions, MB_ExtInstImports, MB_MemoryModel, 34 MB_EntryPoints, // All OpEntryPoint instructions (if any). 35 // MB_ExecutionModes, MB_DebugSourceAndStrings, 36 MB_DebugNames, // All OpName and OpMemberName intrs. 37 MB_DebugModuleProcessed, // All OpModuleProcessed instructions. 38 MB_Annotations, // OpDecorate, OpMemberDecorate etc. 39 MB_TypeConstVars, // OpTypeXXX, OpConstantXXX, and global OpVariables. 40 MB_ExtFuncDecls, // OpFunction etc. to declare for external funcs. 41 NUM_MODULE_SECTIONS // Total number of sections requiring basic blocks. 42 }; 43 44 struct Requirements { 45 const bool IsSatisfiable; 46 const std::optional<Capability::Capability> Cap; 47 const ExtensionList Exts; 48 const VersionTuple MinVer; // 0 if no min version is required. 49 const VersionTuple MaxVer; // 0 if no max version is required. 50 51 Requirements(bool IsSatisfiable = false, 52 std::optional<Capability::Capability> Cap = {}, 53 ExtensionList Exts = {}, VersionTuple MinVer = VersionTuple(), 54 VersionTuple MaxVer = VersionTuple()) IsSatisfiableRequirements55 : IsSatisfiable(IsSatisfiable), Cap(Cap), Exts(Exts), MinVer(MinVer), 56 MaxVer(MaxVer) {} RequirementsRequirements57 Requirements(Capability::Capability Cap) : Requirements(true, {Cap}) {} 58 }; 59 60 struct RequirementHandler { 61 private: 62 CapabilityList MinimalCaps; 63 64 // AllCaps and AvailableCaps are related but different. AllCaps is a subset of 65 // AvailableCaps. AvailableCaps is the complete set of capabilities that are 66 // available to the current target. AllCaps is the set of capabilities that 67 // are required by the current module. 68 SmallSet<Capability::Capability, 8> AllCaps; 69 DenseSet<unsigned> AvailableCaps; 70 71 SmallSet<Extension::Extension, 4> AllExtensions; 72 VersionTuple MinVersion; // 0 if no min version is defined. 73 VersionTuple MaxVersion; // 0 if no max version is defined. 74 // Add capabilities to AllCaps, recursing through their implicitly declared 75 // capabilities too. 76 void recursiveAddCapabilities(const CapabilityList &ToPrune); 77 78 void initAvailableCapabilitiesForOpenCL(const SPIRVSubtarget &ST); 79 void initAvailableCapabilitiesForVulkan(const SPIRVSubtarget &ST); 80 81 public: RequirementHandlerRequirementHandler82 RequirementHandler() {} clearRequirementHandler83 void clear() { 84 MinimalCaps.clear(); 85 AllCaps.clear(); 86 AvailableCaps.clear(); 87 AllExtensions.clear(); 88 MinVersion = VersionTuple(); 89 MaxVersion = VersionTuple(); 90 } getMinimalCapabilitiesRequirementHandler91 const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; } getExtensionsRequirementHandler92 const SmallSet<Extension::Extension, 4> &getExtensions() const { 93 return AllExtensions; 94 } 95 // Add a list of capabilities, ensuring AllCaps captures all the implicitly 96 // declared capabilities, and MinimalCaps has the minimal set of required 97 // capabilities (so all implicitly declared ones are removed). 98 void addCapabilities(const CapabilityList &ToAdd); addCapabilityRequirementHandler99 void addCapability(Capability::Capability ToAdd) { addCapabilities({ToAdd}); } addExtensionsRequirementHandler100 void addExtensions(const ExtensionList &ToAdd) { 101 AllExtensions.insert(ToAdd.begin(), ToAdd.end()); 102 } addExtensionRequirementHandler103 void addExtension(Extension::Extension ToAdd) { AllExtensions.insert(ToAdd); } 104 // Add the given requirements to the lists. If constraints conflict, or these 105 // requirements cannot be satisfied, then abort the compilation. 106 void addRequirements(const Requirements &Req); 107 // Get requirement and add it to the list. 108 void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category, 109 uint32_t i, const SPIRVSubtarget &ST); 110 // Check if all the requirements can be satisfied for the given subtarget, and 111 // if not abort compilation. 112 void checkSatisfiable(const SPIRVSubtarget &ST) const; 113 void initAvailableCapabilities(const SPIRVSubtarget &ST); 114 // Add the given capabilities to available and all their implicitly defined 115 // capabilities too. 116 void addAvailableCaps(const CapabilityList &ToAdd); isCapabilityAvailableRequirementHandler117 bool isCapabilityAvailable(Capability::Capability Cap) const { 118 return AvailableCaps.contains(Cap); 119 } 120 121 // Remove capability ToRemove, but only if IfPresent is present. 122 void removeCapabilityIf(const Capability::Capability ToRemove, 123 const Capability::Capability IfPresent); 124 }; 125 126 using InstrList = SmallVector<MachineInstr *>; 127 // Maps a local register to the corresponding global alias. 128 using LocalToGlobalRegTable = std::map<Register, Register>; 129 using RegisterAliasMapTy = 130 std::map<const MachineFunction *, LocalToGlobalRegTable>; 131 132 // The struct contains results of the module analysis and methods 133 // to access them. 134 struct ModuleAnalysisInfo { 135 RequirementHandler Reqs; 136 MemoryModel::MemoryModel Mem; 137 AddressingModel::AddressingModel Addr; 138 SourceLanguage::SourceLanguage SrcLang; 139 unsigned SrcLangVersion; 140 StringSet<> SrcExt; 141 // Maps ExtInstSet to corresponding ID register. 142 DenseMap<unsigned, Register> ExtInstSetMap; 143 // Contains the list of all global OpVariables in the module. 144 SmallVector<MachineInstr *, 4> GlobalVarList; 145 // Maps functions to corresponding function ID registers. 146 DenseMap<const Function *, Register> FuncMap; 147 // The set contains machine instructions which are necessary 148 // for correct MIR but will not be emitted in function bodies. 149 DenseSet<MachineInstr *> InstrsToDelete; 150 // The table contains global aliases of local registers for each machine 151 // function. The aliases are used to substitute local registers during 152 // code emission. 153 RegisterAliasMapTy RegisterAliasTable; 154 // The counter holds the maximum ID we have in the module. 155 unsigned MaxID; 156 // The array contains lists of MIs for each module section. 157 InstrList MS[NUM_MODULE_SECTIONS]; 158 // The table maps MBB number to SPIR-V unique ID register. 159 DenseMap<int, Register> BBNumToRegMap; 160 getFuncRegModuleAnalysisInfo161 Register getFuncReg(const Function *F) { 162 assert(F && "Function is null"); 163 auto FuncPtrRegPair = FuncMap.find(F); 164 return FuncPtrRegPair == FuncMap.end() ? Register(0) 165 : FuncPtrRegPair->second; 166 } getExtInstSetRegModuleAnalysisInfo167 Register getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; } getMSInstrsModuleAnalysisInfo168 InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; } setSkipEmissionModuleAnalysisInfo169 void setSkipEmission(MachineInstr *MI) { InstrsToDelete.insert(MI); } getSkipEmissionModuleAnalysisInfo170 bool getSkipEmission(const MachineInstr *MI) { 171 return InstrsToDelete.contains(MI); 172 } setRegisterAliasModuleAnalysisInfo173 void setRegisterAlias(const MachineFunction *MF, Register Reg, 174 Register AliasReg) { 175 RegisterAliasTable[MF][Reg] = AliasReg; 176 } getRegisterAliasModuleAnalysisInfo177 Register getRegisterAlias(const MachineFunction *MF, Register Reg) { 178 auto RI = RegisterAliasTable[MF].find(Reg); 179 if (RI == RegisterAliasTable[MF].end()) { 180 return Register(0); 181 } 182 return RegisterAliasTable[MF][Reg]; 183 } hasRegisterAliasModuleAnalysisInfo184 bool hasRegisterAlias(const MachineFunction *MF, Register Reg) { 185 return RegisterAliasTable.find(MF) != RegisterAliasTable.end() && 186 RegisterAliasTable[MF].find(Reg) != RegisterAliasTable[MF].end(); 187 } getNextIDModuleAnalysisInfo188 unsigned getNextID() { return MaxID++; } hasMBBRegisterModuleAnalysisInfo189 bool hasMBBRegister(const MachineBasicBlock &MBB) { 190 return BBNumToRegMap.contains(MBB.getNumber()); 191 } 192 // Convert MBB's number to corresponding ID register. getOrCreateMBBRegisterModuleAnalysisInfo193 Register getOrCreateMBBRegister(const MachineBasicBlock &MBB) { 194 auto f = BBNumToRegMap.find(MBB.getNumber()); 195 if (f != BBNumToRegMap.end()) 196 return f->second; 197 Register NewReg = Register::index2VirtReg(getNextID()); 198 BBNumToRegMap[MBB.getNumber()] = NewReg; 199 return NewReg; 200 } 201 }; 202 } // namespace SPIRV 203 204 struct SPIRVModuleAnalysis : public ModulePass { 205 static char ID; 206 207 public: SPIRVModuleAnalysisSPIRVModuleAnalysis208 SPIRVModuleAnalysis() : ModulePass(ID) {} 209 210 bool runOnModule(Module &M) override; 211 void getAnalysisUsage(AnalysisUsage &AU) const override; 212 static struct SPIRV::ModuleAnalysisInfo MAI; 213 214 private: 215 void setBaseInfo(const Module &M); 216 void collectGlobalEntities( 217 const std::vector<SPIRV::DTSortableEntry *> &DepsGraph, 218 SPIRV::ModuleSectionType MSType, 219 std::function<bool(const SPIRV::DTSortableEntry *)> Pred, 220 bool UsePreOrder); 221 void processDefInstrs(const Module &M); 222 void collectFuncNames(MachineInstr &MI, const Function *F); 223 void processOtherInstrs(const Module &M); 224 void numberRegistersGlobally(const Module &M); 225 void collectFuncPtrs(); 226 void collectFuncPtrs(MachineInstr *MI); 227 228 const SPIRVSubtarget *ST; 229 SPIRVGlobalRegistry *GR; 230 const SPIRVInstrInfo *TII; 231 MachineModuleInfo *MMI; 232 }; 233 } // namespace llvm 234 #endif // LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H 235