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 24 namespace llvm { 25 class SPIRVSubtarget; 26 class MachineFunction; 27 class MachineModuleInfo; 28 29 namespace SPIRV { 30 // The enum contains logical module sections for the instruction collection. 31 enum ModuleSectionType { 32 // MB_Capabilities, MB_Extensions, MB_ExtInstImports, MB_MemoryModel, 33 MB_EntryPoints, // All OpEntryPoint instructions (if any). 34 // MB_ExecutionModes, MB_DebugSourceAndStrings, 35 MB_DebugNames, // All OpName and OpMemberName intrs. 36 MB_DebugStrings, // All OpString intrs. 37 MB_DebugModuleProcessed, // All OpModuleProcessed instructions. 38 MB_AliasingInsts, // SPV_INTEL_memory_access_aliasing instructions. 39 MB_Annotations, // OpDecorate, OpMemberDecorate etc. 40 MB_TypeConstVars, // OpTypeXXX, OpConstantXXX, and global OpVariables. 41 MB_NonSemanticGlobalDI, // OpExtInst with e.g. DebugSource, DebugTypeBasic. 42 MB_ExtFuncDecls, // OpFunction etc. to declare for external funcs. 43 NUM_MODULE_SECTIONS // Total number of sections requiring basic blocks. 44 }; 45 46 struct Requirements { 47 const bool IsSatisfiable; 48 const std::optional<Capability::Capability> Cap; 49 const ExtensionList Exts; 50 const VersionTuple MinVer; // 0 if no min version is required. 51 const VersionTuple MaxVer; // 0 if no max version is required. 52 53 Requirements(bool IsSatisfiable = false, 54 std::optional<Capability::Capability> Cap = {}, 55 ExtensionList Exts = {}, VersionTuple MinVer = VersionTuple(), 56 VersionTuple MaxVer = VersionTuple()) IsSatisfiableRequirements57 : IsSatisfiable(IsSatisfiable), Cap(Cap), Exts(Exts), MinVer(MinVer), 58 MaxVer(MaxVer) {} RequirementsRequirements59 Requirements(Capability::Capability Cap) : Requirements(true, {Cap}) {} 60 }; 61 62 struct RequirementHandler { 63 private: 64 CapabilityList MinimalCaps; 65 66 // AllCaps and AvailableCaps are related but different. AllCaps is a subset of 67 // AvailableCaps. AvailableCaps is the complete set of capabilities that are 68 // available to the current target. AllCaps is the set of capabilities that 69 // are required by the current module. 70 SmallSet<Capability::Capability, 8> AllCaps; 71 DenseSet<unsigned> AvailableCaps; 72 73 SmallSet<Extension::Extension, 4> AllExtensions; 74 VersionTuple MinVersion; // 0 if no min version is defined. 75 VersionTuple MaxVersion; // 0 if no max version is defined. 76 // Add capabilities to AllCaps, recursing through their implicitly declared 77 // capabilities too. 78 void recursiveAddCapabilities(const CapabilityList &ToPrune); 79 80 void initAvailableCapabilitiesForOpenCL(const SPIRVSubtarget &ST); 81 void initAvailableCapabilitiesForVulkan(const SPIRVSubtarget &ST); 82 83 public: RequirementHandlerRequirementHandler84 RequirementHandler() {} clearRequirementHandler85 void clear() { 86 MinimalCaps.clear(); 87 AllCaps.clear(); 88 AvailableCaps.clear(); 89 AllExtensions.clear(); 90 MinVersion = VersionTuple(); 91 MaxVersion = VersionTuple(); 92 } getMinimalCapabilitiesRequirementHandler93 const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; } getExtensionsRequirementHandler94 const SmallSet<Extension::Extension, 4> &getExtensions() const { 95 return AllExtensions; 96 } 97 // Add a list of capabilities, ensuring AllCaps captures all the implicitly 98 // declared capabilities, and MinimalCaps has the minimal set of required 99 // capabilities (so all implicitly declared ones are removed). 100 void addCapabilities(const CapabilityList &ToAdd); addCapabilityRequirementHandler101 void addCapability(Capability::Capability ToAdd) { addCapabilities({ToAdd}); } addExtensionsRequirementHandler102 void addExtensions(const ExtensionList &ToAdd) { 103 AllExtensions.insert_range(ToAdd); 104 } addExtensionRequirementHandler105 void addExtension(Extension::Extension ToAdd) { AllExtensions.insert(ToAdd); } 106 // Add the given requirements to the lists. If constraints conflict, or these 107 // requirements cannot be satisfied, then abort the compilation. 108 void addRequirements(const Requirements &Req); 109 // Get requirement and add it to the list. 110 void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category, 111 uint32_t i, const SPIRVSubtarget &ST); 112 // Check if all the requirements can be satisfied for the given subtarget, and 113 // if not abort compilation. 114 void checkSatisfiable(const SPIRVSubtarget &ST) const; 115 void initAvailableCapabilities(const SPIRVSubtarget &ST); 116 // Add the given capabilities to available and all their implicitly defined 117 // capabilities too. 118 void addAvailableCaps(const CapabilityList &ToAdd); isCapabilityAvailableRequirementHandler119 bool isCapabilityAvailable(Capability::Capability Cap) const { 120 return AvailableCaps.contains(Cap); 121 } 122 123 // Remove capability ToRemove, but only if IfPresent is present. 124 void removeCapabilityIf(const Capability::Capability ToRemove, 125 const Capability::Capability IfPresent); 126 }; 127 128 using InstrList = SmallVector<const MachineInstr *>; 129 // Maps a local register to the corresponding global alias. 130 using LocalToGlobalRegTable = std::map<Register, MCRegister>; 131 using RegisterAliasMapTy = 132 std::map<const MachineFunction *, LocalToGlobalRegTable>; 133 134 // The struct contains results of the module analysis and methods 135 // to access them. 136 struct ModuleAnalysisInfo { 137 RequirementHandler Reqs; 138 MemoryModel::MemoryModel Mem; 139 AddressingModel::AddressingModel Addr; 140 SourceLanguage::SourceLanguage SrcLang; 141 unsigned SrcLangVersion; 142 StringSet<> SrcExt; 143 // Maps ExtInstSet to corresponding ID register. 144 DenseMap<unsigned, MCRegister> ExtInstSetMap; 145 // Contains the list of all global OpVariables in the module. 146 SmallVector<const MachineInstr *, 4> GlobalVarList; 147 // Maps functions to corresponding function ID registers. 148 DenseMap<const Function *, MCRegister> FuncMap; 149 // The set contains machine instructions which are necessary 150 // for correct MIR but will not be emitted in function bodies. 151 DenseSet<const MachineInstr *> InstrsToDelete; 152 // The table contains global aliases of local registers for each machine 153 // function. The aliases are used to substitute local registers during 154 // code emission. 155 RegisterAliasMapTy RegisterAliasTable; 156 // The counter holds the maximum ID we have in the module. 157 unsigned MaxID; 158 // The array contains lists of MIs for each module section. 159 InstrList MS[NUM_MODULE_SECTIONS]; 160 // The table maps MBB number to SPIR-V unique ID register. 161 DenseMap<std::pair<const MachineFunction *, int>, MCRegister> BBNumToRegMap; 162 getFuncRegModuleAnalysisInfo163 MCRegister getFuncReg(const Function *F) { 164 assert(F && "Function is null"); 165 auto FuncPtrRegPair = FuncMap.find(F); 166 return FuncPtrRegPair == FuncMap.end() ? MCRegister() 167 : FuncPtrRegPair->second; 168 } getExtInstSetRegModuleAnalysisInfo169 MCRegister getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; } getMSInstrsModuleAnalysisInfo170 InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; } setSkipEmissionModuleAnalysisInfo171 void setSkipEmission(const MachineInstr *MI) { InstrsToDelete.insert(MI); } getSkipEmissionModuleAnalysisInfo172 bool getSkipEmission(const MachineInstr *MI) { 173 return InstrsToDelete.contains(MI); 174 } setRegisterAliasModuleAnalysisInfo175 void setRegisterAlias(const MachineFunction *MF, Register Reg, 176 MCRegister AliasReg) { 177 RegisterAliasTable[MF][Reg] = AliasReg; 178 } getRegisterAliasModuleAnalysisInfo179 MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg) { 180 auto &RegTable = RegisterAliasTable[MF]; 181 auto RI = RegTable.find(Reg); 182 if (RI == RegTable.end()) { 183 return MCRegister(); 184 } 185 return RI->second; 186 } hasRegisterAliasModuleAnalysisInfo187 bool hasRegisterAlias(const MachineFunction *MF, Register Reg) { 188 auto RI = RegisterAliasTable.find(MF); 189 if (RI == RegisterAliasTable.end()) 190 return false; 191 return RI->second.find(Reg) != RI->second.end(); 192 } getNextIDModuleAnalysisInfo193 unsigned getNextID() { return MaxID++; } getNextIDRegisterModuleAnalysisInfo194 MCRegister getNextIDRegister() { 195 return MCRegister((1U << 31) | getNextID()); 196 } hasMBBRegisterModuleAnalysisInfo197 bool hasMBBRegister(const MachineBasicBlock &MBB) { 198 auto Key = std::make_pair(MBB.getParent(), MBB.getNumber()); 199 return BBNumToRegMap.contains(Key); 200 } 201 // Convert MBB's number to corresponding ID register. getOrCreateMBBRegisterModuleAnalysisInfo202 MCRegister getOrCreateMBBRegister(const MachineBasicBlock &MBB) { 203 auto Key = std::make_pair(MBB.getParent(), MBB.getNumber()); 204 auto [It, Inserted] = BBNumToRegMap.try_emplace(Key); 205 if (Inserted) 206 It->second = getNextIDRegister(); 207 return It->second; 208 } 209 }; 210 } // namespace SPIRV 211 212 using InstrSignature = SmallVector<size_t>; 213 using InstrTraces = std::set<InstrSignature>; 214 using InstrGRegsMap = std::map<SmallVector<size_t>, unsigned>; 215 216 struct SPIRVModuleAnalysis : public ModulePass { 217 static char ID; 218 219 public: SPIRVModuleAnalysisSPIRVModuleAnalysis220 SPIRVModuleAnalysis() : ModulePass(ID) {} 221 222 bool runOnModule(Module &M) override; 223 void getAnalysisUsage(AnalysisUsage &AU) const override; 224 static struct SPIRV::ModuleAnalysisInfo MAI; 225 226 private: 227 void setBaseInfo(const Module &M); 228 void collectFuncNames(MachineInstr &MI, const Function *F); 229 void processOtherInstrs(const Module &M); 230 void numberRegistersGlobally(const Module &M); 231 232 // analyze dependencies to collect module scope definitions 233 void collectDeclarations(const Module &M); 234 void visitDecl(const MachineRegisterInfo &MRI, InstrGRegsMap &SignatureToGReg, 235 std::map<const Value *, unsigned> &GlobalToGReg, 236 const MachineFunction *MF, const MachineInstr &MI); 237 MCRegister handleVariable(const MachineFunction *MF, const MachineInstr &MI, 238 std::map<const Value *, unsigned> &GlobalToGReg); 239 MCRegister handleTypeDeclOrConstant(const MachineInstr &MI, 240 InstrGRegsMap &SignatureToGReg); 241 MCRegister 242 handleFunctionOrParameter(const MachineFunction *MF, const MachineInstr &MI, 243 std::map<const Value *, unsigned> &GlobalToGReg, 244 bool &IsFunDef); 245 void visitFunPtrUse(Register OpReg, InstrGRegsMap &SignatureToGReg, 246 std::map<const Value *, unsigned> &GlobalToGReg, 247 const MachineFunction *MF, const MachineInstr &MI); 248 bool isDeclSection(const MachineRegisterInfo &MRI, const MachineInstr &MI); 249 250 const SPIRVSubtarget *ST; 251 SPIRVGlobalRegistry *GR; 252 const SPIRVInstrInfo *TII; 253 MachineModuleInfo *MMI; 254 }; 255 } // namespace llvm 256 #endif // LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H 257