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
24namespace llvm {
25class SPIRVSubtarget;
26class MachineFunction;
27class MachineModuleInfo;
28
29namespace SPIRV {
30// The enum contains logical module sections for the instruction collection.
31enum 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
46struct 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())
57 : IsSatisfiable(IsSatisfiable), Cap(Cap), Exts(Exts), MinVer(MinVer),
58 MaxVer(MaxVer) {}
59 Requirements(Capability::Capability Cap) : Requirements(true, {Cap}) {}
60};
61
62struct RequirementHandler {
63private:
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
83public:
84 RequirementHandler() {}
85 void clear() {
86 MinimalCaps.clear();
87 AllCaps.clear();
88 AvailableCaps.clear();
89 AllExtensions.clear();
90 MinVersion = VersionTuple();
91 MaxVersion = VersionTuple();
92 }
93 const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; }
94 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);
101 void addCapability(Capability::Capability ToAdd) { addCapabilities(ToAdd: {ToAdd}); }
102 void addExtensions(const ExtensionList &ToAdd) {
103 AllExtensions.insert_range(R: ToAdd);
104 }
105 void addExtension(Extension::Extension ToAdd) { AllExtensions.insert(V: 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);
119 bool isCapabilityAvailable(Capability::Capability Cap) const {
120 return AvailableCaps.contains(V: 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
128using InstrList = SmallVector<const MachineInstr *>;
129// Maps a local register to the corresponding global alias.
130using LocalToGlobalRegTable = std::map<Register, MCRegister>;
131using RegisterAliasMapTy =
132 std::map<const MachineFunction *, LocalToGlobalRegTable>;
133
134// The struct contains results of the module analysis and methods
135// to access them.
136struct 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
163 MCRegister getFuncReg(const Function *F) {
164 assert(F && "Function is null");
165 auto FuncPtrRegPair = FuncMap.find(Val: F);
166 return FuncPtrRegPair == FuncMap.end() ? MCRegister()
167 : FuncPtrRegPair->second;
168 }
169 MCRegister getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; }
170 InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; }
171 void setSkipEmission(const MachineInstr *MI) { InstrsToDelete.insert(V: MI); }
172 bool getSkipEmission(const MachineInstr *MI) {
173 return InstrsToDelete.contains(V: MI);
174 }
175 void setRegisterAlias(const MachineFunction *MF, Register Reg,
176 MCRegister AliasReg) {
177 RegisterAliasTable[MF][Reg] = AliasReg;
178 }
179 MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg) {
180 auto &RegTable = RegisterAliasTable[MF];
181 auto RI = RegTable.find(x: Reg);
182 if (RI == RegTable.end()) {
183 return MCRegister();
184 }
185 return RI->second;
186 }
187 bool hasRegisterAlias(const MachineFunction *MF, Register Reg) {
188 auto RI = RegisterAliasTable.find(x: MF);
189 if (RI == RegisterAliasTable.end())
190 return false;
191 return RI->second.find(x: Reg) != RI->second.end();
192 }
193 unsigned getNextID() { return MaxID++; }
194 MCRegister getNextIDRegister() {
195 return MCRegister((1U << 31) | getNextID());
196 }
197 bool hasMBBRegister(const MachineBasicBlock &MBB) {
198 auto Key = std::make_pair(x: MBB.getParent(), y: MBB.getNumber());
199 return BBNumToRegMap.contains(Val: Key);
200 }
201 // Convert MBB's number to corresponding ID register.
202 MCRegister getOrCreateMBBRegister(const MachineBasicBlock &MBB) {
203 auto Key = std::make_pair(x: MBB.getParent(), y: 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
212using InstrSignature = SmallVector<size_t>;
213using InstrTraces = std::set<InstrSignature>;
214using InstrGRegsMap = std::map<SmallVector<size_t>, unsigned>;
215
216struct SPIRVModuleAnalysis : public ModulePass {
217 static char ID;
218
219public:
220 SPIRVModuleAnalysis() : ModulePass(ID) {}
221
222 bool runOnModule(Module &M) override;
223 void getAnalysisUsage(AnalysisUsage &AU) const override;
224 static struct SPIRV::ModuleAnalysisInfo MAI;
225
226private:
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