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