/home/runner/work/DirectXShaderCompiler/DirectXShaderCompiler/tools/clang/lib/SPIRV/SpirvModule.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- SpirvModule.cpp - SPIR-V Module Implementation ----------*- C++ -*-==// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | |
10 | | #include "clang/SPIRV/SpirvModule.h" |
11 | | #include "clang/SPIRV/SpirvFunction.h" |
12 | | #include "clang/SPIRV/SpirvVisitor.h" |
13 | | |
14 | | namespace clang { |
15 | | namespace spirv { |
16 | | |
17 | | SpirvModule::SpirvModule() |
18 | 3.22k | : capabilities({}), extensions({}), extInstSets({}), memoryModel(nullptr), |
19 | 3.22k | entryPoints({}), executionModes({}), moduleProcesses({}), decorations({}), |
20 | 3.22k | constants({}), undefs({}), variables({}), functions({}), |
21 | 3.22k | debugInstructions({}), perVertexInterp(false) {} |
22 | | |
23 | 3.22k | SpirvModule::~SpirvModule() { |
24 | 3.22k | for (auto *cap : capabilities) |
25 | 39.0k | cap->releaseMemory(); |
26 | 3.22k | for (auto *ext : extensions) |
27 | 14.7k | ext->releaseMemory(); |
28 | 3.22k | for (auto *set : extInstSets) |
29 | 286 | set->releaseMemory(); |
30 | 3.22k | if (memoryModel) |
31 | 2.92k | memoryModel->releaseMemory(); |
32 | 3.22k | for (auto *entry : entryPoints) |
33 | 3.05k | entry->releaseMemory(); |
34 | 3.22k | for (auto *exec : executionModes) |
35 | 3.48k | exec->releaseMemory(); |
36 | 3.22k | for (auto *str : constStrings) |
37 | 242 | str->releaseMemory(); |
38 | 3.22k | for (auto *d : sources) |
39 | 3.38k | d->releaseMemory(); |
40 | 3.22k | for (auto *mp : moduleProcesses) |
41 | 20 | mp->releaseMemory(); |
42 | 3.22k | for (auto *decoration : decorations) |
43 | 14.3k | decoration->releaseMemory(); |
44 | 3.22k | for (auto *constant : constants) |
45 | 57.5k | constant->releaseMemory(); |
46 | 3.22k | for (auto *undef : undefs) |
47 | 70 | undef->releaseMemory(); |
48 | 3.22k | for (auto *var : variables) |
49 | 11.5k | var->releaseMemory(); |
50 | 3.22k | for (auto *di : debugInstructions) |
51 | 2.59k | di->releaseMemory(); |
52 | 3.22k | for (auto *f : allFunctions) |
53 | 8.02k | f->~SpirvFunction(); |
54 | 3.22k | } |
55 | | |
56 | 24.6k | bool SpirvModule::invokeVisitor(Visitor *visitor, bool reverseOrder) { |
57 | | // Note: It is debatable whether reverse order of visiting the module should |
58 | | // reverse everything in this method. For the time being, we just reverse the |
59 | | // order of the function visitors, and keeping everything else the same. |
60 | | // For example, it is not clear what the value would be of vising the last |
61 | | // function first. We can update this methodology if needed. |
62 | | |
63 | 24.6k | if (!visitor->visit(this, Visitor::Phase::Init)) |
64 | 3.65k | return false; |
65 | | |
66 | 20.9k | if (reverseOrder) { |
67 | | // Reverse order of a SPIR-V module. |
68 | | |
69 | | // Our transformations do not cross function bounaries, therefore the order |
70 | | // of visiting functions is not important. |
71 | 21.0k | for (auto iter = functions.rbegin(); iter != functions.rend(); ++iter15.2k ) { |
72 | 15.2k | auto *fn = *iter; |
73 | 15.2k | if (!fn->invokeVisitor(visitor, reverseOrder)) |
74 | 0 | return false; |
75 | 15.2k | } |
76 | | |
77 | 5.77k | for (auto iter = debugInstructions.rbegin(); |
78 | 9.87k | iter != debugInstructions.rend(); ++iter4.10k ) { |
79 | 4.10k | auto *debugInstruction = *iter; |
80 | 4.10k | if (!debugInstruction->invokeVisitor(visitor)) |
81 | 0 | return false; |
82 | 4.10k | } |
83 | | |
84 | 27.8k | for (auto iter = variables.rbegin(); 5.77k iter != variables.rend(); ++iter22.1k ) { |
85 | 22.1k | auto *var = *iter; |
86 | 22.1k | if (!var->invokeVisitor(visitor)) |
87 | 0 | return false; |
88 | 22.1k | } |
89 | | |
90 | 106k | for (auto iter = constants.rbegin(); 5.77k iter != constants.rend(); ++iter100k ) { |
91 | 100k | auto *constant = *iter; |
92 | 100k | if (!constant->invokeVisitor(visitor)) |
93 | 0 | return false; |
94 | 100k | } |
95 | | |
96 | 5.86k | for (auto iter = undefs.rbegin(); 5.77k iter != undefs.rend(); ++iter92 ) { |
97 | 92 | auto *undef = *iter; |
98 | 92 | if (!undef->invokeVisitor(visitor)) |
99 | 0 | return false; |
100 | 92 | } |
101 | | |
102 | | // Since SetVector doesn't have 'rbegin()' and 'rend()' methods, we use |
103 | | // manual indexing. |
104 | 34.2k | for (auto decorIndex = decorations.size(); 5.77k decorIndex > 0; --decorIndex28.4k ) { |
105 | 28.4k | auto *decoration = decorations[decorIndex - 1]; |
106 | 28.4k | if (!decoration->invokeVisitor(visitor)) |
107 | 0 | return false; |
108 | 28.4k | } |
109 | | |
110 | 5.81k | for (auto iter = moduleProcesses.rbegin(); 5.77k iter != moduleProcesses.rend(); |
111 | 5.77k | ++iter40 ) { |
112 | 40 | auto *moduleProcess = *iter; |
113 | 40 | if (!moduleProcess->invokeVisitor(visitor)) |
114 | 0 | return false; |
115 | 40 | } |
116 | | |
117 | 5.77k | if (!sources.empty()) |
118 | 11.8k | for (auto iter = sources.rbegin(); 5.77k iter != sources.rend(); ++iter6.10k ) { |
119 | 6.10k | auto *source = *iter; |
120 | 6.10k | if (!source->invokeVisitor(visitor)) |
121 | 0 | return false; |
122 | 6.10k | } |
123 | | |
124 | 6.24k | for (auto iter = constStrings.rbegin(); 5.77k iter != constStrings.rend(); |
125 | 5.77k | ++iter472 ) { |
126 | 472 | if (!(*iter)->invokeVisitor(visitor)) |
127 | 0 | return false; |
128 | 472 | } |
129 | | |
130 | 12.3k | for (auto iter = executionModes.rbegin(); 5.77k iter != executionModes.rend(); |
131 | 6.55k | ++iter) { |
132 | 6.55k | auto *execMode = *iter; |
133 | 6.55k | if (!execMode->invokeVisitor(visitor)) |
134 | 0 | return false; |
135 | 6.55k | } |
136 | | |
137 | 11.8k | for (auto iter = entryPoints.rbegin(); 5.77k iter != entryPoints.rend(); ++iter6.05k ) { |
138 | 6.05k | auto *entryPoint = *iter; |
139 | 6.05k | if (!entryPoint->invokeVisitor(visitor)) |
140 | 0 | return false; |
141 | 6.05k | } |
142 | | |
143 | 5.77k | if (!memoryModel->invokeVisitor(visitor)) |
144 | 0 | return false; |
145 | | |
146 | 6.22k | for (auto iter = extInstSets.rbegin(); 5.77k iter != extInstSets.rend(); ++iter450 ) { |
147 | 450 | auto *extInstSet = *iter; |
148 | 450 | if (!extInstSet->invokeVisitor(visitor)) |
149 | 0 | return false; |
150 | 450 | } |
151 | | |
152 | | // Since SetVector doesn't have 'rbegin()' and 'rend()' methods, we use |
153 | | // manual indexing. |
154 | 20.5k | for (auto extIndex = extensions.size(); 5.77k extIndex > 0; --extIndex14.7k ) { |
155 | 14.7k | auto *extension = extensions[extIndex - 1]; |
156 | 14.7k | if (!extension->invokeVisitor(visitor)) |
157 | 0 | return false; |
158 | 14.7k | } |
159 | | |
160 | | // Since SetVector doesn't have 'rbegin()' and 'rend()' methods, we use |
161 | | // manual indexing. |
162 | 44.9k | for (auto capIndex = capabilities.size(); 5.77k capIndex > 0; --capIndex39.1k ) { |
163 | 39.1k | auto *capability = capabilities[capIndex - 1]; |
164 | 39.1k | if (!capability->invokeVisitor(visitor)) |
165 | 0 | return false; |
166 | 39.1k | } |
167 | 5.77k | } |
168 | | // Traverse the regular order of a SPIR-V module. |
169 | 15.1k | else { |
170 | 15.1k | for (auto *cap : capabilities) |
171 | 119k | if (!cap->invokeVisitor(visitor)) |
172 | 0 | return false; |
173 | | |
174 | 15.1k | for (auto ext : extensions) |
175 | 46.1k | if (!ext->invokeVisitor(visitor)) |
176 | 0 | return false; |
177 | | |
178 | 15.1k | for (auto extInstSet : extInstSets) |
179 | 1.33k | if (!extInstSet->invokeVisitor(visitor)) |
180 | 0 | return false; |
181 | | |
182 | 15.1k | if (!memoryModel->invokeVisitor(visitor)) |
183 | 0 | return false; |
184 | | |
185 | 15.1k | for (auto entryPoint : entryPoints) |
186 | 15.9k | if (!entryPoint->invokeVisitor(visitor)) |
187 | 0 | return false; |
188 | | |
189 | 15.1k | for (auto execMode : executionModes) |
190 | 17.4k | if (!execMode->invokeVisitor(visitor)) |
191 | 0 | return false; |
192 | | |
193 | 15.1k | for (auto *str : constStrings) |
194 | 1.46k | if (!str->invokeVisitor(visitor)) |
195 | 0 | return false; |
196 | | |
197 | 15.1k | if (!sources.empty()) |
198 | 15.1k | for (auto *source : sources) |
199 | 16.1k | if (!source->invokeVisitor(visitor)) |
200 | 0 | return false; |
201 | | |
202 | 15.1k | for (auto moduleProcess : moduleProcesses) |
203 | 100 | if (!moduleProcess->invokeVisitor(visitor)) |
204 | 0 | return false; |
205 | | |
206 | 15.1k | for (auto decoration : decorations) |
207 | 73.7k | if (!decoration->invokeVisitor(visitor)) |
208 | 0 | return false; |
209 | | |
210 | 15.1k | for (auto constant : constants) |
211 | 285k | if (!constant->invokeVisitor(visitor)) |
212 | 0 | return false; |
213 | | |
214 | 15.1k | for (auto undef : undefs) |
215 | 252 | if (!undef->invokeVisitor(visitor)) |
216 | 0 | return false; |
217 | | |
218 | 15.1k | for (auto var : variables) |
219 | 58.7k | if (!var->invokeVisitor(visitor)) |
220 | 0 | return false; |
221 | | |
222 | 30.2k | for (size_t i = 0; 15.1k i < debugInstructions.size(); i++15.0k ) |
223 | 15.0k | if (!debugInstructions[i]->invokeVisitor(visitor)) |
224 | 0 | return false; |
225 | | |
226 | 15.1k | for (auto fn : functions) |
227 | 40.8k | if (!fn->invokeVisitor(visitor, reverseOrder)) |
228 | 0 | return false; |
229 | 15.1k | } |
230 | | |
231 | 20.9k | if (!visitor->visit(this, Visitor::Phase::Done)) |
232 | 0 | return false; |
233 | | |
234 | 20.9k | return true; |
235 | 20.9k | } |
236 | | |
237 | 7.94k | void SpirvModule::addFunctionToListOfSortedModuleFunctions(SpirvFunction *fn) { |
238 | 7.94k | assert(fn && "cannot add null function to the module"); |
239 | 7.94k | functions.push_back(fn); |
240 | 7.94k | } |
241 | | |
242 | 8.02k | void SpirvModule::addFunction(SpirvFunction *fn) { |
243 | 8.02k | assert(fn && "cannot add null function to the module"); |
244 | 8.02k | allFunctions.insert(fn); |
245 | 8.02k | } |
246 | | |
247 | 89.4k | bool SpirvModule::addCapability(SpirvCapability *cap) { |
248 | 89.4k | assert(cap && "cannot add null capability to the module"); |
249 | 89.4k | return capabilities.insert(cap); |
250 | 89.4k | } |
251 | | |
252 | 2.87k | bool SpirvModule::hasCapability(SpirvCapability &cap) { |
253 | 2.87k | return capabilities.count(&cap) != 0; |
254 | 2.87k | } |
255 | | |
256 | 2.92k | void SpirvModule::setMemoryModel(SpirvMemoryModel *model) { |
257 | 2.92k | assert(model && "cannot set a null memory model"); |
258 | 2.92k | if (memoryModel) |
259 | 0 | memoryModel->releaseMemory(); |
260 | 2.92k | memoryModel = model; |
261 | 2.92k | } |
262 | | |
263 | 38 | bool SpirvModule::promoteAddressingModel(spv::AddressingModel addrModel) { |
264 | 38 | assert(memoryModel && "base memory model must be set first"); |
265 | 76 | auto getPriority = [](spv::AddressingModel am) -> int { |
266 | 76 | switch (am) { |
267 | 0 | default: |
268 | 0 | assert(false && "unknown addressing model"); |
269 | 0 | return 0; |
270 | 38 | case spv::AddressingModel::Logical: |
271 | 38 | return 0; |
272 | 0 | case spv::AddressingModel::Physical32: |
273 | 0 | return 1; |
274 | 0 | case spv::AddressingModel::Physical64: |
275 | 0 | return 2; |
276 | 38 | case spv::AddressingModel::PhysicalStorageBuffer64: |
277 | 38 | return 3; |
278 | 76 | } |
279 | 76 | }; |
280 | | |
281 | 38 | int current = getPriority(memoryModel->getAddressingModel()); |
282 | 38 | int pending = getPriority(addrModel); |
283 | | |
284 | 38 | if (pending > current) { |
285 | 38 | memoryModel->setAddressingModel(addrModel); |
286 | 38 | return true; |
287 | 38 | } else { |
288 | 0 | return false; |
289 | 0 | } |
290 | 38 | } |
291 | | |
292 | 3.05k | void SpirvModule::addEntryPoint(SpirvEntryPoint *ep) { |
293 | 3.05k | assert(ep && "cannot add null as an entry point"); |
294 | 3.05k | entryPoints.push_back(ep); |
295 | 3.05k | } |
296 | | |
297 | | SpirvExecutionModeBase * |
298 | | SpirvModule::findExecutionMode(SpirvFunction *entryPoint, |
299 | 3.73k | spv::ExecutionMode em) { |
300 | 5.93k | for (SpirvExecutionModeBase *cem : executionModes) { |
301 | 5.93k | if (cem->getEntryPoint() != entryPoint) |
302 | 3.98k | continue; |
303 | 1.95k | if (cem->getExecutionMode() != em) |
304 | 1.70k | continue; |
305 | 248 | return cem; |
306 | 1.95k | } |
307 | 3.48k | return nullptr; |
308 | 3.73k | } |
309 | | |
310 | 3.48k | void SpirvModule::addExecutionMode(SpirvExecutionModeBase *em) { |
311 | 3.48k | assert(em && "cannot add null execution mode"); |
312 | 3.48k | executionModes.push_back(em); |
313 | 3.48k | } |
314 | | |
315 | 33.0k | bool SpirvModule::addExtension(SpirvExtension *ext) { |
316 | 33.0k | assert(ext && "cannot add null extension"); |
317 | 33.0k | return extensions.insert(ext); |
318 | 33.0k | } |
319 | | |
320 | 286 | void SpirvModule::addExtInstSet(SpirvExtInstImport *set) { |
321 | 286 | assert(set && "cannot add null extended instruction set"); |
322 | 286 | extInstSets.push_back(set); |
323 | 286 | } |
324 | | |
325 | 6.98k | SpirvExtInstImport *SpirvModule::getExtInstSet(llvm::StringRef name) { |
326 | | // We expect very few (usually 1) extended instruction sets to exist in the |
327 | | // module, so this is not expensive. |
328 | 6.98k | auto found = std::find_if(extInstSets.begin(), extInstSets.end(), |
329 | 7.23k | [name](const SpirvExtInstImport *set) { |
330 | 7.23k | return set->getExtendedInstSetName() == name; |
331 | 7.23k | }); |
332 | | |
333 | 6.98k | if (found != extInstSets.end()) |
334 | 6.69k | return *found; |
335 | | |
336 | 286 | return nullptr; |
337 | 6.98k | } |
338 | | |
339 | 10.7k | void SpirvModule::addVariable(SpirvVariableLike *var) { |
340 | 10.7k | assert(var && "cannot add null variable to the module"); |
341 | 10.7k | variables.push_back(var); |
342 | 10.7k | } |
343 | | |
344 | 814 | void SpirvModule::addVariable(SpirvVariableLike *var, SpirvInstruction *pos) { |
345 | 814 | assert(var && "cannot add null variable to the module"); |
346 | 814 | auto location = std::find(variables.begin(), variables.end(), pos); |
347 | 814 | variables.insert(location, var); |
348 | 814 | } |
349 | | |
350 | 14.3k | void SpirvModule::addDecoration(SpirvDecoration *decor) { |
351 | 14.3k | assert(decor && "cannot add null decoration to the module"); |
352 | 14.3k | decorations.insert(decor); |
353 | 14.3k | } |
354 | | |
355 | 57.5k | void SpirvModule::addConstant(SpirvConstant *constant) { |
356 | 57.5k | assert(constant); |
357 | 57.5k | constants.push_back(constant); |
358 | 57.5k | } |
359 | | |
360 | 70 | void SpirvModule::addUndef(SpirvUndef *undef) { |
361 | 70 | assert(undef); |
362 | 70 | undefs.push_back(undef); |
363 | 70 | } |
364 | | |
365 | 242 | void SpirvModule::addString(SpirvString *str) { |
366 | 242 | assert(str); |
367 | 242 | constStrings.push_back(str); |
368 | 242 | } |
369 | | |
370 | 3.38k | void SpirvModule::addSource(SpirvSource *src) { |
371 | 3.38k | assert(src); |
372 | 3.38k | sources.push_back(src); |
373 | 3.38k | } |
374 | | |
375 | 2.60k | void SpirvModule::addDebugInfo(SpirvDebugInstruction *info) { |
376 | 2.60k | assert(info); |
377 | 2.60k | debugInstructions.push_back(info); |
378 | 2.60k | } |
379 | | |
380 | 20 | void SpirvModule::addModuleProcessed(SpirvModuleProcessed *p) { |
381 | 20 | assert(p); |
382 | 20 | moduleProcesses.push_back(p); |
383 | 20 | } |
384 | | |
385 | 36 | SpirvDebugCompilationUnit *SpirvModule::getDebugCompilationUnit() { |
386 | 36 | SpirvDebugCompilationUnit *unit = debugCompilationUnit; |
387 | 36 | assert(unit && "null DebugCompilationUnit"); |
388 | 36 | return unit; |
389 | 36 | } |
390 | | |
391 | 122 | void SpirvModule::setDebugCompilationUnit(SpirvDebugCompilationUnit *unit) { |
392 | 122 | assert(unit); |
393 | 122 | debugCompilationUnit = unit; |
394 | 122 | } |
395 | | |
396 | | } // end namespace spirv |
397 | | } // end namespace clang |