• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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