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