Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
35294 views
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(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(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(MI); }
170
bool getSkipEmission(const MachineInstr *MI) {
171
return InstrsToDelete.contains(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(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(MF) != RegisterAliasTable.end() &&
186
RegisterAliasTable[MF].find(Reg) != RegisterAliasTable[MF].end();
187
}
188
unsigned getNextID() { return MaxID++; }
189
bool hasMBBRegister(const MachineBasicBlock &MBB) {
190
return BBNumToRegMap.contains(MBB.getNumber());
191
}
192
// Convert MBB's number to corresponding ID register.
193
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:
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
236