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()) |
55 | : IsSatisfiable(IsSatisfiable), Cap(Cap), Exts(Exts), MinVer(MinVer), |
56 | MaxVer(MaxVer) {} |
57 | 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: |
82 | RequirementHandler() {} |
83 | void clear() { |
84 | MinimalCaps.clear(); |
85 | AllCaps.clear(); |
86 | AvailableCaps.clear(); |
87 | AllExtensions.clear(); |
88 | MinVersion = VersionTuple(); |
89 | MaxVersion = VersionTuple(); |
90 | } |
91 | const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; } |
92 | 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); |
99 | void addCapability(Capability::Capability ToAdd) { addCapabilities({ToAdd}); } |
100 | void addExtensions(const ExtensionList &ToAdd) { |
101 | AllExtensions.insert(ToAdd.begin(), ToAdd.end()); |
102 | } |
103 | 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); |
117 | bool isCapabilityAvailable(Capability::Capability Cap) const { |
118 | return AvailableCaps.contains(V: 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 | |
161 | Register getFuncReg(const Function *F) { |
162 | assert(F && "Function is null" ); |
163 | auto FuncPtrRegPair = FuncMap.find(Val: F); |
164 | return FuncPtrRegPair == FuncMap.end() ? Register(0) |
165 | : FuncPtrRegPair->second; |
166 | } |
167 | Register getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; } |
168 | InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; } |
169 | void setSkipEmission(MachineInstr *MI) { InstrsToDelete.insert(V: MI); } |
170 | bool getSkipEmission(const MachineInstr *MI) { |
171 | return InstrsToDelete.contains(V: MI); |
172 | } |
173 | void setRegisterAlias(const MachineFunction *MF, Register Reg, |
174 | Register AliasReg) { |
175 | RegisterAliasTable[MF][Reg] = AliasReg; |
176 | } |
177 | Register getRegisterAlias(const MachineFunction *MF, Register Reg) { |
178 | auto RI = RegisterAliasTable[MF].find(x: Reg); |
179 | if (RI == RegisterAliasTable[MF].end()) { |
180 | return Register(0); |
181 | } |
182 | return RegisterAliasTable[MF][Reg]; |
183 | } |
184 | bool hasRegisterAlias(const MachineFunction *MF, Register Reg) { |
185 | return RegisterAliasTable.find(x: MF) != RegisterAliasTable.end() && |
186 | RegisterAliasTable[MF].find(x: Reg) != RegisterAliasTable[MF].end(); |
187 | } |
188 | unsigned getNextID() { return MaxID++; } |
189 | bool hasMBBRegister(const MachineBasicBlock &MBB) { |
190 | return BBNumToRegMap.contains(Val: MBB.getNumber()); |
191 | } |
192 | // Convert MBB's number to corresponding ID register. |
193 | Register getOrCreateMBBRegister(const MachineBasicBlock &MBB) { |
194 | auto f = BBNumToRegMap.find(Val: MBB.getNumber()); |
195 | if (f != BBNumToRegMap.end()) |
196 | return f->second; |
197 | Register NewReg = Register::index2VirtReg(Index: 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: |
208 | 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 | |