/src/spirv-tools/source/opt/ir_context.cpp
Line | Count | Source |
1 | | // Copyright (c) 2017 Google Inc. |
2 | | // Modifications Copyright (C) 2024 Advanced Micro Devices, Inc. All rights |
3 | | // reserved. |
4 | | // |
5 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
6 | | // you may not use this file except in compliance with the License. |
7 | | // You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, software |
12 | | // distributed under the License is distributed on an "AS IS" BASIS, |
13 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | // See the License for the specific language governing permissions and |
15 | | // limitations under the License. |
16 | | |
17 | | #include "source/opt/ir_context.h" |
18 | | |
19 | | #include <cstring> |
20 | | |
21 | | #include "OpenCLDebugInfo100.h" |
22 | | #include "source/latest_version_glsl_std_450_header.h" |
23 | | #include "source/opt/log.h" |
24 | | #include "source/opt/reflect.h" |
25 | | |
26 | | namespace spvtools { |
27 | | namespace opt { |
28 | | namespace { |
29 | | constexpr int kSpvDecorateTargetIdInIdx = 0; |
30 | | constexpr int kSpvDecorateDecorationInIdx = 1; |
31 | | constexpr int kSpvDecorateBuiltinInIdx = 2; |
32 | | constexpr int kEntryPointInterfaceInIdx = 3; |
33 | | constexpr int kEntryPointFunctionIdInIdx = 1; |
34 | | constexpr int kEntryPointExecutionModelInIdx = 0; |
35 | | |
36 | | // Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo extension |
37 | | // instructions. |
38 | | constexpr uint32_t kDebugFunctionOperandFunctionIndex = 13; |
39 | | constexpr uint32_t kDebugGlobalVariableOperandVariableIndex = 11; |
40 | | } // namespace |
41 | | |
42 | 16.7k | void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) { |
43 | 16.7k | set = Analysis(set & ~valid_analyses_); |
44 | | |
45 | 16.7k | if (set & kAnalysisDefUse) { |
46 | 0 | BuildDefUseManager(); |
47 | 0 | } |
48 | 16.7k | if (set & kAnalysisInstrToBlockMapping) { |
49 | 0 | BuildInstrToBlockMapping(); |
50 | 0 | } |
51 | 16.7k | if (set & kAnalysisDecorations) { |
52 | 0 | BuildDecorationManager(); |
53 | 0 | } |
54 | 16.7k | if (set & kAnalysisCFG) { |
55 | 5.37k | BuildCFG(); |
56 | 5.37k | } |
57 | 16.7k | if (set & kAnalysisDominatorAnalysis) { |
58 | 6.61k | ResetDominatorAnalysis(); |
59 | 6.61k | } |
60 | 16.7k | if (set & kAnalysisLoopAnalysis) { |
61 | 0 | ResetLoopAnalysis(); |
62 | 0 | } |
63 | 16.7k | if (set & kAnalysisBuiltinVarId) { |
64 | 0 | ResetBuiltinAnalysis(); |
65 | 0 | } |
66 | 16.7k | if (set & kAnalysisNameMap) { |
67 | 0 | BuildIdToNameMap(); |
68 | 0 | } |
69 | 16.7k | if (set & kAnalysisScalarEvolution) { |
70 | 0 | BuildScalarEvolutionAnalysis(); |
71 | 0 | } |
72 | 16.7k | if (set & kAnalysisRegisterPressure) { |
73 | 0 | BuildRegPressureAnalysis(); |
74 | 0 | } |
75 | 16.7k | if (set & kAnalysisValueNumberTable) { |
76 | 0 | BuildValueNumberTable(); |
77 | 0 | } |
78 | 16.7k | if (set & kAnalysisStructuredCFG) { |
79 | 0 | BuildStructuredCFGAnalysis(); |
80 | 0 | } |
81 | 16.7k | if (set & kAnalysisIdToFuncMapping) { |
82 | 0 | BuildIdToFuncMapping(); |
83 | 0 | } |
84 | 16.7k | if (set & kAnalysisConstants) { |
85 | 0 | BuildConstantManager(); |
86 | 0 | } |
87 | 16.7k | if (set & kAnalysisTypes) { |
88 | 0 | BuildTypeManager(); |
89 | 0 | } |
90 | 16.7k | if (set & kAnalysisDebugInfo) { |
91 | 0 | BuildDebugInfoManager(); |
92 | 0 | } |
93 | 16.7k | if (set & kAnalysisLiveness) { |
94 | 0 | BuildLivenessManager(); |
95 | 0 | } |
96 | 16.7k | if (set & kAnalysisIdToGraphMapping) { |
97 | 0 | BuildIdToGraphMapping(); |
98 | 0 | } |
99 | 16.7k | } |
100 | | |
101 | | void IRContext::InvalidateAnalysesExceptFor( |
102 | 136k | IRContext::Analysis preserved_analyses) { |
103 | 136k | uint32_t analyses_to_invalidate = valid_analyses_ & (~preserved_analyses); |
104 | 136k | InvalidateAnalyses(static_cast<IRContext::Analysis>(analyses_to_invalidate)); |
105 | 136k | } |
106 | | |
107 | 263k | void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) { |
108 | | // The ConstantManager and DebugInfoManager contain Type pointers. If the |
109 | | // TypeManager goes away, the ConstantManager and DebugInfoManager have to |
110 | | // go away. |
111 | 263k | if (analyses_to_invalidate & kAnalysisTypes) { |
112 | 17.9k | analyses_to_invalidate |= kAnalysisConstants; |
113 | 17.9k | analyses_to_invalidate |= kAnalysisDebugInfo; |
114 | 17.9k | } |
115 | | |
116 | | // The dominator analysis hold the pseudo entry and exit nodes from the CFG. |
117 | | // Also if the CFG change the dominators many changed as well, so the |
118 | | // dominator analysis should be invalidated as well. |
119 | 263k | if (analyses_to_invalidate & kAnalysisCFG) { |
120 | 81.5k | analyses_to_invalidate |= kAnalysisDominatorAnalysis; |
121 | 81.5k | } |
122 | | |
123 | 263k | if (analyses_to_invalidate & kAnalysisDefUse) { |
124 | 61.3k | def_use_mgr_.reset(nullptr); |
125 | 61.3k | } |
126 | 263k | if (analyses_to_invalidate & kAnalysisInstrToBlockMapping) { |
127 | 19.6k | instr_to_block_.clear(); |
128 | 19.6k | } |
129 | 263k | if (analyses_to_invalidate & kAnalysisDecorations) { |
130 | 161k | decoration_mgr_.reset(nullptr); |
131 | 161k | } |
132 | 263k | if (analyses_to_invalidate & kAnalysisCombinators) { |
133 | 39.6k | combinator_ops_.clear(); |
134 | 39.6k | } |
135 | 263k | if (analyses_to_invalidate & kAnalysisBuiltinVarId) { |
136 | 0 | builtin_var_id_map_.clear(); |
137 | 0 | } |
138 | 263k | if (analyses_to_invalidate & kAnalysisCFG) { |
139 | 81.5k | cfg_.reset(nullptr); |
140 | 81.5k | } |
141 | 263k | if (analyses_to_invalidate & kAnalysisDominatorAnalysis) { |
142 | 81.8k | dominator_trees_.clear(); |
143 | 81.8k | post_dominator_trees_.clear(); |
144 | 81.8k | } |
145 | 263k | if (analyses_to_invalidate & kAnalysisNameMap) { |
146 | 75.4k | id_to_name_.reset(nullptr); |
147 | 75.4k | } |
148 | 263k | if (analyses_to_invalidate & kAnalysisValueNumberTable) { |
149 | 10.1k | vn_table_.reset(nullptr); |
150 | 10.1k | } |
151 | 263k | if (analyses_to_invalidate & kAnalysisStructuredCFG) { |
152 | 70.9k | struct_cfg_analysis_.reset(nullptr); |
153 | 70.9k | } |
154 | 263k | if (analyses_to_invalidate & kAnalysisIdToFuncMapping) { |
155 | 97.0k | id_to_func_.clear(); |
156 | 97.0k | } |
157 | 263k | if (analyses_to_invalidate & kAnalysisConstants) { |
158 | 17.9k | constant_mgr_.reset(nullptr); |
159 | 17.9k | } |
160 | 263k | if (analyses_to_invalidate & kAnalysisLiveness) { |
161 | 0 | liveness_mgr_.reset(nullptr); |
162 | 0 | } |
163 | 263k | if (analyses_to_invalidate & kAnalysisTypes) { |
164 | 17.9k | type_mgr_.reset(nullptr); |
165 | 17.9k | } |
166 | | |
167 | 263k | if (analyses_to_invalidate & kAnalysisDebugInfo) { |
168 | 27.0k | debug_info_mgr_.reset(nullptr); |
169 | 27.0k | } |
170 | 263k | if (analyses_to_invalidate & kAnalysisIdToGraphMapping) { |
171 | 0 | id_to_graph_.clear(); |
172 | 0 | } |
173 | | |
174 | 263k | valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate); |
175 | 263k | } |
176 | | |
177 | 18.9M | Instruction* IRContext::KillInst(Instruction* inst) { |
178 | 18.9M | if (!inst) { |
179 | 0 | return nullptr; |
180 | 0 | } |
181 | | |
182 | 18.9M | KillNamesAndDecorates(inst); |
183 | | |
184 | 18.9M | KillOperandFromDebugInstructions(inst); |
185 | | |
186 | 18.9M | KillRelatedDebugScopes(inst); |
187 | | |
188 | 18.9M | if (AreAnalysesValid(kAnalysisDefUse)) { |
189 | 9.71M | analysis::DefUseManager* def_use_mgr = get_def_use_mgr(); |
190 | 9.71M | def_use_mgr->ClearInst(inst); |
191 | 9.71M | for (auto& l_inst : inst->dbg_line_insts()) def_use_mgr->ClearInst(&l_inst); |
192 | 9.71M | } |
193 | 18.9M | if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) { |
194 | 8.99M | instr_to_block_.erase(inst); |
195 | 8.99M | } |
196 | 18.9M | if (AreAnalysesValid(kAnalysisDecorations)) { |
197 | 9.54M | if (inst->IsDecoration()) { |
198 | 216k | decoration_mgr_->RemoveDecoration(inst); |
199 | 216k | } |
200 | 9.54M | } |
201 | 18.9M | if (AreAnalysesValid(kAnalysisDebugInfo)) { |
202 | 1.08M | get_debug_info_mgr()->ClearDebugScopeAndInlinedAtUses(inst); |
203 | 1.08M | get_debug_info_mgr()->ClearDebugInfo(inst); |
204 | 1.08M | } |
205 | 18.9M | if (type_mgr_ && IsTypeInst(inst->opcode())) { |
206 | 63.7k | type_mgr_->RemoveId(inst->result_id()); |
207 | 63.7k | } |
208 | 18.9M | if (constant_mgr_ && IsConstantInst(inst->opcode())) { |
209 | 431k | constant_mgr_->RemoveId(inst->result_id()); |
210 | 431k | } |
211 | 18.9M | if (inst->opcode() == spv::Op::OpCapability || |
212 | 18.9M | inst->opcode() == spv::Op::OpConditionalCapabilityINTEL || |
213 | 18.9M | inst->opcode() == spv::Op::OpExtension || |
214 | 18.9M | inst->opcode() == spv::Op::OpConditionalExtensionINTEL) { |
215 | | // We reset the feature manager, instead of updating it, because it is just |
216 | | // as much work. We would have to remove all capabilities implied by this |
217 | | // capability that are not also implied by the remaining OpCapability |
218 | | // instructions. We could update extensions, but we will see if it is |
219 | | // needed. |
220 | 0 | ResetFeatureManager(); |
221 | 0 | } |
222 | | |
223 | 18.9M | RemoveFromIdToName(inst); |
224 | | |
225 | 18.9M | Instruction* next_instruction = nullptr; |
226 | 18.9M | if (inst->IsInAList()) { |
227 | 18.0M | next_instruction = inst->NextNode(); |
228 | 18.0M | inst->RemoveFromList(); |
229 | 18.0M | delete inst; |
230 | 18.0M | } else { |
231 | | // Needed for instructions that are not part of a list like OpLabels, |
232 | | // OpFunction, OpFunctionEnd, etc.. |
233 | 956k | inst->ToNop(); |
234 | 956k | } |
235 | 18.9M | return next_instruction; |
236 | 18.9M | } |
237 | | |
238 | | bool IRContext::KillInstructionIf(Module::inst_iterator begin, |
239 | | Module::inst_iterator end, |
240 | 0 | std::function<bool(Instruction*)> condition) { |
241 | 0 | bool removed = false; |
242 | 0 | for (auto it = begin; it != end;) { |
243 | 0 | if (!condition(&*it)) { |
244 | 0 | ++it; |
245 | 0 | continue; |
246 | 0 | } |
247 | | |
248 | 0 | removed = true; |
249 | | // `it` is an iterator on an intrusive list. Next is invalidated on the |
250 | | // current node when an instruction is killed. The iterator must be moved |
251 | | // forward before deleting the node. |
252 | 0 | auto instruction = &*it; |
253 | 0 | ++it; |
254 | 0 | KillInst(instruction); |
255 | 0 | } |
256 | |
|
257 | 0 | return removed; |
258 | 0 | } |
259 | | |
260 | | void IRContext::CollectNonSemanticTree( |
261 | 577k | Instruction* inst, std::unordered_set<Instruction*>* to_kill) { |
262 | 577k | if (!inst->HasResultId()) return; |
263 | | // Debug[No]Line result id is not used, so we are done |
264 | 391k | if (inst->IsDebugLineInst()) return; |
265 | 391k | std::vector<Instruction*> work_list; |
266 | 391k | std::unordered_set<Instruction*> seen; |
267 | 391k | work_list.push_back(inst); |
268 | | |
269 | 782k | while (!work_list.empty()) { |
270 | 391k | auto* i = work_list.back(); |
271 | 391k | work_list.pop_back(); |
272 | 391k | get_def_use_mgr()->ForEachUser( |
273 | 474k | i, [&work_list, to_kill, &seen](Instruction* user) { |
274 | 474k | if (user->IsNonSemanticInstruction() && seen.insert(user).second) { |
275 | 0 | work_list.push_back(user); |
276 | 0 | to_kill->insert(user); |
277 | 0 | } |
278 | 474k | }); |
279 | 391k | } |
280 | 391k | } |
281 | | |
282 | 0 | bool IRContext::KillDef(uint32_t id) { |
283 | 0 | Instruction* def = get_def_use_mgr()->GetDef(id); |
284 | 0 | if (def != nullptr) { |
285 | 0 | KillInst(def); |
286 | 0 | return true; |
287 | 0 | } |
288 | 0 | return false; |
289 | 0 | } |
290 | | |
291 | 0 | bool IRContext::RemoveCapability(spv::Capability capability) { |
292 | 0 | const bool removed = KillInstructionIf( |
293 | 0 | module()->capability_begin(), module()->capability_end(), |
294 | 0 | [capability](Instruction* inst) { |
295 | 0 | return static_cast<spv::Capability>(inst->GetSingleWordOperand(0)) == |
296 | 0 | capability; |
297 | 0 | }); |
298 | |
|
299 | 0 | if (removed && feature_mgr_ != nullptr) { |
300 | 0 | feature_mgr_->RemoveCapability(capability); |
301 | 0 | } |
302 | |
|
303 | 0 | return removed; |
304 | 0 | } |
305 | | |
306 | 0 | bool IRContext::RemoveExtension(Extension extension) { |
307 | 0 | const std::string_view extensionName = ExtensionToString(extension); |
308 | 0 | const bool removed = KillInstructionIf( |
309 | 0 | module()->extension_begin(), module()->extension_end(), |
310 | 0 | [&extensionName](Instruction* inst) { |
311 | 0 | return inst->GetOperand(0).AsString() == extensionName; |
312 | 0 | }); |
313 | |
|
314 | 0 | if (removed && feature_mgr_ != nullptr) { |
315 | 0 | feature_mgr_->RemoveExtension(extension); |
316 | 0 | } |
317 | |
|
318 | 0 | return removed; |
319 | 0 | } |
320 | | |
321 | 1.55M | bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) { |
322 | 1.55M | return ReplaceAllUsesWithPredicate(before, after, |
323 | 1.55M | [](Instruction*) { return true; }); |
324 | 1.55M | } |
325 | | |
326 | | bool IRContext::ReplaceAllUsesWithPredicate( |
327 | | uint32_t before, uint32_t after, |
328 | 3.99M | const std::function<bool(Instruction*)>& predicate) { |
329 | 3.99M | if (before == after) return false; |
330 | | |
331 | 3.99M | if (AreAnalysesValid(kAnalysisDebugInfo)) { |
332 | 459k | get_debug_info_mgr()->ReplaceAllUsesInDebugScopeWithPredicate(before, after, |
333 | 459k | predicate); |
334 | 459k | } |
335 | | |
336 | | // Ensure that |after| has been registered as def. |
337 | 3.99M | assert(get_def_use_mgr()->GetDef(after) && |
338 | 3.99M | "'after' is not a registered def."); |
339 | | |
340 | 3.99M | std::vector<std::pair<Instruction*, uint32_t>> uses_to_update; |
341 | 3.99M | get_def_use_mgr()->ForEachUse( |
342 | 4.40M | before, [&predicate, &uses_to_update](Instruction* user, uint32_t index) { |
343 | 4.40M | if (predicate(user)) { |
344 | 4.32M | uses_to_update.emplace_back(user, index); |
345 | 4.32M | } |
346 | 4.40M | }); |
347 | | |
348 | 3.99M | Instruction* prev = nullptr; |
349 | 4.32M | for (auto p : uses_to_update) { |
350 | 4.32M | Instruction* user = p.first; |
351 | 4.32M | uint32_t index = p.second; |
352 | 4.32M | if (prev == nullptr || prev != user) { |
353 | 4.22M | ForgetUses(user); |
354 | 4.22M | prev = user; |
355 | 4.22M | } |
356 | 4.32M | const uint32_t type_result_id_count = |
357 | 4.32M | (user->result_id() != 0) + (user->type_id() != 0); |
358 | | |
359 | 4.32M | if (index < type_result_id_count) { |
360 | | // Update the type_id. Note that result id is immutable so it should |
361 | | // never be updated. |
362 | 0 | if (user->type_id() != 0 && index == 0) { |
363 | 0 | user->SetResultType(after); |
364 | 0 | } else if (user->type_id() == 0) { |
365 | 0 | SPIRV_ASSERT(consumer_, false, |
366 | 0 | "Result type id considered as use while the instruction " |
367 | 0 | "doesn't have a result type id."); |
368 | 0 | (void)consumer_; // Makes the compiler happy for release build. |
369 | 0 | } else { |
370 | 0 | SPIRV_ASSERT(consumer_, false, |
371 | 0 | "Trying setting the immutable result id."); |
372 | 0 | } |
373 | 4.32M | } else { |
374 | | // Update an in-operand. |
375 | 4.32M | uint32_t in_operand_pos = index - type_result_id_count; |
376 | | // Make the modification in the instruction. |
377 | 4.32M | user->SetInOperand(in_operand_pos, {after}); |
378 | 4.32M | } |
379 | 4.32M | AnalyzeUses(user); |
380 | 4.32M | } |
381 | 3.99M | return true; |
382 | 3.99M | } |
383 | | |
384 | 694k | bool IRContext::IsConsistent() { |
385 | | #ifndef SPIRV_CHECK_CONTEXT |
386 | | return true; |
387 | | #else |
388 | 694k | if (AreAnalysesValid(kAnalysisDefUse)) { |
389 | 554k | analysis::DefUseManager new_def_use(module()); |
390 | 554k | if (!CompareAndPrintDifferences(*get_def_use_mgr(), new_def_use)) { |
391 | 0 | return false; |
392 | 0 | } |
393 | 554k | } |
394 | | |
395 | 694k | return true; |
396 | 0 | if (AreAnalysesValid(kAnalysisIdToFuncMapping)) { |
397 | 0 | for (auto& fn : *module_) { |
398 | 0 | if (id_to_func_[fn.result_id()] != &fn) { |
399 | 0 | return false; |
400 | 0 | } |
401 | 0 | } |
402 | 0 | } |
403 | | |
404 | 0 | if (AreAnalysesValid(kAnalysisIdToGraphMapping)) { |
405 | 0 | for (auto& g : module_->graphs()) { |
406 | 0 | if (id_to_graph_[g->DefInst().result_id()] != g.get()) { |
407 | 0 | return false; |
408 | 0 | } |
409 | 0 | } |
410 | 0 | } |
411 | | |
412 | 0 | if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) { |
413 | 0 | for (auto& func : *module()) { |
414 | 0 | for (auto& block : func) { |
415 | 0 | if (!block.WhileEachInst([this, &block](Instruction* inst) { |
416 | 0 | if (get_instr_block(inst) != &block) { |
417 | 0 | return false; |
418 | 0 | } |
419 | 0 | return true; |
420 | 0 | })) { |
421 | 0 | return false; |
422 | 0 | } |
423 | 0 | } |
424 | 0 | } |
425 | 0 | } |
426 | | |
427 | 0 | if (!CheckCFG()) { |
428 | 0 | return false; |
429 | 0 | } |
430 | | |
431 | 0 | if (AreAnalysesValid(kAnalysisDecorations)) { |
432 | 0 | analysis::DecorationManager* dec_mgr = get_decoration_mgr(); |
433 | 0 | analysis::DecorationManager current(module()); |
434 | |
|
435 | 0 | if (*dec_mgr != current) { |
436 | 0 | return false; |
437 | 0 | } |
438 | 0 | } |
439 | | |
440 | 0 | if (feature_mgr_ != nullptr) { |
441 | 0 | FeatureManager current(grammar_); |
442 | 0 | current.Analyze(module()); |
443 | |
|
444 | 0 | if (current != *feature_mgr_) { |
445 | 0 | return false; |
446 | 0 | } |
447 | 0 | } |
448 | 0 | return true; |
449 | 0 | #endif |
450 | 0 | } |
451 | | |
452 | 4.78M | void IRContext::ForgetUses(Instruction* inst) { |
453 | 4.78M | if (AreAnalysesValid(kAnalysisDefUse)) { |
454 | 4.78M | get_def_use_mgr()->EraseUseRecordsOfOperandIds(inst); |
455 | 4.78M | } |
456 | 4.78M | if (AreAnalysesValid(kAnalysisDecorations)) { |
457 | 4.59M | if (inst->IsDecoration()) { |
458 | 598 | get_decoration_mgr()->RemoveDecoration(inst); |
459 | 598 | } |
460 | 4.59M | } |
461 | 4.78M | if (AreAnalysesValid(kAnalysisDebugInfo)) { |
462 | 521k | get_debug_info_mgr()->ClearDebugInfo(inst); |
463 | 521k | } |
464 | 4.78M | RemoveFromIdToName(inst); |
465 | 4.78M | } |
466 | | |
467 | 19.4M | void IRContext::AnalyzeUses(Instruction* inst) { |
468 | 19.4M | if (AreAnalysesValid(kAnalysisDefUse)) { |
469 | 19.3M | get_def_use_mgr()->AnalyzeInstUse(inst); |
470 | 19.3M | } |
471 | 19.4M | if (AreAnalysesValid(kAnalysisDecorations)) { |
472 | 19.1M | if (inst->IsDecoration()) { |
473 | 225k | get_decoration_mgr()->AddDecoration(inst); |
474 | 225k | } |
475 | 19.1M | } |
476 | 19.4M | if (AreAnalysesValid(kAnalysisDebugInfo)) { |
477 | 12.4M | get_debug_info_mgr()->AnalyzeDebugInst(inst); |
478 | 12.4M | } |
479 | 19.4M | if (id_to_name_ && (inst->opcode() == spv::Op::OpName || |
480 | 3.91M | inst->opcode() == spv::Op::OpMemberName)) { |
481 | 155 | id_to_name_->insert({inst->GetSingleWordInOperand(0), inst}); |
482 | 155 | } |
483 | 19.4M | } |
484 | | |
485 | 8.09M | void IRContext::KillNamesAndDecorates(uint32_t id) { |
486 | 8.09M | analysis::DecorationManager* dec_mgr = get_decoration_mgr(); |
487 | 8.09M | dec_mgr->RemoveDecorationsFrom(id); |
488 | | |
489 | 8.09M | std::vector<Instruction*> name_to_kill; |
490 | 8.09M | for (auto name : GetNames(id)) { |
491 | 37.6k | name_to_kill.push_back(name.second); |
492 | 37.6k | } |
493 | 8.09M | for (Instruction* name_inst : name_to_kill) { |
494 | 37.6k | KillInst(name_inst); |
495 | 37.6k | } |
496 | 8.09M | } |
497 | | |
498 | 19.3M | void IRContext::KillNamesAndDecorates(Instruction* inst) { |
499 | 19.3M | const uint32_t rId = inst->result_id(); |
500 | 19.3M | if (rId == 0) return; |
501 | 7.54M | KillNamesAndDecorates(rId); |
502 | 7.54M | } |
503 | | |
504 | 18.9M | void IRContext::KillOperandFromDebugInstructions(Instruction* inst) { |
505 | 18.9M | const auto opcode = inst->opcode(); |
506 | 18.9M | const uint32_t id = inst->result_id(); |
507 | | // Kill id of OpFunction from DebugFunction. |
508 | 18.9M | if (opcode == spv::Op::OpFunction) { |
509 | 11.4k | for (auto it = module()->ext_inst_debuginfo_begin(); |
510 | 11.4k | it != module()->ext_inst_debuginfo_end(); ++it) { |
511 | 0 | if (it->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugFunction) |
512 | 0 | continue; |
513 | 0 | auto& operand = it->GetOperand(kDebugFunctionOperandFunctionIndex); |
514 | 0 | if (operand.words[0] == id) { |
515 | 0 | operand.words[0] = |
516 | 0 | get_debug_info_mgr()->GetDebugInfoNone()->result_id(); |
517 | 0 | get_def_use_mgr()->AnalyzeInstUse(&*it); |
518 | 0 | } |
519 | 0 | } |
520 | 11.4k | } |
521 | | // Kill id of OpVariable for global variable from DebugGlobalVariable. |
522 | 18.9M | if (opcode == spv::Op::OpVariable || IsConstantInst(opcode)) { |
523 | 791k | for (auto it = module()->ext_inst_debuginfo_begin(); |
524 | 791k | it != module()->ext_inst_debuginfo_end(); ++it) { |
525 | 0 | if (it->GetCommonDebugOpcode() != CommonDebugInfoDebugGlobalVariable) |
526 | 0 | continue; |
527 | 0 | auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex); |
528 | 0 | if (operand.words[0] == id) { |
529 | 0 | operand.words[0] = |
530 | 0 | get_debug_info_mgr()->GetDebugInfoNone()->result_id(); |
531 | 0 | get_def_use_mgr()->AnalyzeInstUse(&*it); |
532 | 0 | } |
533 | 0 | } |
534 | 791k | } |
535 | 18.9M | } |
536 | | |
537 | 18.9M | void IRContext::KillRelatedDebugScopes(Instruction* inst) { |
538 | | // Extension has been fully unloaded, remove debug scope from every |
539 | | // instruction. |
540 | 18.9M | if (inst->opcode() == spv::Op::OpExtInstImport) { |
541 | 0 | const std::string extension_name = inst->GetInOperand(0).AsString(); |
542 | 0 | if (extension_name.compare(0, 29, "NonSemantic.Shader.DebugInfo.") == 0 || |
543 | 0 | extension_name == "OpenCL.DebugInfo.100") { |
544 | 0 | module()->ForEachInst([](Instruction* child) { |
545 | 0 | child->SetDebugScope(DebugScope(kNoDebugScope, kNoInlinedAt)); |
546 | 0 | }); |
547 | 0 | } |
548 | 0 | } |
549 | 18.9M | } |
550 | | |
551 | 119k | void IRContext::AddCombinatorsForCapability(uint32_t capability) { |
552 | 119k | spv::Capability cap = spv::Capability(capability); |
553 | 119k | if (cap == spv::Capability::Shader) { |
554 | 53.3k | combinator_ops_[0].insert( |
555 | 53.3k | {(uint32_t)spv::Op::OpNop, |
556 | 53.3k | (uint32_t)spv::Op::OpUndef, |
557 | 53.3k | (uint32_t)spv::Op::OpConstant, |
558 | 53.3k | (uint32_t)spv::Op::OpConstantTrue, |
559 | 53.3k | (uint32_t)spv::Op::OpConstantFalse, |
560 | 53.3k | (uint32_t)spv::Op::OpConstantComposite, |
561 | 53.3k | (uint32_t)spv::Op::OpConstantSampler, |
562 | 53.3k | (uint32_t)spv::Op::OpConstantNull, |
563 | 53.3k | (uint32_t)spv::Op::OpTypeVoid, |
564 | 53.3k | (uint32_t)spv::Op::OpTypeBool, |
565 | 53.3k | (uint32_t)spv::Op::OpTypeInt, |
566 | 53.3k | (uint32_t)spv::Op::OpTypeFloat, |
567 | 53.3k | (uint32_t)spv::Op::OpTypeVector, |
568 | 53.3k | (uint32_t)spv::Op::OpTypeMatrix, |
569 | 53.3k | (uint32_t)spv::Op::OpTypeImage, |
570 | 53.3k | (uint32_t)spv::Op::OpTypeSampler, |
571 | 53.3k | (uint32_t)spv::Op::OpTypeSampledImage, |
572 | 53.3k | (uint32_t)spv::Op::OpTypeAccelerationStructureNV, |
573 | 53.3k | (uint32_t)spv::Op::OpTypeAccelerationStructureKHR, |
574 | 53.3k | (uint32_t)spv::Op::OpTypeRayQueryKHR, |
575 | 53.3k | (uint32_t)spv::Op::OpTypeHitObjectNV, |
576 | 53.3k | (uint32_t)spv::Op::OpTypeHitObjectEXT, |
577 | 53.3k | (uint32_t)spv::Op::OpTypeArray, |
578 | 53.3k | (uint32_t)spv::Op::OpTypeRuntimeArray, |
579 | 53.3k | (uint32_t)spv::Op::OpTypeNodePayloadArrayAMDX, |
580 | 53.3k | (uint32_t)spv::Op::OpTypeStruct, |
581 | 53.3k | (uint32_t)spv::Op::OpTypeOpaque, |
582 | 53.3k | (uint32_t)spv::Op::OpTypePointer, |
583 | 53.3k | (uint32_t)spv::Op::OpTypeUntypedPointerKHR, |
584 | 53.3k | (uint32_t)spv::Op::OpTypeFunction, |
585 | 53.3k | (uint32_t)spv::Op::OpTypeEvent, |
586 | 53.3k | (uint32_t)spv::Op::OpTypeDeviceEvent, |
587 | 53.3k | (uint32_t)spv::Op::OpTypeReserveId, |
588 | 53.3k | (uint32_t)spv::Op::OpTypeQueue, |
589 | 53.3k | (uint32_t)spv::Op::OpTypePipe, |
590 | 53.3k | (uint32_t)spv::Op::OpTypeForwardPointer, |
591 | 53.3k | (uint32_t)spv::Op::OpVariable, |
592 | 53.3k | (uint32_t)spv::Op::OpUntypedVariableKHR, |
593 | 53.3k | (uint32_t)spv::Op::OpImageTexelPointer, |
594 | 53.3k | (uint32_t)spv::Op::OpLoad, |
595 | 53.3k | (uint32_t)spv::Op::OpAccessChain, |
596 | 53.3k | (uint32_t)spv::Op::OpInBoundsAccessChain, |
597 | 53.3k | (uint32_t)spv::Op::OpUntypedAccessChainKHR, |
598 | 53.3k | (uint32_t)spv::Op::OpArrayLength, |
599 | 53.3k | (uint32_t)spv::Op::OpVectorExtractDynamic, |
600 | 53.3k | (uint32_t)spv::Op::OpVectorInsertDynamic, |
601 | 53.3k | (uint32_t)spv::Op::OpVectorShuffle, |
602 | 53.3k | (uint32_t)spv::Op::OpCompositeConstruct, |
603 | 53.3k | (uint32_t)spv::Op::OpCompositeExtract, |
604 | 53.3k | (uint32_t)spv::Op::OpCompositeInsert, |
605 | 53.3k | (uint32_t)spv::Op::OpCopyLogical, |
606 | 53.3k | (uint32_t)spv::Op::OpCopyObject, |
607 | 53.3k | (uint32_t)spv::Op::OpTranspose, |
608 | 53.3k | (uint32_t)spv::Op::OpSampledImage, |
609 | 53.3k | (uint32_t)spv::Op::OpImageSampleImplicitLod, |
610 | 53.3k | (uint32_t)spv::Op::OpImageSampleExplicitLod, |
611 | 53.3k | (uint32_t)spv::Op::OpImageSampleDrefImplicitLod, |
612 | 53.3k | (uint32_t)spv::Op::OpImageSampleDrefExplicitLod, |
613 | 53.3k | (uint32_t)spv::Op::OpImageSampleProjImplicitLod, |
614 | 53.3k | (uint32_t)spv::Op::OpImageSampleProjExplicitLod, |
615 | 53.3k | (uint32_t)spv::Op::OpImageSampleProjDrefImplicitLod, |
616 | 53.3k | (uint32_t)spv::Op::OpImageSampleProjDrefExplicitLod, |
617 | 53.3k | (uint32_t)spv::Op::OpImageFetch, |
618 | 53.3k | (uint32_t)spv::Op::OpImageGather, |
619 | 53.3k | (uint32_t)spv::Op::OpImageDrefGather, |
620 | 53.3k | (uint32_t)spv::Op::OpImageRead, |
621 | 53.3k | (uint32_t)spv::Op::OpImage, |
622 | 53.3k | (uint32_t)spv::Op::OpImageQueryFormat, |
623 | 53.3k | (uint32_t)spv::Op::OpImageQueryOrder, |
624 | 53.3k | (uint32_t)spv::Op::OpImageQuerySizeLod, |
625 | 53.3k | (uint32_t)spv::Op::OpImageQuerySize, |
626 | 53.3k | (uint32_t)spv::Op::OpImageQueryLevels, |
627 | 53.3k | (uint32_t)spv::Op::OpImageQuerySamples, |
628 | 53.3k | (uint32_t)spv::Op::OpConvertFToU, |
629 | 53.3k | (uint32_t)spv::Op::OpConvertFToS, |
630 | 53.3k | (uint32_t)spv::Op::OpConvertSToF, |
631 | 53.3k | (uint32_t)spv::Op::OpConvertUToF, |
632 | 53.3k | (uint32_t)spv::Op::OpUConvert, |
633 | 53.3k | (uint32_t)spv::Op::OpSConvert, |
634 | 53.3k | (uint32_t)spv::Op::OpFConvert, |
635 | 53.3k | (uint32_t)spv::Op::OpQuantizeToF16, |
636 | 53.3k | (uint32_t)spv::Op::OpBitcast, |
637 | 53.3k | (uint32_t)spv::Op::OpSNegate, |
638 | 53.3k | (uint32_t)spv::Op::OpFNegate, |
639 | 53.3k | (uint32_t)spv::Op::OpIAdd, |
640 | 53.3k | (uint32_t)spv::Op::OpFAdd, |
641 | 53.3k | (uint32_t)spv::Op::OpISub, |
642 | 53.3k | (uint32_t)spv::Op::OpFSub, |
643 | 53.3k | (uint32_t)spv::Op::OpIMul, |
644 | 53.3k | (uint32_t)spv::Op::OpFMul, |
645 | 53.3k | (uint32_t)spv::Op::OpUDiv, |
646 | 53.3k | (uint32_t)spv::Op::OpSDiv, |
647 | 53.3k | (uint32_t)spv::Op::OpFDiv, |
648 | 53.3k | (uint32_t)spv::Op::OpUMod, |
649 | 53.3k | (uint32_t)spv::Op::OpSRem, |
650 | 53.3k | (uint32_t)spv::Op::OpSMod, |
651 | 53.3k | (uint32_t)spv::Op::OpFRem, |
652 | 53.3k | (uint32_t)spv::Op::OpFMod, |
653 | 53.3k | (uint32_t)spv::Op::OpVectorTimesScalar, |
654 | 53.3k | (uint32_t)spv::Op::OpMatrixTimesScalar, |
655 | 53.3k | (uint32_t)spv::Op::OpVectorTimesMatrix, |
656 | 53.3k | (uint32_t)spv::Op::OpMatrixTimesVector, |
657 | 53.3k | (uint32_t)spv::Op::OpMatrixTimesMatrix, |
658 | 53.3k | (uint32_t)spv::Op::OpOuterProduct, |
659 | 53.3k | (uint32_t)spv::Op::OpDot, |
660 | 53.3k | (uint32_t)spv::Op::OpIAddCarry, |
661 | 53.3k | (uint32_t)spv::Op::OpISubBorrow, |
662 | 53.3k | (uint32_t)spv::Op::OpUMulExtended, |
663 | 53.3k | (uint32_t)spv::Op::OpSMulExtended, |
664 | 53.3k | (uint32_t)spv::Op::OpAny, |
665 | 53.3k | (uint32_t)spv::Op::OpAll, |
666 | 53.3k | (uint32_t)spv::Op::OpIsNan, |
667 | 53.3k | (uint32_t)spv::Op::OpIsInf, |
668 | 53.3k | (uint32_t)spv::Op::OpLogicalEqual, |
669 | 53.3k | (uint32_t)spv::Op::OpLogicalNotEqual, |
670 | 53.3k | (uint32_t)spv::Op::OpLogicalOr, |
671 | 53.3k | (uint32_t)spv::Op::OpLogicalAnd, |
672 | 53.3k | (uint32_t)spv::Op::OpLogicalNot, |
673 | 53.3k | (uint32_t)spv::Op::OpSelect, |
674 | 53.3k | (uint32_t)spv::Op::OpIEqual, |
675 | 53.3k | (uint32_t)spv::Op::OpINotEqual, |
676 | 53.3k | (uint32_t)spv::Op::OpUGreaterThan, |
677 | 53.3k | (uint32_t)spv::Op::OpSGreaterThan, |
678 | 53.3k | (uint32_t)spv::Op::OpUGreaterThanEqual, |
679 | 53.3k | (uint32_t)spv::Op::OpSGreaterThanEqual, |
680 | 53.3k | (uint32_t)spv::Op::OpULessThan, |
681 | 53.3k | (uint32_t)spv::Op::OpSLessThan, |
682 | 53.3k | (uint32_t)spv::Op::OpULessThanEqual, |
683 | 53.3k | (uint32_t)spv::Op::OpSLessThanEqual, |
684 | 53.3k | (uint32_t)spv::Op::OpFOrdEqual, |
685 | 53.3k | (uint32_t)spv::Op::OpFUnordEqual, |
686 | 53.3k | (uint32_t)spv::Op::OpFOrdNotEqual, |
687 | 53.3k | (uint32_t)spv::Op::OpFUnordNotEqual, |
688 | 53.3k | (uint32_t)spv::Op::OpFOrdLessThan, |
689 | 53.3k | (uint32_t)spv::Op::OpFUnordLessThan, |
690 | 53.3k | (uint32_t)spv::Op::OpFOrdGreaterThan, |
691 | 53.3k | (uint32_t)spv::Op::OpFUnordGreaterThan, |
692 | 53.3k | (uint32_t)spv::Op::OpFOrdLessThanEqual, |
693 | 53.3k | (uint32_t)spv::Op::OpFUnordLessThanEqual, |
694 | 53.3k | (uint32_t)spv::Op::OpFOrdGreaterThanEqual, |
695 | 53.3k | (uint32_t)spv::Op::OpFUnordGreaterThanEqual, |
696 | 53.3k | (uint32_t)spv::Op::OpShiftRightLogical, |
697 | 53.3k | (uint32_t)spv::Op::OpShiftRightArithmetic, |
698 | 53.3k | (uint32_t)spv::Op::OpShiftLeftLogical, |
699 | 53.3k | (uint32_t)spv::Op::OpBitwiseOr, |
700 | 53.3k | (uint32_t)spv::Op::OpBitwiseXor, |
701 | 53.3k | (uint32_t)spv::Op::OpBitwiseAnd, |
702 | 53.3k | (uint32_t)spv::Op::OpNot, |
703 | 53.3k | (uint32_t)spv::Op::OpBitFieldInsert, |
704 | 53.3k | (uint32_t)spv::Op::OpBitFieldSExtract, |
705 | 53.3k | (uint32_t)spv::Op::OpBitFieldUExtract, |
706 | 53.3k | (uint32_t)spv::Op::OpBitReverse, |
707 | 53.3k | (uint32_t)spv::Op::OpBitCount, |
708 | 53.3k | (uint32_t)spv::Op::OpPhi, |
709 | 53.3k | (uint32_t)spv::Op::OpImageSparseSampleImplicitLod, |
710 | 53.3k | (uint32_t)spv::Op::OpImageSparseSampleExplicitLod, |
711 | 53.3k | (uint32_t)spv::Op::OpImageSparseSampleDrefImplicitLod, |
712 | 53.3k | (uint32_t)spv::Op::OpImageSparseSampleDrefExplicitLod, |
713 | 53.3k | (uint32_t)spv::Op::OpImageSparseSampleProjImplicitLod, |
714 | 53.3k | (uint32_t)spv::Op::OpImageSparseSampleProjExplicitLod, |
715 | 53.3k | (uint32_t)spv::Op::OpImageSparseSampleProjDrefImplicitLod, |
716 | 53.3k | (uint32_t)spv::Op::OpImageSparseSampleProjDrefExplicitLod, |
717 | 53.3k | (uint32_t)spv::Op::OpImageSparseFetch, |
718 | 53.3k | (uint32_t)spv::Op::OpImageSparseGather, |
719 | 53.3k | (uint32_t)spv::Op::OpImageSparseDrefGather, |
720 | 53.3k | (uint32_t)spv::Op::OpImageSparseTexelsResident, |
721 | 53.3k | (uint32_t)spv::Op::OpImageSparseRead, |
722 | 53.3k | (uint32_t)spv::Op::OpSizeOf}); |
723 | 53.3k | } |
724 | 119k | } |
725 | | |
726 | 39.7k | void IRContext::AddCombinatorsForExtension(Instruction* extension) { |
727 | 39.7k | assert(extension->opcode() == spv::Op::OpExtInstImport && |
728 | 39.7k | "Expecting an import of an extension's instruction set."); |
729 | 39.7k | const std::string extension_name = extension->GetInOperand(0).AsString(); |
730 | 39.7k | if (extension_name == "GLSL.std.450") { |
731 | 39.5k | combinator_ops_[extension->result_id()] = { |
732 | 39.5k | (uint32_t)GLSLstd450Round, |
733 | 39.5k | (uint32_t)GLSLstd450RoundEven, |
734 | 39.5k | (uint32_t)GLSLstd450Trunc, |
735 | 39.5k | (uint32_t)GLSLstd450FAbs, |
736 | 39.5k | (uint32_t)GLSLstd450SAbs, |
737 | 39.5k | (uint32_t)GLSLstd450FSign, |
738 | 39.5k | (uint32_t)GLSLstd450SSign, |
739 | 39.5k | (uint32_t)GLSLstd450Floor, |
740 | 39.5k | (uint32_t)GLSLstd450Ceil, |
741 | 39.5k | (uint32_t)GLSLstd450Fract, |
742 | 39.5k | (uint32_t)GLSLstd450Radians, |
743 | 39.5k | (uint32_t)GLSLstd450Degrees, |
744 | 39.5k | (uint32_t)GLSLstd450Sin, |
745 | 39.5k | (uint32_t)GLSLstd450Cos, |
746 | 39.5k | (uint32_t)GLSLstd450Tan, |
747 | 39.5k | (uint32_t)GLSLstd450Asin, |
748 | 39.5k | (uint32_t)GLSLstd450Acos, |
749 | 39.5k | (uint32_t)GLSLstd450Atan, |
750 | 39.5k | (uint32_t)GLSLstd450Sinh, |
751 | 39.5k | (uint32_t)GLSLstd450Cosh, |
752 | 39.5k | (uint32_t)GLSLstd450Tanh, |
753 | 39.5k | (uint32_t)GLSLstd450Asinh, |
754 | 39.5k | (uint32_t)GLSLstd450Acosh, |
755 | 39.5k | (uint32_t)GLSLstd450Atanh, |
756 | 39.5k | (uint32_t)GLSLstd450Atan2, |
757 | 39.5k | (uint32_t)GLSLstd450Pow, |
758 | 39.5k | (uint32_t)GLSLstd450Exp, |
759 | 39.5k | (uint32_t)GLSLstd450Log, |
760 | 39.5k | (uint32_t)GLSLstd450Exp2, |
761 | 39.5k | (uint32_t)GLSLstd450Log2, |
762 | 39.5k | (uint32_t)GLSLstd450Sqrt, |
763 | 39.5k | (uint32_t)GLSLstd450InverseSqrt, |
764 | 39.5k | (uint32_t)GLSLstd450Determinant, |
765 | 39.5k | (uint32_t)GLSLstd450MatrixInverse, |
766 | 39.5k | (uint32_t)GLSLstd450ModfStruct, |
767 | 39.5k | (uint32_t)GLSLstd450FMin, |
768 | 39.5k | (uint32_t)GLSLstd450UMin, |
769 | 39.5k | (uint32_t)GLSLstd450SMin, |
770 | 39.5k | (uint32_t)GLSLstd450FMax, |
771 | 39.5k | (uint32_t)GLSLstd450UMax, |
772 | 39.5k | (uint32_t)GLSLstd450SMax, |
773 | 39.5k | (uint32_t)GLSLstd450FClamp, |
774 | 39.5k | (uint32_t)GLSLstd450UClamp, |
775 | 39.5k | (uint32_t)GLSLstd450SClamp, |
776 | 39.5k | (uint32_t)GLSLstd450FMix, |
777 | 39.5k | (uint32_t)GLSLstd450IMix, |
778 | 39.5k | (uint32_t)GLSLstd450Step, |
779 | 39.5k | (uint32_t)GLSLstd450SmoothStep, |
780 | 39.5k | (uint32_t)GLSLstd450Fma, |
781 | 39.5k | (uint32_t)GLSLstd450FrexpStruct, |
782 | 39.5k | (uint32_t)GLSLstd450Ldexp, |
783 | 39.5k | (uint32_t)GLSLstd450PackSnorm4x8, |
784 | 39.5k | (uint32_t)GLSLstd450PackUnorm4x8, |
785 | 39.5k | (uint32_t)GLSLstd450PackSnorm2x16, |
786 | 39.5k | (uint32_t)GLSLstd450PackUnorm2x16, |
787 | 39.5k | (uint32_t)GLSLstd450PackHalf2x16, |
788 | 39.5k | (uint32_t)GLSLstd450PackDouble2x32, |
789 | 39.5k | (uint32_t)GLSLstd450UnpackSnorm2x16, |
790 | 39.5k | (uint32_t)GLSLstd450UnpackUnorm2x16, |
791 | 39.5k | (uint32_t)GLSLstd450UnpackHalf2x16, |
792 | 39.5k | (uint32_t)GLSLstd450UnpackSnorm4x8, |
793 | 39.5k | (uint32_t)GLSLstd450UnpackUnorm4x8, |
794 | 39.5k | (uint32_t)GLSLstd450UnpackDouble2x32, |
795 | 39.5k | (uint32_t)GLSLstd450Length, |
796 | 39.5k | (uint32_t)GLSLstd450Distance, |
797 | 39.5k | (uint32_t)GLSLstd450Cross, |
798 | 39.5k | (uint32_t)GLSLstd450Normalize, |
799 | 39.5k | (uint32_t)GLSLstd450FaceForward, |
800 | 39.5k | (uint32_t)GLSLstd450Reflect, |
801 | 39.5k | (uint32_t)GLSLstd450Refract, |
802 | 39.5k | (uint32_t)GLSLstd450FindILsb, |
803 | 39.5k | (uint32_t)GLSLstd450FindSMsb, |
804 | 39.5k | (uint32_t)GLSLstd450FindUMsb, |
805 | 39.5k | (uint32_t)GLSLstd450InterpolateAtCentroid, |
806 | 39.5k | (uint32_t)GLSLstd450InterpolateAtSample, |
807 | 39.5k | (uint32_t)GLSLstd450InterpolateAtOffset, |
808 | 39.5k | (uint32_t)GLSLstd450NMin, |
809 | 39.5k | (uint32_t)GLSLstd450NMax, |
810 | 39.5k | (uint32_t)GLSLstd450NClamp}; |
811 | 39.5k | } else { |
812 | | // Map the result id to the empty set. |
813 | 189 | combinator_ops_[extension->result_id()]; |
814 | 189 | } |
815 | 39.7k | } |
816 | | |
817 | 53.4k | void IRContext::InitializeCombinators() { |
818 | 119k | for (auto capability : get_feature_mgr()->GetCapabilities()) { |
819 | 119k | AddCombinatorsForCapability(uint32_t(capability)); |
820 | 119k | } |
821 | | |
822 | 53.4k | for (auto& extension : module()->ext_inst_imports()) { |
823 | 39.7k | AddCombinatorsForExtension(&extension); |
824 | 39.7k | } |
825 | | |
826 | 53.4k | valid_analyses_ |= kAnalysisCombinators; |
827 | 53.4k | } |
828 | | |
829 | 23.7M | void IRContext::RemoveFromIdToName(const Instruction* inst) { |
830 | 23.7M | if (id_to_name_ && (inst->opcode() == spv::Op::OpName || |
831 | 11.0M | inst->opcode() == spv::Op::OpMemberName)) { |
832 | 49.4k | auto range = id_to_name_->equal_range(inst->GetSingleWordInOperand(0)); |
833 | 73.3k | for (auto it = range.first; it != range.second; ++it) { |
834 | 73.3k | if (it->second == inst) { |
835 | 49.4k | id_to_name_->erase(it); |
836 | 49.4k | break; |
837 | 49.4k | } |
838 | 73.3k | } |
839 | 49.4k | } |
840 | 23.7M | } |
841 | | |
842 | 51.6k | LoopDescriptor* IRContext::GetLoopDescriptor(const Function* f) { |
843 | 51.6k | if (!AreAnalysesValid(kAnalysisLoopAnalysis)) { |
844 | 16.0k | ResetLoopAnalysis(); |
845 | 16.0k | } |
846 | | |
847 | 51.6k | std::unordered_map<const Function*, LoopDescriptor>::iterator it = |
848 | 51.6k | loop_descriptors_.find(f); |
849 | 51.6k | if (it == loop_descriptors_.end()) { |
850 | 19.0k | return &loop_descriptors_ |
851 | 19.0k | .emplace(std::make_pair(f, LoopDescriptor(this, f))) |
852 | 19.0k | .first->second; |
853 | 19.0k | } |
854 | | |
855 | 32.5k | return &it->second; |
856 | 51.6k | } |
857 | | |
858 | 0 | uint32_t IRContext::FindBuiltinInputVar(uint32_t builtin) { |
859 | 0 | for (auto& a : module_->annotations()) { |
860 | 0 | if (spv::Op(a.opcode()) != spv::Op::OpDecorate) continue; |
861 | 0 | if (spv::Decoration(a.GetSingleWordInOperand( |
862 | 0 | kSpvDecorateDecorationInIdx)) != spv::Decoration::BuiltIn) |
863 | 0 | continue; |
864 | 0 | if (a.GetSingleWordInOperand(kSpvDecorateBuiltinInIdx) != builtin) continue; |
865 | 0 | uint32_t target_id = a.GetSingleWordInOperand(kSpvDecorateTargetIdInIdx); |
866 | 0 | Instruction* b_var = get_def_use_mgr()->GetDef(target_id); |
867 | 0 | if (b_var->opcode() != spv::Op::OpVariable) continue; |
868 | 0 | if (spv::StorageClass(b_var->GetSingleWordInOperand(0)) != |
869 | 0 | spv::StorageClass::Input) |
870 | 0 | continue; |
871 | 0 | return target_id; |
872 | 0 | } |
873 | 0 | return 0; |
874 | 0 | } |
875 | | |
876 | 0 | void IRContext::AddVarToEntryPoints(uint32_t var_id) { |
877 | 0 | uint32_t ocnt = 0; |
878 | 0 | for (auto& e : module()->entry_points()) { |
879 | 0 | bool found = false; |
880 | 0 | e.ForEachInOperand([&ocnt, &found, &var_id](const uint32_t* idp) { |
881 | 0 | if (ocnt >= kEntryPointInterfaceInIdx) { |
882 | 0 | if (*idp == var_id) found = true; |
883 | 0 | } |
884 | 0 | ++ocnt; |
885 | 0 | }); |
886 | 0 | if (!found) { |
887 | 0 | e.AddOperand({SPV_OPERAND_TYPE_ID, {var_id}}); |
888 | 0 | get_def_use_mgr()->AnalyzeInstDefUse(&e); |
889 | 0 | } |
890 | 0 | } |
891 | 0 | } |
892 | | |
893 | 0 | uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) { |
894 | 0 | if (!AreAnalysesValid(kAnalysisBuiltinVarId)) ResetBuiltinAnalysis(); |
895 | | // If cached, return it. |
896 | 0 | std::unordered_map<uint32_t, uint32_t>::iterator it = |
897 | 0 | builtin_var_id_map_.find(builtin); |
898 | 0 | if (it != builtin_var_id_map_.end()) return it->second; |
899 | | // Look for one in shader |
900 | 0 | uint32_t var_id = FindBuiltinInputVar(builtin); |
901 | 0 | if (var_id == 0) { |
902 | | // If not found, create it |
903 | | // TODO(greg-lunarg): Add support for all builtins |
904 | 0 | analysis::TypeManager* type_mgr = get_type_mgr(); |
905 | 0 | analysis::Type* reg_type; |
906 | 0 | switch (spv::BuiltIn(builtin)) { |
907 | 0 | case spv::BuiltIn::FragCoord: { |
908 | 0 | analysis::Float float_ty(32); |
909 | 0 | analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty); |
910 | 0 | analysis::Vector v4float_ty(reg_float_ty, 4); |
911 | 0 | reg_type = type_mgr->GetRegisteredType(&v4float_ty); |
912 | 0 | break; |
913 | 0 | } |
914 | 0 | case spv::BuiltIn::VertexIndex: |
915 | 0 | case spv::BuiltIn::InstanceIndex: |
916 | 0 | case spv::BuiltIn::PrimitiveId: |
917 | 0 | case spv::BuiltIn::InvocationId: |
918 | 0 | case spv::BuiltIn::SubgroupLocalInvocationId: { |
919 | 0 | analysis::Integer uint_ty(32, false); |
920 | 0 | reg_type = type_mgr->GetRegisteredType(&uint_ty); |
921 | 0 | break; |
922 | 0 | } |
923 | 0 | case spv::BuiltIn::GlobalInvocationId: |
924 | 0 | case spv::BuiltIn::LaunchIdNV: { |
925 | 0 | analysis::Integer uint_ty(32, false); |
926 | 0 | analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); |
927 | 0 | analysis::Vector v3uint_ty(reg_uint_ty, 3); |
928 | 0 | reg_type = type_mgr->GetRegisteredType(&v3uint_ty); |
929 | 0 | break; |
930 | 0 | } |
931 | 0 | case spv::BuiltIn::TessCoord: { |
932 | 0 | analysis::Float float_ty(32); |
933 | 0 | analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty); |
934 | 0 | analysis::Vector v3float_ty(reg_float_ty, 3); |
935 | 0 | reg_type = type_mgr->GetRegisteredType(&v3float_ty); |
936 | 0 | break; |
937 | 0 | } |
938 | 0 | case spv::BuiltIn::SubgroupLtMask: { |
939 | 0 | analysis::Integer uint_ty(32, false); |
940 | 0 | analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); |
941 | 0 | analysis::Vector v4uint_ty(reg_uint_ty, 4); |
942 | 0 | reg_type = type_mgr->GetRegisteredType(&v4uint_ty); |
943 | 0 | break; |
944 | 0 | } |
945 | 0 | default: { |
946 | 0 | assert(false && "unhandled builtin"); |
947 | 0 | return 0; |
948 | 0 | } |
949 | 0 | } |
950 | 0 | if (reg_type == nullptr) return 0; // Error |
951 | | |
952 | 0 | uint32_t type_id = type_mgr->GetTypeInstruction(reg_type); |
953 | 0 | uint32_t varTyPtrId = |
954 | 0 | type_mgr->FindPointerToType(type_id, spv::StorageClass::Input); |
955 | 0 | var_id = TakeNextId(); |
956 | 0 | if (var_id == 0) return 0; // Error |
957 | 0 | std::unique_ptr<Instruction> newVarOp( |
958 | 0 | new Instruction(this, spv::Op::OpVariable, varTyPtrId, var_id, |
959 | 0 | {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, |
960 | 0 | {uint32_t(spv::StorageClass::Input)}}})); |
961 | 0 | get_def_use_mgr()->AnalyzeInstDefUse(&*newVarOp); |
962 | 0 | module()->AddGlobalValue(std::move(newVarOp)); |
963 | 0 | get_decoration_mgr()->AddDecorationVal( |
964 | 0 | var_id, uint32_t(spv::Decoration::BuiltIn), builtin); |
965 | 0 | AddVarToEntryPoints(var_id); |
966 | 0 | } |
967 | 0 | builtin_var_id_map_[builtin] = var_id; |
968 | 0 | return var_id; |
969 | 0 | } |
970 | | |
971 | 402k | void IRContext::AddCalls(const Function* func, std::queue<uint32_t>* todo) { |
972 | 13.9M | for (auto bi = func->begin(); bi != func->end(); ++bi) |
973 | 72.5M | for (auto ii = bi->begin(); ii != bi->end(); ++ii) { |
974 | 58.9M | if (ii->opcode() == spv::Op::OpFunctionCall) |
975 | 225k | todo->push(ii->GetSingleWordInOperand(0)); |
976 | 58.9M | if (ii->opcode() == spv::Op::OpCooperativeMatrixPerElementOpNV) |
977 | 0 | todo->push(ii->GetSingleWordInOperand(1)); |
978 | 58.9M | if (ii->opcode() == spv::Op::OpCooperativeMatrixReduceNV) |
979 | 0 | todo->push(ii->GetSingleWordInOperand(2)); |
980 | 58.9M | if (ii->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) { |
981 | 0 | const auto memory_operands_index = 3; |
982 | 0 | auto mask = ii->GetSingleWordInOperand(memory_operands_index); |
983 | |
|
984 | 0 | uint32_t count = 1; |
985 | 0 | if (mask & uint32_t(spv::MemoryAccessMask::Aligned)) ++count; |
986 | 0 | if (mask & uint32_t(spv::MemoryAccessMask::MakePointerAvailableKHR)) |
987 | 0 | ++count; |
988 | 0 | if (mask & uint32_t(spv::MemoryAccessMask::MakePointerVisibleKHR)) |
989 | 0 | ++count; |
990 | |
|
991 | 0 | const auto tensor_operands_index = memory_operands_index + count; |
992 | 0 | mask = ii->GetSingleWordInOperand(tensor_operands_index); |
993 | 0 | count = 1; |
994 | 0 | if (mask & uint32_t(spv::TensorAddressingOperandsMask::TensorView)) |
995 | 0 | ++count; |
996 | |
|
997 | 0 | if (mask & uint32_t(spv::TensorAddressingOperandsMask::DecodeFunc)) { |
998 | 0 | todo->push(ii->GetSingleWordInOperand(tensor_operands_index + count)); |
999 | 0 | ++count; |
1000 | 0 | } |
1001 | 0 | if (mask & |
1002 | 0 | uint32_t(spv::TensorAddressingOperandsMask::DecodeVectorFunc)) { |
1003 | 0 | todo->push(ii->GetSingleWordInOperand(tensor_operands_index + count)); |
1004 | 0 | } |
1005 | 0 | } |
1006 | 58.9M | } |
1007 | 402k | } |
1008 | | |
1009 | 0 | bool IRContext::ProcessEntryPointCallTree(ProcessFunction& pfn) { |
1010 | | // Collect all of the entry points as the roots. |
1011 | 0 | std::queue<uint32_t> roots; |
1012 | 0 | for (auto& e : module()->entry_points()) { |
1013 | 0 | roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); |
1014 | 0 | } |
1015 | 0 | return ProcessCallTreeFromRoots(pfn, &roots); |
1016 | 0 | } |
1017 | | |
1018 | 339k | bool IRContext::ProcessReachableCallTree(ProcessFunction& pfn) { |
1019 | 339k | std::queue<uint32_t> roots; |
1020 | | |
1021 | | // Add all entry points since they can be reached from outside the module. |
1022 | 339k | for (auto& e : module()->entry_points()) |
1023 | 277k | roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); |
1024 | | |
1025 | | // Add all exported functions since they can be reached from outside the |
1026 | | // module. |
1027 | 48.3M | for (auto& a : annotations()) { |
1028 | | // TODO: Handle group decorations as well. Currently not generate by any |
1029 | | // front-end, but could be coming. |
1030 | 48.3M | if (a.opcode() == spv::Op::OpDecorate) { |
1031 | 1.92M | if (spv::Decoration(a.GetSingleWordOperand(1)) == |
1032 | 1.92M | spv::Decoration::LinkageAttributes) { |
1033 | 0 | uint32_t lastOperand = a.NumOperands() - 1; |
1034 | 0 | if (spv::LinkageType(a.GetSingleWordOperand(lastOperand)) == |
1035 | 0 | spv::LinkageType::Export) { |
1036 | 0 | uint32_t id = a.GetSingleWordOperand(0); |
1037 | 0 | if (GetFunction(id)) { |
1038 | 0 | roots.push(id); |
1039 | 0 | } |
1040 | 0 | } |
1041 | 0 | } |
1042 | 1.92M | } |
1043 | 48.3M | } |
1044 | | |
1045 | 339k | return ProcessCallTreeFromRoots(pfn, &roots); |
1046 | 339k | } |
1047 | | |
1048 | | bool IRContext::ProcessCallTreeFromRoots(ProcessFunction& pfn, |
1049 | 370k | std::queue<uint32_t>* roots) { |
1050 | | // Process call tree |
1051 | 370k | bool modified = false; |
1052 | 370k | std::unordered_set<uint32_t> done; |
1053 | | |
1054 | 880k | while (!roots->empty()) { |
1055 | 509k | const uint32_t fi = roots->front(); |
1056 | 509k | roots->pop(); |
1057 | 509k | if (done.insert(fi).second) { |
1058 | 376k | Function* fn = GetFunction(fi); |
1059 | 376k | assert(fn && "Trying to process a function that does not exist."); |
1060 | 376k | modified = pfn(fn) || modified; |
1061 | 376k | AddCalls(fn, roots); |
1062 | 376k | } |
1063 | 509k | } |
1064 | 370k | return modified; |
1065 | 370k | } |
1066 | | |
1067 | | void IRContext::CollectCallTreeFromRoots(unsigned entryId, |
1068 | 0 | std::unordered_set<uint32_t>* funcs) { |
1069 | 0 | std::queue<uint32_t> roots; |
1070 | 0 | roots.push(entryId); |
1071 | 0 | while (!roots.empty()) { |
1072 | 0 | const uint32_t fi = roots.front(); |
1073 | 0 | roots.pop(); |
1074 | 0 | funcs->insert(fi); |
1075 | 0 | Function* fn = GetFunction(fi); |
1076 | 0 | AddCalls(fn, &roots); |
1077 | 0 | } |
1078 | 0 | } |
1079 | | |
1080 | 0 | void IRContext::EmitErrorMessage(std::string message, Instruction* inst) { |
1081 | 0 | if (!consumer()) { |
1082 | 0 | return; |
1083 | 0 | } |
1084 | | |
1085 | 0 | Instruction* line_inst = inst; |
1086 | 0 | while (line_inst != nullptr) { // Stop at the beginning of the basic block. |
1087 | 0 | if (!line_inst->dbg_line_insts().empty()) { |
1088 | 0 | line_inst = &line_inst->dbg_line_insts().back(); |
1089 | 0 | if (line_inst->IsNoLine()) { |
1090 | 0 | line_inst = nullptr; |
1091 | 0 | } |
1092 | 0 | break; |
1093 | 0 | } |
1094 | 0 | line_inst = line_inst->PreviousNode(); |
1095 | 0 | } |
1096 | |
|
1097 | 0 | uint32_t line_number = 0; |
1098 | 0 | uint32_t col_number = 0; |
1099 | 0 | std::string source; |
1100 | 0 | if (line_inst != nullptr) { |
1101 | 0 | Instruction* file_name = |
1102 | 0 | get_def_use_mgr()->GetDef(line_inst->GetSingleWordInOperand(0)); |
1103 | 0 | source = file_name->GetInOperand(0).AsString(); |
1104 | | |
1105 | | // Get the line number and column number. |
1106 | 0 | line_number = line_inst->GetSingleWordInOperand(1); |
1107 | 0 | col_number = line_inst->GetSingleWordInOperand(2); |
1108 | 0 | } |
1109 | |
|
1110 | 0 | message += |
1111 | 0 | "\n " + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); |
1112 | 0 | consumer()(SPV_MSG_ERROR, source.c_str(), {line_number, col_number, 0}, |
1113 | 0 | message.c_str()); |
1114 | 0 | } |
1115 | | |
1116 | | // Gets the dominator analysis for function |f|. |
1117 | 1.36M | DominatorAnalysis* IRContext::GetDominatorAnalysis(const Function* f) { |
1118 | 1.36M | if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) { |
1119 | 56.4k | ResetDominatorAnalysis(); |
1120 | 56.4k | } |
1121 | | |
1122 | 1.36M | if (dominator_trees_.find(f) == dominator_trees_.end()) { |
1123 | 68.8k | dominator_trees_[f].InitializeTree(*cfg(), f); |
1124 | 68.8k | } |
1125 | | |
1126 | 1.36M | return &dominator_trees_[f]; |
1127 | 1.36M | } |
1128 | | |
1129 | | // Gets the postdominator analysis for function |f|. |
1130 | 0 | PostDominatorAnalysis* IRContext::GetPostDominatorAnalysis(const Function* f) { |
1131 | 0 | if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) { |
1132 | 0 | ResetDominatorAnalysis(); |
1133 | 0 | } |
1134 | |
|
1135 | 0 | if (post_dominator_trees_.find(f) == post_dominator_trees_.end()) { |
1136 | 0 | post_dominator_trees_[f].InitializeTree(*cfg(), f); |
1137 | 0 | } |
1138 | |
|
1139 | 0 | return &post_dominator_trees_[f]; |
1140 | 0 | } |
1141 | | |
1142 | 0 | bool IRContext::CheckCFG() { |
1143 | 0 | std::unordered_map<uint32_t, std::vector<uint32_t>> real_preds; |
1144 | 0 | if (!AreAnalysesValid(kAnalysisCFG)) { |
1145 | 0 | return true; |
1146 | 0 | } |
1147 | | |
1148 | 0 | for (Function& function : *module()) { |
1149 | 0 | for (const auto& bb : function) { |
1150 | 0 | bb.ForEachSuccessorLabel([&bb, &real_preds](const uint32_t lab_id) { |
1151 | 0 | real_preds[lab_id].push_back(bb.id()); |
1152 | 0 | }); |
1153 | 0 | } |
1154 | |
|
1155 | 0 | for (auto& bb : function) { |
1156 | 0 | std::vector<uint32_t> preds = cfg()->preds(bb.id()); |
1157 | 0 | std::vector<uint32_t> real = real_preds[bb.id()]; |
1158 | 0 | std::sort(preds.begin(), preds.end()); |
1159 | 0 | std::sort(real.begin(), real.end()); |
1160 | |
|
1161 | 0 | bool same = true; |
1162 | 0 | if (preds.size() != real.size()) { |
1163 | 0 | same = false; |
1164 | 0 | } |
1165 | |
|
1166 | 0 | for (size_t i = 0; i < real.size() && same; i++) { |
1167 | 0 | if (preds[i] != real[i]) { |
1168 | 0 | same = false; |
1169 | 0 | } |
1170 | 0 | } |
1171 | |
|
1172 | 0 | if (!same) { |
1173 | 0 | std::cerr << "Predecessors for " << bb.id() << " are different:\n"; |
1174 | |
|
1175 | 0 | std::cerr << "Real:"; |
1176 | 0 | for (uint32_t i : real) { |
1177 | 0 | std::cerr << ' ' << i; |
1178 | 0 | } |
1179 | 0 | std::cerr << std::endl; |
1180 | |
|
1181 | 0 | std::cerr << "Recorded:"; |
1182 | 0 | for (uint32_t i : preds) { |
1183 | 0 | std::cerr << ' ' << i; |
1184 | 0 | } |
1185 | 0 | std::cerr << std::endl; |
1186 | 0 | } |
1187 | 0 | if (!same) return false; |
1188 | 0 | } |
1189 | 0 | } |
1190 | | |
1191 | 0 | return true; |
1192 | 0 | } |
1193 | | |
1194 | 961k | bool IRContext::IsReachable(const opt::BasicBlock& bb) { |
1195 | 961k | auto enclosing_function = bb.GetParent(); |
1196 | 961k | return GetDominatorAnalysis(enclosing_function) |
1197 | 961k | ->Dominates(enclosing_function->entry().get(), &bb); |
1198 | 961k | } |
1199 | | |
1200 | 0 | spv::ExecutionModel IRContext::GetStage() { |
1201 | 0 | const auto& entry_points = module()->entry_points(); |
1202 | 0 | if (entry_points.empty()) { |
1203 | 0 | return spv::ExecutionModel::Max; |
1204 | 0 | } |
1205 | | |
1206 | 0 | uint32_t stage = entry_points.begin()->GetSingleWordInOperand( |
1207 | 0 | kEntryPointExecutionModelInIdx); |
1208 | 0 | auto it = std::find_if( |
1209 | 0 | entry_points.begin(), entry_points.end(), [stage](const Instruction& x) { |
1210 | 0 | return x.GetSingleWordInOperand(kEntryPointExecutionModelInIdx) != |
1211 | 0 | stage; |
1212 | 0 | }); |
1213 | 0 | if (it != entry_points.end()) { |
1214 | 0 | EmitErrorMessage("Mixed stage shader module not supported", &(*it)); |
1215 | 0 | } |
1216 | |
|
1217 | 0 | return static_cast<spv::ExecutionModel>(stage); |
1218 | 0 | } |
1219 | | |
1220 | | } // namespace opt |
1221 | | } // namespace spvtools |