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
25namespace llvm {
26class SPIRVSubtarget;
27class MachineFunction;
28class MachineModuleInfo;
29
30namespace SPIRV {
31// The enum contains logical module sections for the instruction collection.
32enum 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
44struct 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
60struct RequirementHandler {
61private:
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
81public:
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
126using InstrList = SmallVector<MachineInstr *>;
127// Maps a local register to the corresponding global alias.
128using LocalToGlobalRegTable = std::map<Register, Register>;
129using RegisterAliasMapTy =
130 std::map<const MachineFunction *, LocalToGlobalRegTable>;
131
132// The struct contains results of the module analysis and methods
133// to access them.
134struct 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
204struct SPIRVModuleAnalysis : public ModulePass {
205 static char ID;
206
207public:
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
214private:
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

source code of llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h