| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197 |
- // Copyright (c) 2017 Google Inc.
- // Modifications Copyright (C) 2024 Advanced Micro Devices, Inc. All rights
- // reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "source/opt/ir_context.h"
- #include <cstring>
- #include "OpenCLDebugInfo100.h"
- #include "source/latest_version_glsl_std_450_header.h"
- #include "source/opt/log.h"
- #include "source/opt/reflect.h"
- namespace spvtools {
- namespace opt {
- namespace {
- constexpr int kSpvDecorateTargetIdInIdx = 0;
- constexpr int kSpvDecorateDecorationInIdx = 1;
- constexpr int kSpvDecorateBuiltinInIdx = 2;
- constexpr int kEntryPointInterfaceInIdx = 3;
- constexpr int kEntryPointFunctionIdInIdx = 1;
- constexpr int kEntryPointExecutionModelInIdx = 0;
- // Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo.100
- // extension instructions.
- constexpr uint32_t kDebugFunctionOperandFunctionIndex = 13;
- constexpr uint32_t kDebugGlobalVariableOperandVariableIndex = 11;
- } // namespace
- void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
- set = Analysis(set & ~valid_analyses_);
- if (set & kAnalysisDefUse) {
- BuildDefUseManager();
- }
- if (set & kAnalysisInstrToBlockMapping) {
- BuildInstrToBlockMapping();
- }
- if (set & kAnalysisDecorations) {
- BuildDecorationManager();
- }
- if (set & kAnalysisCFG) {
- BuildCFG();
- }
- if (set & kAnalysisDominatorAnalysis) {
- ResetDominatorAnalysis();
- }
- if (set & kAnalysisLoopAnalysis) {
- ResetLoopAnalysis();
- }
- if (set & kAnalysisBuiltinVarId) {
- ResetBuiltinAnalysis();
- }
- if (set & kAnalysisNameMap) {
- BuildIdToNameMap();
- }
- if (set & kAnalysisScalarEvolution) {
- BuildScalarEvolutionAnalysis();
- }
- if (set & kAnalysisRegisterPressure) {
- BuildRegPressureAnalysis();
- }
- if (set & kAnalysisValueNumberTable) {
- BuildValueNumberTable();
- }
- if (set & kAnalysisStructuredCFG) {
- BuildStructuredCFGAnalysis();
- }
- if (set & kAnalysisIdToFuncMapping) {
- BuildIdToFuncMapping();
- }
- if (set & kAnalysisConstants) {
- BuildConstantManager();
- }
- if (set & kAnalysisTypes) {
- BuildTypeManager();
- }
- if (set & kAnalysisDebugInfo) {
- BuildDebugInfoManager();
- }
- if (set & kAnalysisLiveness) {
- BuildLivenessManager();
- }
- if (set & kAnalysisIdToGraphMapping) {
- BuildIdToGraphMapping();
- }
- }
- void IRContext::InvalidateAnalysesExceptFor(
- IRContext::Analysis preserved_analyses) {
- uint32_t analyses_to_invalidate = valid_analyses_ & (~preserved_analyses);
- InvalidateAnalyses(static_cast<IRContext::Analysis>(analyses_to_invalidate));
- }
- void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
- // The ConstantManager and DebugInfoManager contain Type pointers. If the
- // TypeManager goes away, the ConstantManager and DebugInfoManager have to
- // go away.
- if (analyses_to_invalidate & kAnalysisTypes) {
- analyses_to_invalidate |= kAnalysisConstants;
- analyses_to_invalidate |= kAnalysisDebugInfo;
- }
- // The dominator analysis hold the pseudo entry and exit nodes from the CFG.
- // Also if the CFG change the dominators many changed as well, so the
- // dominator analysis should be invalidated as well.
- if (analyses_to_invalidate & kAnalysisCFG) {
- analyses_to_invalidate |= kAnalysisDominatorAnalysis;
- }
- if (analyses_to_invalidate & kAnalysisDefUse) {
- def_use_mgr_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisInstrToBlockMapping) {
- instr_to_block_.clear();
- }
- if (analyses_to_invalidate & kAnalysisDecorations) {
- decoration_mgr_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisCombinators) {
- combinator_ops_.clear();
- }
- if (analyses_to_invalidate & kAnalysisBuiltinVarId) {
- builtin_var_id_map_.clear();
- }
- if (analyses_to_invalidate & kAnalysisCFG) {
- cfg_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisDominatorAnalysis) {
- dominator_trees_.clear();
- post_dominator_trees_.clear();
- }
- if (analyses_to_invalidate & kAnalysisNameMap) {
- id_to_name_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisValueNumberTable) {
- vn_table_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisStructuredCFG) {
- struct_cfg_analysis_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisIdToFuncMapping) {
- id_to_func_.clear();
- }
- if (analyses_to_invalidate & kAnalysisConstants) {
- constant_mgr_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisLiveness) {
- liveness_mgr_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisTypes) {
- type_mgr_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisDebugInfo) {
- debug_info_mgr_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisIdToGraphMapping) {
- id_to_graph_.clear();
- }
- valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
- }
- Instruction* IRContext::KillInst(Instruction* inst) {
- if (!inst) {
- return nullptr;
- }
- KillNamesAndDecorates(inst);
- KillOperandFromDebugInstructions(inst);
- if (AreAnalysesValid(kAnalysisDefUse)) {
- analysis::DefUseManager* def_use_mgr = get_def_use_mgr();
- def_use_mgr->ClearInst(inst);
- for (auto& l_inst : inst->dbg_line_insts()) def_use_mgr->ClearInst(&l_inst);
- }
- if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
- instr_to_block_.erase(inst);
- }
- if (AreAnalysesValid(kAnalysisDecorations)) {
- if (inst->IsDecoration()) {
- decoration_mgr_->RemoveDecoration(inst);
- }
- }
- if (AreAnalysesValid(kAnalysisDebugInfo)) {
- get_debug_info_mgr()->ClearDebugScopeAndInlinedAtUses(inst);
- get_debug_info_mgr()->ClearDebugInfo(inst);
- }
- if (type_mgr_ && IsTypeInst(inst->opcode())) {
- type_mgr_->RemoveId(inst->result_id());
- }
- if (constant_mgr_ && IsConstantInst(inst->opcode())) {
- constant_mgr_->RemoveId(inst->result_id());
- }
- if (inst->opcode() == spv::Op::OpCapability ||
- inst->opcode() == spv::Op::OpConditionalCapabilityINTEL ||
- inst->opcode() == spv::Op::OpExtension ||
- inst->opcode() == spv::Op::OpConditionalExtensionINTEL) {
- // We reset the feature manager, instead of updating it, because it is just
- // as much work. We would have to remove all capabilities implied by this
- // capability that are not also implied by the remaining OpCapability
- // instructions. We could update extensions, but we will see if it is
- // needed.
- ResetFeatureManager();
- }
- RemoveFromIdToName(inst);
- Instruction* next_instruction = nullptr;
- if (inst->IsInAList()) {
- next_instruction = inst->NextNode();
- inst->RemoveFromList();
- delete inst;
- } else {
- // Needed for instructions that are not part of a list like OpLabels,
- // OpFunction, OpFunctionEnd, etc..
- inst->ToNop();
- }
- return next_instruction;
- }
- bool IRContext::KillInstructionIf(Module::inst_iterator begin,
- Module::inst_iterator end,
- std::function<bool(Instruction*)> condition) {
- bool removed = false;
- for (auto it = begin; it != end;) {
- if (!condition(&*it)) {
- ++it;
- continue;
- }
- removed = true;
- // `it` is an iterator on an intrusive list. Next is invalidated on the
- // current node when an instruction is killed. The iterator must be moved
- // forward before deleting the node.
- auto instruction = &*it;
- ++it;
- KillInst(instruction);
- }
- return removed;
- }
- void IRContext::CollectNonSemanticTree(
- Instruction* inst, std::unordered_set<Instruction*>* to_kill) {
- if (!inst->HasResultId()) return;
- // Debug[No]Line result id is not used, so we are done
- if (inst->IsDebugLineInst()) return;
- std::vector<Instruction*> work_list;
- std::unordered_set<Instruction*> seen;
- work_list.push_back(inst);
- while (!work_list.empty()) {
- auto* i = work_list.back();
- work_list.pop_back();
- get_def_use_mgr()->ForEachUser(
- i, [&work_list, to_kill, &seen](Instruction* user) {
- if (user->IsNonSemanticInstruction() && seen.insert(user).second) {
- work_list.push_back(user);
- to_kill->insert(user);
- }
- });
- }
- }
- bool IRContext::KillDef(uint32_t id) {
- Instruction* def = get_def_use_mgr()->GetDef(id);
- if (def != nullptr) {
- KillInst(def);
- return true;
- }
- return false;
- }
- bool IRContext::RemoveCapability(spv::Capability capability) {
- const bool removed = KillInstructionIf(
- module()->capability_begin(), module()->capability_end(),
- [capability](Instruction* inst) {
- return static_cast<spv::Capability>(inst->GetSingleWordOperand(0)) ==
- capability;
- });
- if (removed && feature_mgr_ != nullptr) {
- feature_mgr_->RemoveCapability(capability);
- }
- return removed;
- }
- bool IRContext::RemoveExtension(Extension extension) {
- const std::string_view extensionName = ExtensionToString(extension);
- const bool removed = KillInstructionIf(
- module()->extension_begin(), module()->extension_end(),
- [&extensionName](Instruction* inst) {
- return inst->GetOperand(0).AsString() == extensionName;
- });
- if (removed && feature_mgr_ != nullptr) {
- feature_mgr_->RemoveExtension(extension);
- }
- return removed;
- }
- bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
- return ReplaceAllUsesWithPredicate(before, after,
- [](Instruction*) { return true; });
- }
- bool IRContext::ReplaceAllUsesWithPredicate(
- uint32_t before, uint32_t after,
- const std::function<bool(Instruction*)>& predicate) {
- if (before == after) return false;
- if (AreAnalysesValid(kAnalysisDebugInfo)) {
- get_debug_info_mgr()->ReplaceAllUsesInDebugScopeWithPredicate(before, after,
- predicate);
- }
- // Ensure that |after| has been registered as def.
- assert(get_def_use_mgr()->GetDef(after) &&
- "'after' is not a registered def.");
- std::vector<std::pair<Instruction*, uint32_t>> uses_to_update;
- get_def_use_mgr()->ForEachUse(
- before, [&predicate, &uses_to_update](Instruction* user, uint32_t index) {
- if (predicate(user)) {
- uses_to_update.emplace_back(user, index);
- }
- });
- Instruction* prev = nullptr;
- for (auto p : uses_to_update) {
- Instruction* user = p.first;
- uint32_t index = p.second;
- if (prev == nullptr || prev != user) {
- ForgetUses(user);
- prev = user;
- }
- const uint32_t type_result_id_count =
- (user->result_id() != 0) + (user->type_id() != 0);
- if (index < type_result_id_count) {
- // Update the type_id. Note that result id is immutable so it should
- // never be updated.
- if (user->type_id() != 0 && index == 0) {
- user->SetResultType(after);
- } else if (user->type_id() == 0) {
- SPIRV_ASSERT(consumer_, false,
- "Result type id considered as use while the instruction "
- "doesn't have a result type id.");
- (void)consumer_; // Makes the compiler happy for release build.
- } else {
- SPIRV_ASSERT(consumer_, false,
- "Trying setting the immutable result id.");
- }
- } else {
- // Update an in-operand.
- uint32_t in_operand_pos = index - type_result_id_count;
- // Make the modification in the instruction.
- user->SetInOperand(in_operand_pos, {after});
- }
- AnalyzeUses(user);
- }
- return true;
- }
- bool IRContext::IsConsistent() {
- #ifndef SPIRV_CHECK_CONTEXT
- return true;
- #else
- if (AreAnalysesValid(kAnalysisDefUse)) {
- analysis::DefUseManager new_def_use(module());
- if (!CompareAndPrintDifferences(*get_def_use_mgr(), new_def_use)) {
- return false;
- }
- }
- return true;
- if (AreAnalysesValid(kAnalysisIdToFuncMapping)) {
- for (auto& fn : *module_) {
- if (id_to_func_[fn.result_id()] != &fn) {
- return false;
- }
- }
- }
- if (AreAnalysesValid(kAnalysisIdToGraphMapping)) {
- for (auto& g : module_->graphs()) {
- if (id_to_graph_[g->DefInst().result_id()] != g.get()) {
- return false;
- }
- }
- }
- if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
- for (auto& func : *module()) {
- for (auto& block : func) {
- if (!block.WhileEachInst([this, &block](Instruction* inst) {
- if (get_instr_block(inst) != &block) {
- return false;
- }
- return true;
- })) {
- return false;
- }
- }
- }
- }
- if (!CheckCFG()) {
- return false;
- }
- if (AreAnalysesValid(kAnalysisDecorations)) {
- analysis::DecorationManager* dec_mgr = get_decoration_mgr();
- analysis::DecorationManager current(module());
- if (*dec_mgr != current) {
- return false;
- }
- }
- if (feature_mgr_ != nullptr) {
- FeatureManager current(grammar_);
- current.Analyze(module());
- if (current != *feature_mgr_) {
- return false;
- }
- }
- return true;
- #endif
- }
- void IRContext::ForgetUses(Instruction* inst) {
- if (AreAnalysesValid(kAnalysisDefUse)) {
- get_def_use_mgr()->EraseUseRecordsOfOperandIds(inst);
- }
- if (AreAnalysesValid(kAnalysisDecorations)) {
- if (inst->IsDecoration()) {
- get_decoration_mgr()->RemoveDecoration(inst);
- }
- }
- if (AreAnalysesValid(kAnalysisDebugInfo)) {
- get_debug_info_mgr()->ClearDebugInfo(inst);
- }
- RemoveFromIdToName(inst);
- }
- void IRContext::AnalyzeUses(Instruction* inst) {
- if (AreAnalysesValid(kAnalysisDefUse)) {
- get_def_use_mgr()->AnalyzeInstUse(inst);
- }
- if (AreAnalysesValid(kAnalysisDecorations)) {
- if (inst->IsDecoration()) {
- get_decoration_mgr()->AddDecoration(inst);
- }
- }
- if (AreAnalysesValid(kAnalysisDebugInfo)) {
- get_debug_info_mgr()->AnalyzeDebugInst(inst);
- }
- if (id_to_name_ && (inst->opcode() == spv::Op::OpName ||
- inst->opcode() == spv::Op::OpMemberName)) {
- id_to_name_->insert({inst->GetSingleWordInOperand(0), inst});
- }
- }
- void IRContext::KillNamesAndDecorates(uint32_t id) {
- analysis::DecorationManager* dec_mgr = get_decoration_mgr();
- dec_mgr->RemoveDecorationsFrom(id);
- std::vector<Instruction*> name_to_kill;
- for (auto name : GetNames(id)) {
- name_to_kill.push_back(name.second);
- }
- for (Instruction* name_inst : name_to_kill) {
- KillInst(name_inst);
- }
- }
- void IRContext::KillNamesAndDecorates(Instruction* inst) {
- const uint32_t rId = inst->result_id();
- if (rId == 0) return;
- KillNamesAndDecorates(rId);
- }
- void IRContext::KillOperandFromDebugInstructions(Instruction* inst) {
- const auto opcode = inst->opcode();
- const uint32_t id = inst->result_id();
- // Kill id of OpFunction from DebugFunction.
- if (opcode == spv::Op::OpFunction) {
- for (auto it = module()->ext_inst_debuginfo_begin();
- it != module()->ext_inst_debuginfo_end(); ++it) {
- if (it->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugFunction)
- continue;
- auto& operand = it->GetOperand(kDebugFunctionOperandFunctionIndex);
- if (operand.words[0] == id) {
- operand.words[0] =
- get_debug_info_mgr()->GetDebugInfoNone()->result_id();
- get_def_use_mgr()->AnalyzeInstUse(&*it);
- }
- }
- }
- // Kill id of OpVariable for global variable from DebugGlobalVariable.
- if (opcode == spv::Op::OpVariable || IsConstantInst(opcode)) {
- for (auto it = module()->ext_inst_debuginfo_begin();
- it != module()->ext_inst_debuginfo_end(); ++it) {
- if (it->GetCommonDebugOpcode() != CommonDebugInfoDebugGlobalVariable)
- continue;
- auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex);
- if (operand.words[0] == id) {
- operand.words[0] =
- get_debug_info_mgr()->GetDebugInfoNone()->result_id();
- get_def_use_mgr()->AnalyzeInstUse(&*it);
- }
- }
- }
- }
- void IRContext::AddCombinatorsForCapability(uint32_t capability) {
- spv::Capability cap = spv::Capability(capability);
- if (cap == spv::Capability::Shader) {
- combinator_ops_[0].insert(
- {(uint32_t)spv::Op::OpNop,
- (uint32_t)spv::Op::OpUndef,
- (uint32_t)spv::Op::OpConstant,
- (uint32_t)spv::Op::OpConstantTrue,
- (uint32_t)spv::Op::OpConstantFalse,
- (uint32_t)spv::Op::OpConstantComposite,
- (uint32_t)spv::Op::OpConstantSampler,
- (uint32_t)spv::Op::OpConstantNull,
- (uint32_t)spv::Op::OpTypeVoid,
- (uint32_t)spv::Op::OpTypeBool,
- (uint32_t)spv::Op::OpTypeInt,
- (uint32_t)spv::Op::OpTypeFloat,
- (uint32_t)spv::Op::OpTypeVector,
- (uint32_t)spv::Op::OpTypeMatrix,
- (uint32_t)spv::Op::OpTypeImage,
- (uint32_t)spv::Op::OpTypeSampler,
- (uint32_t)spv::Op::OpTypeSampledImage,
- (uint32_t)spv::Op::OpTypeAccelerationStructureNV,
- (uint32_t)spv::Op::OpTypeAccelerationStructureKHR,
- (uint32_t)spv::Op::OpTypeRayQueryKHR,
- (uint32_t)spv::Op::OpTypeHitObjectNV,
- (uint32_t)spv::Op::OpTypeHitObjectEXT,
- (uint32_t)spv::Op::OpTypeArray,
- (uint32_t)spv::Op::OpTypeRuntimeArray,
- (uint32_t)spv::Op::OpTypeNodePayloadArrayAMDX,
- (uint32_t)spv::Op::OpTypeStruct,
- (uint32_t)spv::Op::OpTypeOpaque,
- (uint32_t)spv::Op::OpTypePointer,
- (uint32_t)spv::Op::OpTypeFunction,
- (uint32_t)spv::Op::OpTypeEvent,
- (uint32_t)spv::Op::OpTypeDeviceEvent,
- (uint32_t)spv::Op::OpTypeReserveId,
- (uint32_t)spv::Op::OpTypeQueue,
- (uint32_t)spv::Op::OpTypePipe,
- (uint32_t)spv::Op::OpTypeForwardPointer,
- (uint32_t)spv::Op::OpVariable,
- (uint32_t)spv::Op::OpImageTexelPointer,
- (uint32_t)spv::Op::OpLoad,
- (uint32_t)spv::Op::OpAccessChain,
- (uint32_t)spv::Op::OpInBoundsAccessChain,
- (uint32_t)spv::Op::OpArrayLength,
- (uint32_t)spv::Op::OpVectorExtractDynamic,
- (uint32_t)spv::Op::OpVectorInsertDynamic,
- (uint32_t)spv::Op::OpVectorShuffle,
- (uint32_t)spv::Op::OpCompositeConstruct,
- (uint32_t)spv::Op::OpCompositeExtract,
- (uint32_t)spv::Op::OpCompositeInsert,
- (uint32_t)spv::Op::OpCopyLogical,
- (uint32_t)spv::Op::OpCopyObject,
- (uint32_t)spv::Op::OpTranspose,
- (uint32_t)spv::Op::OpSampledImage,
- (uint32_t)spv::Op::OpImageSampleImplicitLod,
- (uint32_t)spv::Op::OpImageSampleExplicitLod,
- (uint32_t)spv::Op::OpImageSampleDrefImplicitLod,
- (uint32_t)spv::Op::OpImageSampleDrefExplicitLod,
- (uint32_t)spv::Op::OpImageSampleProjImplicitLod,
- (uint32_t)spv::Op::OpImageSampleProjExplicitLod,
- (uint32_t)spv::Op::OpImageSampleProjDrefImplicitLod,
- (uint32_t)spv::Op::OpImageSampleProjDrefExplicitLod,
- (uint32_t)spv::Op::OpImageFetch,
- (uint32_t)spv::Op::OpImageGather,
- (uint32_t)spv::Op::OpImageDrefGather,
- (uint32_t)spv::Op::OpImageRead,
- (uint32_t)spv::Op::OpImage,
- (uint32_t)spv::Op::OpImageQueryFormat,
- (uint32_t)spv::Op::OpImageQueryOrder,
- (uint32_t)spv::Op::OpImageQuerySizeLod,
- (uint32_t)spv::Op::OpImageQuerySize,
- (uint32_t)spv::Op::OpImageQueryLevels,
- (uint32_t)spv::Op::OpImageQuerySamples,
- (uint32_t)spv::Op::OpConvertFToU,
- (uint32_t)spv::Op::OpConvertFToS,
- (uint32_t)spv::Op::OpConvertSToF,
- (uint32_t)spv::Op::OpConvertUToF,
- (uint32_t)spv::Op::OpUConvert,
- (uint32_t)spv::Op::OpSConvert,
- (uint32_t)spv::Op::OpFConvert,
- (uint32_t)spv::Op::OpQuantizeToF16,
- (uint32_t)spv::Op::OpBitcast,
- (uint32_t)spv::Op::OpSNegate,
- (uint32_t)spv::Op::OpFNegate,
- (uint32_t)spv::Op::OpIAdd,
- (uint32_t)spv::Op::OpFAdd,
- (uint32_t)spv::Op::OpISub,
- (uint32_t)spv::Op::OpFSub,
- (uint32_t)spv::Op::OpIMul,
- (uint32_t)spv::Op::OpFMul,
- (uint32_t)spv::Op::OpUDiv,
- (uint32_t)spv::Op::OpSDiv,
- (uint32_t)spv::Op::OpFDiv,
- (uint32_t)spv::Op::OpUMod,
- (uint32_t)spv::Op::OpSRem,
- (uint32_t)spv::Op::OpSMod,
- (uint32_t)spv::Op::OpFRem,
- (uint32_t)spv::Op::OpFMod,
- (uint32_t)spv::Op::OpVectorTimesScalar,
- (uint32_t)spv::Op::OpMatrixTimesScalar,
- (uint32_t)spv::Op::OpVectorTimesMatrix,
- (uint32_t)spv::Op::OpMatrixTimesVector,
- (uint32_t)spv::Op::OpMatrixTimesMatrix,
- (uint32_t)spv::Op::OpOuterProduct,
- (uint32_t)spv::Op::OpDot,
- (uint32_t)spv::Op::OpIAddCarry,
- (uint32_t)spv::Op::OpISubBorrow,
- (uint32_t)spv::Op::OpUMulExtended,
- (uint32_t)spv::Op::OpSMulExtended,
- (uint32_t)spv::Op::OpAny,
- (uint32_t)spv::Op::OpAll,
- (uint32_t)spv::Op::OpIsNan,
- (uint32_t)spv::Op::OpIsInf,
- (uint32_t)spv::Op::OpLogicalEqual,
- (uint32_t)spv::Op::OpLogicalNotEqual,
- (uint32_t)spv::Op::OpLogicalOr,
- (uint32_t)spv::Op::OpLogicalAnd,
- (uint32_t)spv::Op::OpLogicalNot,
- (uint32_t)spv::Op::OpSelect,
- (uint32_t)spv::Op::OpIEqual,
- (uint32_t)spv::Op::OpINotEqual,
- (uint32_t)spv::Op::OpUGreaterThan,
- (uint32_t)spv::Op::OpSGreaterThan,
- (uint32_t)spv::Op::OpUGreaterThanEqual,
- (uint32_t)spv::Op::OpSGreaterThanEqual,
- (uint32_t)spv::Op::OpULessThan,
- (uint32_t)spv::Op::OpSLessThan,
- (uint32_t)spv::Op::OpULessThanEqual,
- (uint32_t)spv::Op::OpSLessThanEqual,
- (uint32_t)spv::Op::OpFOrdEqual,
- (uint32_t)spv::Op::OpFUnordEqual,
- (uint32_t)spv::Op::OpFOrdNotEqual,
- (uint32_t)spv::Op::OpFUnordNotEqual,
- (uint32_t)spv::Op::OpFOrdLessThan,
- (uint32_t)spv::Op::OpFUnordLessThan,
- (uint32_t)spv::Op::OpFOrdGreaterThan,
- (uint32_t)spv::Op::OpFUnordGreaterThan,
- (uint32_t)spv::Op::OpFOrdLessThanEqual,
- (uint32_t)spv::Op::OpFUnordLessThanEqual,
- (uint32_t)spv::Op::OpFOrdGreaterThanEqual,
- (uint32_t)spv::Op::OpFUnordGreaterThanEqual,
- (uint32_t)spv::Op::OpShiftRightLogical,
- (uint32_t)spv::Op::OpShiftRightArithmetic,
- (uint32_t)spv::Op::OpShiftLeftLogical,
- (uint32_t)spv::Op::OpBitwiseOr,
- (uint32_t)spv::Op::OpBitwiseXor,
- (uint32_t)spv::Op::OpBitwiseAnd,
- (uint32_t)spv::Op::OpNot,
- (uint32_t)spv::Op::OpBitFieldInsert,
- (uint32_t)spv::Op::OpBitFieldSExtract,
- (uint32_t)spv::Op::OpBitFieldUExtract,
- (uint32_t)spv::Op::OpBitReverse,
- (uint32_t)spv::Op::OpBitCount,
- (uint32_t)spv::Op::OpPhi,
- (uint32_t)spv::Op::OpImageSparseSampleImplicitLod,
- (uint32_t)spv::Op::OpImageSparseSampleExplicitLod,
- (uint32_t)spv::Op::OpImageSparseSampleDrefImplicitLod,
- (uint32_t)spv::Op::OpImageSparseSampleDrefExplicitLod,
- (uint32_t)spv::Op::OpImageSparseSampleProjImplicitLod,
- (uint32_t)spv::Op::OpImageSparseSampleProjExplicitLod,
- (uint32_t)spv::Op::OpImageSparseSampleProjDrefImplicitLod,
- (uint32_t)spv::Op::OpImageSparseSampleProjDrefExplicitLod,
- (uint32_t)spv::Op::OpImageSparseFetch,
- (uint32_t)spv::Op::OpImageSparseGather,
- (uint32_t)spv::Op::OpImageSparseDrefGather,
- (uint32_t)spv::Op::OpImageSparseTexelsResident,
- (uint32_t)spv::Op::OpImageSparseRead,
- (uint32_t)spv::Op::OpSizeOf});
- }
- }
- void IRContext::AddCombinatorsForExtension(Instruction* extension) {
- assert(extension->opcode() == spv::Op::OpExtInstImport &&
- "Expecting an import of an extension's instruction set.");
- const std::string extension_name = extension->GetInOperand(0).AsString();
- if (extension_name == "GLSL.std.450") {
- combinator_ops_[extension->result_id()] = {
- (uint32_t)GLSLstd450Round,
- (uint32_t)GLSLstd450RoundEven,
- (uint32_t)GLSLstd450Trunc,
- (uint32_t)GLSLstd450FAbs,
- (uint32_t)GLSLstd450SAbs,
- (uint32_t)GLSLstd450FSign,
- (uint32_t)GLSLstd450SSign,
- (uint32_t)GLSLstd450Floor,
- (uint32_t)GLSLstd450Ceil,
- (uint32_t)GLSLstd450Fract,
- (uint32_t)GLSLstd450Radians,
- (uint32_t)GLSLstd450Degrees,
- (uint32_t)GLSLstd450Sin,
- (uint32_t)GLSLstd450Cos,
- (uint32_t)GLSLstd450Tan,
- (uint32_t)GLSLstd450Asin,
- (uint32_t)GLSLstd450Acos,
- (uint32_t)GLSLstd450Atan,
- (uint32_t)GLSLstd450Sinh,
- (uint32_t)GLSLstd450Cosh,
- (uint32_t)GLSLstd450Tanh,
- (uint32_t)GLSLstd450Asinh,
- (uint32_t)GLSLstd450Acosh,
- (uint32_t)GLSLstd450Atanh,
- (uint32_t)GLSLstd450Atan2,
- (uint32_t)GLSLstd450Pow,
- (uint32_t)GLSLstd450Exp,
- (uint32_t)GLSLstd450Log,
- (uint32_t)GLSLstd450Exp2,
- (uint32_t)GLSLstd450Log2,
- (uint32_t)GLSLstd450Sqrt,
- (uint32_t)GLSLstd450InverseSqrt,
- (uint32_t)GLSLstd450Determinant,
- (uint32_t)GLSLstd450MatrixInverse,
- (uint32_t)GLSLstd450ModfStruct,
- (uint32_t)GLSLstd450FMin,
- (uint32_t)GLSLstd450UMin,
- (uint32_t)GLSLstd450SMin,
- (uint32_t)GLSLstd450FMax,
- (uint32_t)GLSLstd450UMax,
- (uint32_t)GLSLstd450SMax,
- (uint32_t)GLSLstd450FClamp,
- (uint32_t)GLSLstd450UClamp,
- (uint32_t)GLSLstd450SClamp,
- (uint32_t)GLSLstd450FMix,
- (uint32_t)GLSLstd450IMix,
- (uint32_t)GLSLstd450Step,
- (uint32_t)GLSLstd450SmoothStep,
- (uint32_t)GLSLstd450Fma,
- (uint32_t)GLSLstd450FrexpStruct,
- (uint32_t)GLSLstd450Ldexp,
- (uint32_t)GLSLstd450PackSnorm4x8,
- (uint32_t)GLSLstd450PackUnorm4x8,
- (uint32_t)GLSLstd450PackSnorm2x16,
- (uint32_t)GLSLstd450PackUnorm2x16,
- (uint32_t)GLSLstd450PackHalf2x16,
- (uint32_t)GLSLstd450PackDouble2x32,
- (uint32_t)GLSLstd450UnpackSnorm2x16,
- (uint32_t)GLSLstd450UnpackUnorm2x16,
- (uint32_t)GLSLstd450UnpackHalf2x16,
- (uint32_t)GLSLstd450UnpackSnorm4x8,
- (uint32_t)GLSLstd450UnpackUnorm4x8,
- (uint32_t)GLSLstd450UnpackDouble2x32,
- (uint32_t)GLSLstd450Length,
- (uint32_t)GLSLstd450Distance,
- (uint32_t)GLSLstd450Cross,
- (uint32_t)GLSLstd450Normalize,
- (uint32_t)GLSLstd450FaceForward,
- (uint32_t)GLSLstd450Reflect,
- (uint32_t)GLSLstd450Refract,
- (uint32_t)GLSLstd450FindILsb,
- (uint32_t)GLSLstd450FindSMsb,
- (uint32_t)GLSLstd450FindUMsb,
- (uint32_t)GLSLstd450InterpolateAtCentroid,
- (uint32_t)GLSLstd450InterpolateAtSample,
- (uint32_t)GLSLstd450InterpolateAtOffset,
- (uint32_t)GLSLstd450NMin,
- (uint32_t)GLSLstd450NMax,
- (uint32_t)GLSLstd450NClamp};
- } else {
- // Map the result id to the empty set.
- combinator_ops_[extension->result_id()];
- }
- }
- void IRContext::InitializeCombinators() {
- for (auto capability : get_feature_mgr()->GetCapabilities()) {
- AddCombinatorsForCapability(uint32_t(capability));
- }
- for (auto& extension : module()->ext_inst_imports()) {
- AddCombinatorsForExtension(&extension);
- }
- valid_analyses_ |= kAnalysisCombinators;
- }
- void IRContext::RemoveFromIdToName(const Instruction* inst) {
- if (id_to_name_ && (inst->opcode() == spv::Op::OpName ||
- inst->opcode() == spv::Op::OpMemberName)) {
- auto range = id_to_name_->equal_range(inst->GetSingleWordInOperand(0));
- for (auto it = range.first; it != range.second; ++it) {
- if (it->second == inst) {
- id_to_name_->erase(it);
- break;
- }
- }
- }
- }
- LoopDescriptor* IRContext::GetLoopDescriptor(const Function* f) {
- if (!AreAnalysesValid(kAnalysisLoopAnalysis)) {
- ResetLoopAnalysis();
- }
- std::unordered_map<const Function*, LoopDescriptor>::iterator it =
- loop_descriptors_.find(f);
- if (it == loop_descriptors_.end()) {
- return &loop_descriptors_
- .emplace(std::make_pair(f, LoopDescriptor(this, f)))
- .first->second;
- }
- return &it->second;
- }
- uint32_t IRContext::FindBuiltinInputVar(uint32_t builtin) {
- for (auto& a : module_->annotations()) {
- if (spv::Op(a.opcode()) != spv::Op::OpDecorate) continue;
- if (spv::Decoration(a.GetSingleWordInOperand(
- kSpvDecorateDecorationInIdx)) != spv::Decoration::BuiltIn)
- continue;
- if (a.GetSingleWordInOperand(kSpvDecorateBuiltinInIdx) != builtin) continue;
- uint32_t target_id = a.GetSingleWordInOperand(kSpvDecorateTargetIdInIdx);
- Instruction* b_var = get_def_use_mgr()->GetDef(target_id);
- if (b_var->opcode() != spv::Op::OpVariable) continue;
- if (spv::StorageClass(b_var->GetSingleWordInOperand(0)) !=
- spv::StorageClass::Input)
- continue;
- return target_id;
- }
- return 0;
- }
- void IRContext::AddVarToEntryPoints(uint32_t var_id) {
- uint32_t ocnt = 0;
- for (auto& e : module()->entry_points()) {
- bool found = false;
- e.ForEachInOperand([&ocnt, &found, &var_id](const uint32_t* idp) {
- if (ocnt >= kEntryPointInterfaceInIdx) {
- if (*idp == var_id) found = true;
- }
- ++ocnt;
- });
- if (!found) {
- e.AddOperand({SPV_OPERAND_TYPE_ID, {var_id}});
- get_def_use_mgr()->AnalyzeInstDefUse(&e);
- }
- }
- }
- uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
- if (!AreAnalysesValid(kAnalysisBuiltinVarId)) ResetBuiltinAnalysis();
- // If cached, return it.
- std::unordered_map<uint32_t, uint32_t>::iterator it =
- builtin_var_id_map_.find(builtin);
- if (it != builtin_var_id_map_.end()) return it->second;
- // Look for one in shader
- uint32_t var_id = FindBuiltinInputVar(builtin);
- if (var_id == 0) {
- // If not found, create it
- // TODO(greg-lunarg): Add support for all builtins
- analysis::TypeManager* type_mgr = get_type_mgr();
- analysis::Type* reg_type;
- switch (spv::BuiltIn(builtin)) {
- case spv::BuiltIn::FragCoord: {
- analysis::Float float_ty(32);
- analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
- analysis::Vector v4float_ty(reg_float_ty, 4);
- reg_type = type_mgr->GetRegisteredType(&v4float_ty);
- break;
- }
- case spv::BuiltIn::VertexIndex:
- case spv::BuiltIn::InstanceIndex:
- case spv::BuiltIn::PrimitiveId:
- case spv::BuiltIn::InvocationId:
- case spv::BuiltIn::SubgroupLocalInvocationId: {
- analysis::Integer uint_ty(32, false);
- reg_type = type_mgr->GetRegisteredType(&uint_ty);
- break;
- }
- case spv::BuiltIn::GlobalInvocationId:
- case spv::BuiltIn::LaunchIdNV: {
- analysis::Integer uint_ty(32, false);
- analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
- analysis::Vector v3uint_ty(reg_uint_ty, 3);
- reg_type = type_mgr->GetRegisteredType(&v3uint_ty);
- break;
- }
- case spv::BuiltIn::TessCoord: {
- analysis::Float float_ty(32);
- analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
- analysis::Vector v3float_ty(reg_float_ty, 3);
- reg_type = type_mgr->GetRegisteredType(&v3float_ty);
- break;
- }
- case spv::BuiltIn::SubgroupLtMask: {
- analysis::Integer uint_ty(32, false);
- analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
- analysis::Vector v4uint_ty(reg_uint_ty, 4);
- reg_type = type_mgr->GetRegisteredType(&v4uint_ty);
- break;
- }
- default: {
- assert(false && "unhandled builtin");
- return 0;
- }
- }
- if (reg_type == nullptr) return 0; // Error
- uint32_t type_id = type_mgr->GetTypeInstruction(reg_type);
- uint32_t varTyPtrId =
- type_mgr->FindPointerToType(type_id, spv::StorageClass::Input);
- var_id = TakeNextId();
- if (var_id == 0) return 0; // Error
- std::unique_ptr<Instruction> newVarOp(
- new Instruction(this, spv::Op::OpVariable, varTyPtrId, var_id,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
- {uint32_t(spv::StorageClass::Input)}}}));
- get_def_use_mgr()->AnalyzeInstDefUse(&*newVarOp);
- module()->AddGlobalValue(std::move(newVarOp));
- get_decoration_mgr()->AddDecorationVal(
- var_id, uint32_t(spv::Decoration::BuiltIn), builtin);
- AddVarToEntryPoints(var_id);
- }
- builtin_var_id_map_[builtin] = var_id;
- return var_id;
- }
- void IRContext::AddCalls(const Function* func, std::queue<uint32_t>* todo) {
- for (auto bi = func->begin(); bi != func->end(); ++bi)
- for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
- if (ii->opcode() == spv::Op::OpFunctionCall)
- todo->push(ii->GetSingleWordInOperand(0));
- if (ii->opcode() == spv::Op::OpCooperativeMatrixPerElementOpNV)
- todo->push(ii->GetSingleWordInOperand(1));
- if (ii->opcode() == spv::Op::OpCooperativeMatrixReduceNV)
- todo->push(ii->GetSingleWordInOperand(2));
- if (ii->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) {
- const auto memory_operands_index = 3;
- auto mask = ii->GetSingleWordInOperand(memory_operands_index);
- uint32_t count = 1;
- if (mask & uint32_t(spv::MemoryAccessMask::Aligned)) ++count;
- if (mask & uint32_t(spv::MemoryAccessMask::MakePointerAvailableKHR))
- ++count;
- if (mask & uint32_t(spv::MemoryAccessMask::MakePointerVisibleKHR))
- ++count;
- const auto tensor_operands_index = memory_operands_index + count;
- mask = ii->GetSingleWordInOperand(tensor_operands_index);
- count = 1;
- if (mask & uint32_t(spv::TensorAddressingOperandsMask::TensorView))
- ++count;
- if (mask & uint32_t(spv::TensorAddressingOperandsMask::DecodeFunc)) {
- todo->push(ii->GetSingleWordInOperand(tensor_operands_index + count));
- }
- }
- }
- }
- bool IRContext::ProcessEntryPointCallTree(ProcessFunction& pfn) {
- // Collect all of the entry points as the roots.
- std::queue<uint32_t> roots;
- for (auto& e : module()->entry_points()) {
- roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
- }
- return ProcessCallTreeFromRoots(pfn, &roots);
- }
- bool IRContext::ProcessReachableCallTree(ProcessFunction& pfn) {
- std::queue<uint32_t> roots;
- // Add all entry points since they can be reached from outside the module.
- for (auto& e : module()->entry_points())
- roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
- // Add all exported functions since they can be reached from outside the
- // module.
- for (auto& a : annotations()) {
- // TODO: Handle group decorations as well. Currently not generate by any
- // front-end, but could be coming.
- if (a.opcode() == spv::Op::OpDecorate) {
- if (spv::Decoration(a.GetSingleWordOperand(1)) ==
- spv::Decoration::LinkageAttributes) {
- uint32_t lastOperand = a.NumOperands() - 1;
- if (spv::LinkageType(a.GetSingleWordOperand(lastOperand)) ==
- spv::LinkageType::Export) {
- uint32_t id = a.GetSingleWordOperand(0);
- if (GetFunction(id)) {
- roots.push(id);
- }
- }
- }
- }
- }
- return ProcessCallTreeFromRoots(pfn, &roots);
- }
- bool IRContext::ProcessCallTreeFromRoots(ProcessFunction& pfn,
- std::queue<uint32_t>* roots) {
- // Process call tree
- bool modified = false;
- std::unordered_set<uint32_t> done;
- while (!roots->empty()) {
- const uint32_t fi = roots->front();
- roots->pop();
- if (done.insert(fi).second) {
- Function* fn = GetFunction(fi);
- assert(fn && "Trying to process a function that does not exist.");
- modified = pfn(fn) || modified;
- AddCalls(fn, roots);
- }
- }
- return modified;
- }
- void IRContext::CollectCallTreeFromRoots(unsigned entryId,
- std::unordered_set<uint32_t>* funcs) {
- std::queue<uint32_t> roots;
- roots.push(entryId);
- while (!roots.empty()) {
- const uint32_t fi = roots.front();
- roots.pop();
- funcs->insert(fi);
- Function* fn = GetFunction(fi);
- AddCalls(fn, &roots);
- }
- }
- void IRContext::EmitErrorMessage(std::string message, Instruction* inst) {
- if (!consumer()) {
- return;
- }
- Instruction* line_inst = inst;
- while (line_inst != nullptr) { // Stop at the beginning of the basic block.
- if (!line_inst->dbg_line_insts().empty()) {
- line_inst = &line_inst->dbg_line_insts().back();
- if (line_inst->IsNoLine()) {
- line_inst = nullptr;
- }
- break;
- }
- line_inst = line_inst->PreviousNode();
- }
- uint32_t line_number = 0;
- uint32_t col_number = 0;
- std::string source;
- if (line_inst != nullptr) {
- Instruction* file_name =
- get_def_use_mgr()->GetDef(line_inst->GetSingleWordInOperand(0));
- source = file_name->GetInOperand(0).AsString();
- // Get the line number and column number.
- line_number = line_inst->GetSingleWordInOperand(1);
- col_number = line_inst->GetSingleWordInOperand(2);
- }
- message +=
- "\n " + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
- consumer()(SPV_MSG_ERROR, source.c_str(), {line_number, col_number, 0},
- message.c_str());
- }
- // Gets the dominator analysis for function |f|.
- DominatorAnalysis* IRContext::GetDominatorAnalysis(const Function* f) {
- if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
- ResetDominatorAnalysis();
- }
- if (dominator_trees_.find(f) == dominator_trees_.end()) {
- dominator_trees_[f].InitializeTree(*cfg(), f);
- }
- return &dominator_trees_[f];
- }
- // Gets the postdominator analysis for function |f|.
- PostDominatorAnalysis* IRContext::GetPostDominatorAnalysis(const Function* f) {
- if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
- ResetDominatorAnalysis();
- }
- if (post_dominator_trees_.find(f) == post_dominator_trees_.end()) {
- post_dominator_trees_[f].InitializeTree(*cfg(), f);
- }
- return &post_dominator_trees_[f];
- }
- bool IRContext::CheckCFG() {
- std::unordered_map<uint32_t, std::vector<uint32_t>> real_preds;
- if (!AreAnalysesValid(kAnalysisCFG)) {
- return true;
- }
- for (Function& function : *module()) {
- for (const auto& bb : function) {
- bb.ForEachSuccessorLabel([&bb, &real_preds](const uint32_t lab_id) {
- real_preds[lab_id].push_back(bb.id());
- });
- }
- for (auto& bb : function) {
- std::vector<uint32_t> preds = cfg()->preds(bb.id());
- std::vector<uint32_t> real = real_preds[bb.id()];
- std::sort(preds.begin(), preds.end());
- std::sort(real.begin(), real.end());
- bool same = true;
- if (preds.size() != real.size()) {
- same = false;
- }
- for (size_t i = 0; i < real.size() && same; i++) {
- if (preds[i] != real[i]) {
- same = false;
- }
- }
- if (!same) {
- std::cerr << "Predecessors for " << bb.id() << " are different:\n";
- std::cerr << "Real:";
- for (uint32_t i : real) {
- std::cerr << ' ' << i;
- }
- std::cerr << std::endl;
- std::cerr << "Recorded:";
- for (uint32_t i : preds) {
- std::cerr << ' ' << i;
- }
- std::cerr << std::endl;
- }
- if (!same) return false;
- }
- }
- return true;
- }
- bool IRContext::IsReachable(const opt::BasicBlock& bb) {
- auto enclosing_function = bb.GetParent();
- return GetDominatorAnalysis(enclosing_function)
- ->Dominates(enclosing_function->entry().get(), &bb);
- }
- spv::ExecutionModel IRContext::GetStage() {
- const auto& entry_points = module()->entry_points();
- if (entry_points.empty()) {
- return spv::ExecutionModel::Max;
- }
- uint32_t stage = entry_points.begin()->GetSingleWordInOperand(
- kEntryPointExecutionModelInIdx);
- auto it = std::find_if(
- entry_points.begin(), entry_points.end(), [stage](const Instruction& x) {
- return x.GetSingleWordInOperand(kEntryPointExecutionModelInIdx) !=
- stage;
- });
- if (it != entry_points.end()) {
- EmitErrorMessage("Mixed stage shader module not supported", &(*it));
- }
- return static_cast<spv::ExecutionModel>(stage);
- }
- } // namespace opt
- } // namespace spvtools
|