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