• 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   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