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