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