xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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