diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index a01a14a30..155d8c93a 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2020.3-dev", "SPIRV-Tools v2020.3-dev ad8e2138c256f6fb0b38e883fe1ae0e2a59c7620" +"v2020.3-dev", "SPIRV-Tools v2020.3-dev 7f7c8a9bc032be95861952467a66f0c77560ec04" diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp index 2cfe3268b..bc6f3b1e1 100644 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp @@ -430,6 +430,9 @@ class FactManager::DataSynonymAndIdEquationFacts { uint32_t maximum_equivalence_class_size); private: + using OperationSet = + std::unordered_set; + // Adds the synonym |dd1| = |dd2| to the set of managed facts, and recurses // into sub-components of the data descriptors, if they are composites, to // record that their components are pairwise-synonymous. @@ -448,6 +451,8 @@ class FactManager::DataSynonymAndIdEquationFacts { opt::IRContext* context, const protobufs::DataDescriptor& dd1, const protobufs::DataDescriptor& dd2) const; + OperationSet GetEquations(const protobufs::DataDescriptor* lhs) const; + // Requires that |lhs_dd| and every element of |rhs_dds| is present in the // |synonymous_| equivalence relation, but is not necessarily its own // representative. Records the fact that the equation @@ -480,9 +485,7 @@ class FactManager::DataSynonymAndIdEquationFacts { // All data descriptors occurring in equations are required to be present in // the |synonymous_| equivalence relation, and to be their own representatives // in that relation. - std::unordered_map< - const protobufs::DataDescriptor*, - std::unordered_set> + std::unordered_map id_equations_; }; @@ -520,6 +523,16 @@ void FactManager::DataSynonymAndIdEquationFacts::AddFact( rhs_dd_ptrs, context); } +FactManager::DataSynonymAndIdEquationFacts::OperationSet +FactManager::DataSynonymAndIdEquationFacts::GetEquations( + const protobufs::DataDescriptor* lhs) const { + auto existing = id_equations_.find(lhs); + if (existing == id_equations_.end()) { + return OperationSet(); + } + return existing->second; +} + void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive( const protobufs::DataDescriptor& lhs_dd, SpvOp opcode, const std::vector& rhs_dds, @@ -538,9 +551,7 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive( if (id_equations_.count(lhs_dd_representative) == 0) { // We have not seen an equation with this LHS before, so associate the LHS // with an initially empty set. - id_equations_.insert( - {lhs_dd_representative, - std::unordered_set()}); + id_equations_.insert({lhs_dd_representative, OperationSet()}); } { @@ -562,44 +573,29 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive( switch (opcode) { case SpvOpIAdd: { // Equation form: "a = b + c" - { - auto existing_first_operand_equations = id_equations_.find(rhs_dds[0]); - if (existing_first_operand_equations != id_equations_.end()) { - for (auto equation : existing_first_operand_equations->second) { - if (equation.opcode == SpvOpISub) { - // Equation form: "a = (d - e) + c" - if (synonymous_.IsEquivalent(*equation.operands[1], - *rhs_dds[1])) { - // Equation form: "a = (d - c) + c" - // We can thus infer "a = d" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], - context); - } - if (synonymous_.IsEquivalent(*equation.operands[0], - *rhs_dds[1])) { - // Equation form: "a = (c - e) + c" - // We can thus infer "a = -e" - AddEquationFactRecursive(lhs_dd, SpvOpSNegate, - {equation.operands[1]}, context); - } - } + for (auto equation : GetEquations(rhs_dds[0])) { + if (equation.opcode == SpvOpISub) { + // Equation form: "a = (d - e) + c" + if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) { + // Equation form: "a = (d - c) + c" + // We can thus infer "a = d" + AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context); + } + if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) { + // Equation form: "a = (c - e) + c" + // We can thus infer "a = -e" + AddEquationFactRecursive(lhs_dd, SpvOpSNegate, + {equation.operands[1]}, context); } } } - { - auto existing_second_operand_equations = id_equations_.find(rhs_dds[1]); - if (existing_second_operand_equations != id_equations_.end()) { - for (auto equation : existing_second_operand_equations->second) { - if (equation.opcode == SpvOpISub) { - // Equation form: "a = b + (d - e)" - if (synonymous_.IsEquivalent(*equation.operands[1], - *rhs_dds[0])) { - // Equation form: "a = b + (d - b)" - // We can thus infer "a = d" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], - context); - } - } + for (auto equation : GetEquations(rhs_dds[1])) { + if (equation.opcode == SpvOpISub) { + // Equation form: "a = b + (d - e)" + if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) { + // Equation form: "a = b + (d - b)" + // We can thus infer "a = d" + AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context); } } } @@ -607,73 +603,54 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive( } case SpvOpISub: { // Equation form: "a = b - c" - { - auto existing_first_operand_equations = id_equations_.find(rhs_dds[0]); - if (existing_first_operand_equations != id_equations_.end()) { - for (auto equation : existing_first_operand_equations->second) { - if (equation.opcode == SpvOpIAdd) { - // Equation form: "a = (d + e) - c" - if (synonymous_.IsEquivalent(*equation.operands[0], - *rhs_dds[1])) { - // Equation form: "a = (c + e) - c" - // We can thus infer "a = e" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], - context); - } - if (synonymous_.IsEquivalent(*equation.operands[1], - *rhs_dds[1])) { - // Equation form: "a = (d + c) - c" - // We can thus infer "a = d" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], - context); - } - } + for (auto equation : GetEquations(rhs_dds[0])) { + if (equation.opcode == SpvOpIAdd) { + // Equation form: "a = (d + e) - c" + if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) { + // Equation form: "a = (c + e) - c" + // We can thus infer "a = e" + AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], context); + } + if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) { + // Equation form: "a = (d + c) - c" + // We can thus infer "a = d" + AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context); + } + } - if (equation.opcode == SpvOpISub) { - // Equation form: "a = (d - e) - c" - if (synonymous_.IsEquivalent(*equation.operands[0], - *rhs_dds[1])) { - // Equation form: "a = (c - e) - c" - // We can thus infer "a = -e" - AddEquationFactRecursive(lhs_dd, SpvOpSNegate, - {equation.operands[1]}, context); - } - } + if (equation.opcode == SpvOpISub) { + // Equation form: "a = (d - e) - c" + if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) { + // Equation form: "a = (c - e) - c" + // We can thus infer "a = -e" + AddEquationFactRecursive(lhs_dd, SpvOpSNegate, + {equation.operands[1]}, context); } } } - { - auto existing_second_operand_equations = id_equations_.find(rhs_dds[1]); - if (existing_second_operand_equations != id_equations_.end()) { - for (auto equation : existing_second_operand_equations->second) { - if (equation.opcode == SpvOpIAdd) { - // Equation form: "a = b - (d + e)" - if (synonymous_.IsEquivalent(*equation.operands[0], - *rhs_dds[0])) { - // Equation form: "a = b - (b + e)" - // We can thus infer "a = -e" - AddEquationFactRecursive(lhs_dd, SpvOpSNegate, - {equation.operands[1]}, context); - } - if (synonymous_.IsEquivalent(*equation.operands[1], - *rhs_dds[0])) { - // Equation form: "a = b - (d + b)" - // We can thus infer "a = -d" - AddEquationFactRecursive(lhs_dd, SpvOpSNegate, - {equation.operands[0]}, context); - } - } - if (equation.opcode == SpvOpISub) { - // Equation form: "a = b - (d - e)" - if (synonymous_.IsEquivalent(*equation.operands[0], - *rhs_dds[0])) { - // Equation form: "a = b - (b - e)" - // We can thus infer "a = e" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], - context); - } - } + for (auto equation : GetEquations(rhs_dds[1])) { + if (equation.opcode == SpvOpIAdd) { + // Equation form: "a = b - (d + e)" + if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) { + // Equation form: "a = b - (b + e)" + // We can thus infer "a = -e" + AddEquationFactRecursive(lhs_dd, SpvOpSNegate, + {equation.operands[1]}, context); + } + if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) { + // Equation form: "a = b - (d + b)" + // We can thus infer "a = -d" + AddEquationFactRecursive(lhs_dd, SpvOpSNegate, + {equation.operands[0]}, context); + } + } + if (equation.opcode == SpvOpISub) { + // Equation form: "a = b - (d - e)" + if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) { + // Equation form: "a = b - (b - e)" + // We can thus infer "a = e" + AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], context); } } } @@ -682,14 +659,11 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive( case SpvOpLogicalNot: case SpvOpSNegate: { // Equation form: "a = !b" or "a = -b" - auto existing_equations = id_equations_.find(rhs_dds[0]); - if (existing_equations != id_equations_.end()) { - for (auto equation : existing_equations->second) { - if (equation.opcode == opcode) { - // Equation form: "a = !!b" or "a = -(-b)" - // We can thus infer "a = b" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context); - } + for (auto equation : GetEquations(rhs_dds[0])) { + if (equation.opcode == opcode) { + // Equation form: "a = !!b" or "a = -(-b)" + // We can thus infer "a = b" + AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context); } } break; @@ -1116,9 +1090,7 @@ void FactManager::DataSynonymAndIdEquationFacts::MakeEquivalent( // equations about |still_representative|; create an empty set of equations // if this is the case. if (!id_equations_.count(still_representative)) { - id_equations_.insert( - {still_representative, - std::unordered_set()}); + id_equations_.insert({still_representative, OperationSet()}); } auto still_representative_id_equations = id_equations_.find(still_representative); diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp index e8871be80..ff660505c 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp @@ -68,9 +68,8 @@ void FuzzerPassAddStores::Apply() { // Not a pointer. return false; } - if (type_inst->GetSingleWordInOperand(0) == - SpvStorageClassInput) { - // Read-only: cannot store to it. + if (instruction->IsReadOnlyPointer()) { + // Read only: cannot store to it. return false; } switch (instruction->result_id()) { diff --git a/3rdparty/spirv-tools/source/fuzz/shrinker.cpp b/3rdparty/spirv-tools/source/fuzz/shrinker.cpp index b8e414536..002e8a7ef 100644 --- a/3rdparty/spirv-tools/source/fuzz/shrinker.cpp +++ b/3rdparty/spirv-tools/source/fuzz/shrinker.cpp @@ -107,7 +107,8 @@ Shrinker::ShrinkerResultStatus Shrinker::Run( } // Initial binary should be valid. - if (!tools.Validate(&binary_in[0], binary_in.size())) { + if (!tools.Validate(&binary_in[0], binary_in.size(), + impl_->validator_options)) { impl_->consumer(SPV_MSG_INFO, nullptr, {}, "Initial binary is invalid; stopping."); return Shrinker::ShrinkerResultStatus::kInitialBinaryInvalid; diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_function.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_function.cpp index c990f2368..90276ed0b 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_function.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_function.cpp @@ -810,8 +810,10 @@ bool TransformationAddFunction::TryToClampAccessChainIndices( ->GetType(index_type_inst->result_id()) ->AsInteger(); - if (index_inst->opcode() != SpvOpConstant) { - // The index is non-constant so we need to clamp it. + if (index_inst->opcode() != SpvOpConstant || + index_inst->GetSingleWordInOperand(0) >= bound) { + // The index is either non-constant or an out-of-bounds constant, so we + // need to clamp it. assert(should_be_composite_type->opcode() != SpvOpTypeStruct && "Access chain indices into structures are required to be " "constants."); @@ -864,21 +866,6 @@ bool TransformationAddFunction::TryToClampAccessChainIndices( access_chain_inst->SetInOperand(index, {select_id}); fuzzerutil::UpdateModuleIdBound(ir_context, compare_id); fuzzerutil::UpdateModuleIdBound(ir_context, select_id); - } else { - // TODO(afd): At present the SPIR-V spec is not clear on whether - // statically out-of-bounds indices mean that a module is invalid (so - // that it should be rejected by the validator), or that such accesses - // yield undefined results. Via the following assertion, we assume that - // functions added to the module do not feature statically out-of-bounds - // accesses. - // Assert that the index is smaller (unsigned) than this value. - // Return false if it is not (to keep compilers happy). - if (index_inst->GetSingleWordInOperand(0) >= bound) { - assert(false && - "The function has a statically out-of-bounds access; " - "this should not occur."); - return false; - } } should_be_composite_type = FollowCompositeIndex(ir_context, *should_be_composite_type, index_id); diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp index d84545a29..05fd923cd 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp @@ -200,21 +200,13 @@ bool TransformationOutlineFunction::IsApplicable( // It is OK (and typically expected) for the exit block of the region to // have successors outside the region. // - // It is also OK for the exit block to head a structured control flow - // construct - the block containing the call to the outlined function will - // end up heading this construct if outlining takes place. However, we - // must ensure that if the exit block heads a loop, the continue target - // for this loop is outside the region. - if (auto loop_merge = block.GetLoopMergeInst()) { - // The exit block heads a loop - auto continue_target = - ir_context->cfg()->block(loop_merge->GetSingleWordOperand(1)); - if (region_set.count(continue_target)) { - // The continue target for the loop is in the region. - return false; - } + // It is also OK for the exit block to head a selection construct: the + // block containing the call to the outlined function will end up heading + // this construct if outlining takes place. However, it is not OK for + // the exit block to head a loop construct. + if (block.GetLoopMergeInst()) { + return false; } - continue; } diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp index 3a106822b..e427f3c36 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp @@ -170,6 +170,15 @@ bool TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym( return false; } } + + if (use_instruction->opcode() == SpvOpImageTexelPointer && + use_in_operand_index == 2) { + // The OpImageTexelPointer instruction has a Sample parameter that in some + // situations must be an id for the value 0. To guard against disrupting + // that requirement, we do not replace this argument to that instruction. + return false; + } + return true; } diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_store.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_store.cpp index 3df1b7d37..f77afe35d 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_store.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_store.cpp @@ -50,7 +50,7 @@ bool TransformationStore::IsApplicable( } // The pointer must not be read only. - if (pointer_type->GetSingleWordInOperand(0) == SpvStorageClassInput) { + if (pointer->IsReadOnlyPointer()) { return false; } diff --git a/3rdparty/spirv-tools/source/opt/CMakeLists.txt b/3rdparty/spirv-tools/source/opt/CMakeLists.txt index 1428c7465..0047c3467 100644 --- a/3rdparty/spirv-tools/source/opt/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/opt/CMakeLists.txt @@ -34,6 +34,7 @@ set(SPIRV_TOOLS_OPT_SOURCES dead_variable_elimination.h decompose_initialized_variables_pass.h decoration_manager.h + debug_info_manager.h def_use_manager.h desc_sroa.h dominator_analysis.h @@ -141,6 +142,7 @@ set(SPIRV_TOOLS_OPT_SOURCES dead_variable_elimination.cpp decompose_initialized_variables_pass.cpp decoration_manager.cpp + debug_info_manager.cpp def_use_manager.cpp desc_sroa.cpp dominator_analysis.cpp diff --git a/3rdparty/spirv-tools/source/opt/code_sink.cpp b/3rdparty/spirv-tools/source/opt/code_sink.cpp index 9d54ee517..4c88cd432 100644 --- a/3rdparty/spirv-tools/source/opt/code_sink.cpp +++ b/3rdparty/spirv-tools/source/opt/code_sink.cpp @@ -177,7 +177,7 @@ bool CodeSinkingPass::ReferencesMutableMemory(Instruction* inst) { return true; } - if (base_ptr->IsReadOnlyVariable()) { + if (base_ptr->IsReadOnlyPointer()) { return false; } diff --git a/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp new file mode 100644 index 000000000..3df3f2b49 --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp @@ -0,0 +1,208 @@ +// Copyright (c) 2020 Google LLC +// +// 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/debug_info_manager.h" + +#include + +#include "source/opt/ir_context.h" + +// Constants for OpenCL.DebugInfo.100 extension instructions. + +static const uint32_t kOpLineOperandLineIndex = 1; +static const uint32_t kLineOperandIndexDebugFunction = 7; +static const uint32_t kLineOperandIndexDebugLexicalBlock = 5; +static const uint32_t kDebugFunctionOperandFunctionIndex = 13; + +namespace spvtools { +namespace opt { +namespace analysis { + +DebugInfoManager::DebugInfoManager(IRContext* c) : context_(c) { + AnalyzeDebugInsts(*c->module()); +} + +Instruction* DebugInfoManager::GetDbgInst(uint32_t id) { + auto dbg_inst_it = id_to_dbg_inst_.find(id); + return dbg_inst_it == id_to_dbg_inst_.end() ? nullptr : dbg_inst_it->second; +} + +void DebugInfoManager::RegisterDbgInst(Instruction* inst) { + assert( + inst->NumInOperands() != 0 && + context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() == + inst->GetInOperand(0).words[0] && + "Given instruction is not a debug instruction"); + id_to_dbg_inst_[inst->result_id()] = inst; +} + +void DebugInfoManager::RegisterDbgFunction(Instruction* inst) { + assert(inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction && + "inst is not a DebugFunction"); + auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex); + assert( + fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() && + "Register DebugFunction for a function that already has DebugFunction"); + fn_id_to_dbg_fn_[fn_id] = inst; +} + +uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line, + const DebugScope& scope) { + if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() == + 0) + return kNoInlinedAt; + + uint32_t line_number = 0; + if (line == nullptr) { + auto* lexical_scope_inst = GetDbgInst(scope.GetLexicalScope()); + if (lexical_scope_inst == nullptr) return kNoInlinedAt; + OpenCLDebugInfo100Instructions debug_opcode = + lexical_scope_inst->GetOpenCL100DebugOpcode(); + switch (debug_opcode) { + case OpenCLDebugInfo100DebugFunction: + line_number = lexical_scope_inst->GetSingleWordOperand( + kLineOperandIndexDebugFunction); + break; + case OpenCLDebugInfo100DebugLexicalBlock: + line_number = lexical_scope_inst->GetSingleWordOperand( + kLineOperandIndexDebugLexicalBlock); + break; + case OpenCLDebugInfo100DebugTypeComposite: + case OpenCLDebugInfo100DebugCompilationUnit: + assert(false && + "DebugTypeComposite and DebugCompilationUnit are lexical " + "scopes, but we inline functions into a function or a block " + "of a function, not into a struct/class or a global scope."); + break; + default: + assert(false && + "Unreachable. a debug extension instruction for a " + "lexical scope must be DebugFunction, DebugTypeComposite, " + "DebugLexicalBlock, or DebugCompilationUnit."); + break; + } + } else { + line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex); + } + + uint32_t result_id = context()->TakeNextId(); + std::unique_ptr inlined_at(new Instruction( + context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), + result_id, + { + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, + {context() + ->get_feature_mgr() + ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, + {static_cast(OpenCLDebugInfo100DebugInlinedAt)}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetLexicalScope()}}, + })); + // |scope| already has DebugInlinedAt. We put the existing DebugInlinedAt + // into the Inlined operand of this new DebugInlinedAt. + if (scope.GetInlinedAt() != kNoInlinedAt) { + inlined_at->AddOperand({spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID, + {scope.GetInlinedAt()}}); + } + RegisterDbgInst(inlined_at.get()); + context()->module()->AddExtInstDebugInfo(std::move(inlined_at)); + return result_id; +} + +Instruction* DebugInfoManager::GetDebugInfoNone() { + if (debug_info_none_inst_ != nullptr) return debug_info_none_inst_; + + uint32_t result_id = context()->TakeNextId(); + std::unique_ptr dbg_info_none_inst(new Instruction( + context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), + result_id, + { + {SPV_OPERAND_TYPE_RESULT_ID, + {context() + ->get_feature_mgr() + ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, + {static_cast(OpenCLDebugInfo100DebugInfoNone)}}, + })); + + // Add to the front of |ext_inst_debuginfo_|. + debug_info_none_inst_ = + context()->module()->ext_inst_debuginfo_begin()->InsertBefore( + std::move(dbg_info_none_inst)); + + RegisterDbgInst(debug_info_none_inst_); + return debug_info_none_inst_; +} + +Instruction* DebugInfoManager::GetDebugInlinedAt(uint32_t dbg_inlined_at_id) { + auto* inlined_at = GetDbgInst(dbg_inlined_at_id); + if (inlined_at == nullptr) return nullptr; + if (inlined_at->GetOpenCL100DebugOpcode() != + OpenCLDebugInfo100DebugInlinedAt) { + return nullptr; + } + return inlined_at; +} + +Instruction* DebugInfoManager::CloneDebugInlinedAt(uint32_t clone_inlined_at_id, + Instruction* insert_before) { + auto* inlined_at = GetDebugInlinedAt(clone_inlined_at_id); + if (inlined_at == nullptr) return nullptr; + std::unique_ptr new_inlined_at(inlined_at->Clone(context())); + new_inlined_at->SetResultId(context()->TakeNextId()); + RegisterDbgInst(new_inlined_at.get()); + if (insert_before != nullptr) + return insert_before->InsertBefore(std::move(new_inlined_at)); + return context()->module()->ext_inst_debuginfo_end()->InsertBefore( + std::move(new_inlined_at)); +} + +void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) { + if (dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100InstructionsMax) + return; + + RegisterDbgInst(dbg_inst); + + if (dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) { + assert(GetDebugFunction(dbg_inst->GetSingleWordOperand( + kDebugFunctionOperandFunctionIndex)) == nullptr && + "Two DebugFunction instruction exists for a single OpFunction."); + RegisterDbgFunction(dbg_inst); + } + + if (debug_info_none_inst_ == nullptr && + dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) { + debug_info_none_inst_ = dbg_inst; + } +} + +void DebugInfoManager::AnalyzeDebugInsts(Module& module) { + debug_info_none_inst_ = nullptr; + module.ForEachInst([this](Instruction* cpi) { AnalyzeDebugInst(cpi); }); + + // Move |debug_info_none_inst_| to the beginning of the debug instruction + // list. + if (debug_info_none_inst_ != nullptr && + debug_info_none_inst_->PreviousNode() != nullptr && + debug_info_none_inst_->PreviousNode()->GetOpenCL100DebugOpcode() != + OpenCLDebugInfo100InstructionsMax) { + debug_info_none_inst_->InsertBefore( + &*context()->module()->ext_inst_debuginfo_begin()); + } +} + +} // namespace analysis +} // namespace opt +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/debug_info_manager.h b/3rdparty/spirv-tools/source/opt/debug_info_manager.h new file mode 100644 index 000000000..a2746deca --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/debug_info_manager.h @@ -0,0 +1,115 @@ +// Copyright (c) 2020 Google LLC +// +// 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. + +#ifndef SOURCE_OPT_DEBUG_INFO_MANAGER_H_ +#define SOURCE_OPT_DEBUG_INFO_MANAGER_H_ + +#include + +#include "source/opt/instruction.h" +#include "source/opt/module.h" + +namespace spvtools { +namespace opt { +namespace analysis { + +// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 extension +// instructions. +class DebugInfoManager { + public: + // Constructs a debug information manager from the given |context|. + DebugInfoManager(IRContext* context); + + DebugInfoManager(const DebugInfoManager&) = delete; + DebugInfoManager(DebugInfoManager&&) = delete; + DebugInfoManager& operator=(const DebugInfoManager&) = delete; + DebugInfoManager& operator=(DebugInfoManager&&) = delete; + + friend bool operator==(const DebugInfoManager&, const DebugInfoManager&); + friend bool operator!=(const DebugInfoManager& lhs, + const DebugInfoManager& rhs) { + return !(lhs == rhs); + } + + // Analyzes OpenCL.DebugInfo.100 instruction |dbg_inst|. + void AnalyzeDebugInst(Instruction* dbg_inst); + + // Creates new DebugInlinedAt and returns its id. Its line operand is the + // line number of |line| if |line| is not nullptr. Otherwise, its line operand + // is the line number of lexical scope of |scope|. Its Scope and Inlined + // operands are Scope and Inlined of |scope|. + uint32_t CreateDebugInlinedAt(const Instruction* line, + const DebugScope& scope); + + // Returns a DebugInfoNone instruction. + Instruction* GetDebugInfoNone(); + + // Returns DebugInlinedAt whose id is |dbg_inlined_at_id|. If it does not + // exist or it is not a DebugInlinedAt instruction, return nullptr. + Instruction* GetDebugInlinedAt(uint32_t dbg_inlined_at_id); + + // Returns DebugFunction whose Function operand is |fn_id|. If it does not + // exist, return nullptr. + Instruction* GetDebugFunction(uint32_t fn_id) { + auto dbg_fn_it = fn_id_to_dbg_fn_.find(fn_id); + return dbg_fn_it == fn_id_to_dbg_fn_.end() ? nullptr : dbg_fn_it->second; + } + + // Clones DebugInlinedAt whose id is |clone_inlined_at_id|. If + // |clone_inlined_at_id| is not an id of DebugInlinedAt, returns nullptr. + // If |insert_before| is given, inserts the new DebugInlinedAt before it. + // Otherwise, inserts the new DebugInlinedAt into the debug instruction + // section of the module. + Instruction* CloneDebugInlinedAt(uint32_t clone_inlined_at_id, + Instruction* insert_before = nullptr); + + private: + IRContext* context() { return context_; } + + // Analyzes OpenCL.DebugInfo.100 instructions in the given |module| and + // populates data structures in this class. + void AnalyzeDebugInsts(Module& module); + + // Returns the debug instruction whose id is |id|. Returns |nullptr| if one + // does not exists. + Instruction* GetDbgInst(uint32_t id); + + // Registers the debug instruction |inst| into |id_to_dbg_inst_| using id of + // |inst| as a key. + void RegisterDbgInst(Instruction* inst); + + // Register the DebugFunction instruction |inst|. The function referenced + // in |inst| must not already be registered. + void RegisterDbgFunction(Instruction* inst); + + IRContext* context_; + + // Mapping from ids of OpenCL.DebugInfo.100 extension instructions + // to their Instruction instances. + std::unordered_map id_to_dbg_inst_; + + // Mapping from function's ids to DebugFunction instructions whose + // operand is the function. + std::unordered_map fn_id_to_dbg_fn_; + + // DebugInfoNone instruction. We need only a single DebugInfoNone. + // To reuse the existing one, we keep it using this member variable. + Instruction* debug_info_none_inst_; +}; + +} // namespace analysis +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_DEBUG_INFO_MANAGER_H_ diff --git a/3rdparty/spirv-tools/source/opt/function.h b/3rdparty/spirv-tools/source/opt/function.h index f208d8e4d..d7e41760e 100644 --- a/3rdparty/spirv-tools/source/opt/function.h +++ b/3rdparty/spirv-tools/source/opt/function.h @@ -192,13 +192,13 @@ inline void Function::AddBasicBlocks(T src_begin, T src_end, iterator ip) { } inline void Function::MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip) { - auto block_to_move = std::move(*FindBlock(id).Get()); + std::unique_ptr block_to_move = std::move(*FindBlock(id).Get()); + blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr)); assert(block_to_move->GetParent() == ip->GetParent() && "Both blocks have to be in the same function."); InsertBasicBlockAfter(std::move(block_to_move), ip); - blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr)); } inline void Function::RemoveEmptyBlocks() { diff --git a/3rdparty/spirv-tools/source/opt/instruction.cpp b/3rdparty/spirv-tools/source/opt/instruction.cpp index 9e54e7e8d..7052d3e72 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.cpp +++ b/3rdparty/spirv-tools/source/opt/instruction.cpp @@ -29,7 +29,7 @@ namespace { // Indices used to get particular operands out of instructions using InOperand. const uint32_t kTypeImageDimIndex = 1; const uint32_t kLoadBaseIndex = 0; -const uint32_t kVariableStorageClassIndex = 0; +const uint32_t kPointerTypeStorageClassIndex = 0; const uint32_t kTypeImageSampledIndex = 5; // Constants for OpenCL.DebugInfo.100 extension instructions. @@ -187,7 +187,7 @@ bool Instruction::IsReadOnlyLoad() const { } if (address_def->opcode() == SpvOpVariable) { - if (address_def->IsReadOnlyVariable()) { + if (address_def->IsReadOnlyPointer()) { return true; } } @@ -232,11 +232,11 @@ Instruction* Instruction::GetBaseAddress() const { return base_inst; } -bool Instruction::IsReadOnlyVariable() const { +bool Instruction::IsReadOnlyPointer() const { if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) - return IsReadOnlyVariableShaders(); + return IsReadOnlyPointerShaders(); else - return IsReadOnlyVariableKernel(); + return IsReadOnlyPointerKernel(); } bool Instruction::IsVulkanStorageImage() const { @@ -244,7 +244,8 @@ bool Instruction::IsVulkanStorageImage() const { return false; } - uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex); + uint32_t storage_class = + GetSingleWordInOperand(kPointerTypeStorageClassIndex); if (storage_class != SpvStorageClassUniformConstant) { return false; } @@ -278,7 +279,8 @@ bool Instruction::IsVulkanSampledImage() const { return false; } - uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex); + uint32_t storage_class = + GetSingleWordInOperand(kPointerTypeStorageClassIndex); if (storage_class != SpvStorageClassUniformConstant) { return false; } @@ -312,7 +314,8 @@ bool Instruction::IsVulkanStorageTexelBuffer() const { return false; } - uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex); + uint32_t storage_class = + GetSingleWordInOperand(kPointerTypeStorageClassIndex); if (storage_class != SpvStorageClassUniformConstant) { return false; } @@ -361,7 +364,8 @@ bool Instruction::IsVulkanStorageBuffer() const { return false; } - uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex); + uint32_t storage_class = + GetSingleWordInOperand(kPointerTypeStorageClassIndex); if (storage_class == SpvStorageClassUniform) { bool is_buffer_block = false; context()->get_decoration_mgr()->ForEachDecoration( @@ -383,7 +387,8 @@ bool Instruction::IsVulkanUniformBuffer() const { return false; } - uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex); + uint32_t storage_class = + GetSingleWordInOperand(kPointerTypeStorageClassIndex); if (storage_class != SpvStorageClassUniform) { return false; } @@ -409,9 +414,18 @@ bool Instruction::IsVulkanUniformBuffer() const { return is_block; } -bool Instruction::IsReadOnlyVariableShaders() const { - uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex); +bool Instruction::IsReadOnlyPointerShaders() const { + if (type_id() == 0) { + return false; + } + Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id()); + if (type_def->opcode() != SpvOpTypePointer) { + return false; + } + + uint32_t storage_class = + type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex); switch (storage_class) { case SpvStorageClassUniformConstant: @@ -439,8 +453,19 @@ bool Instruction::IsReadOnlyVariableShaders() const { return is_nonwritable; } -bool Instruction::IsReadOnlyVariableKernel() const { - uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex); +bool Instruction::IsReadOnlyPointerKernel() const { + if (type_id() == 0) { + return false; + } + + Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id()); + if (type_def->opcode() != SpvOpTypePointer) { + return false; + } + + uint32_t storage_class = + type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex); + return storage_class == SpvStorageClassUniformConstant; } diff --git a/3rdparty/spirv-tools/source/opt/instruction.h b/3rdparty/spirv-tools/source/opt/instruction.h index 008a831bb..87d772251 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.h +++ b/3rdparty/spirv-tools/source/opt/instruction.h @@ -92,6 +92,19 @@ struct Operand { // Returns a string operand as a std::string. std::string AsString() const { return AsCString(); } + // Returns a literal integer operand as a uint64_t + uint64_t AsLiteralUint64() const { + assert(type == SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER); + assert(1 <= words.size()); + assert(words.size() <= 2); + // Load the low word. + uint64_t result = uint64_t(words[0]); + if (words.size() > 1) { + result = result | (uint64_t(words[1]) << 32); + } + return result; + } + friend bool operator==(const Operand& o1, const Operand& o2) { return o1.type == o2.type && o1.words == o2.words; } @@ -383,8 +396,14 @@ class Instruction : public utils::IntrusiveNodeBase { // Memory-to-memory instructions are not considered loads. inline bool IsLoad() const; - // Returns true if the instruction declares a variable that is read-only. - bool IsReadOnlyVariable() const; + // Returns true if the instruction generates a pointer that is definitely + // read-only. This is determined by analysing the pointer type's storage + // class and decorations that target the pointer's id. It does not analyse + // other instructions that the pointer may be derived from. Thus if 'true' is + // returned, the pointer is definitely read-only, while if 'false' is returned + // it is possible that the pointer may actually be read-only if it is derived + // from another pointer that is decorated as read-only. + bool IsReadOnlyPointer() const; // The following functions check for the various descriptor types defined in // the Vulkan specification section 13.1. @@ -513,11 +532,12 @@ class Instruction : public utils::IntrusiveNodeBase { return 0; } - // Returns true if the instruction declares a variable that is read-only. The - // first version assumes the module is a shader module. The second assumes a + // Returns true if the instruction generates a read-only pointer, with the + // same caveats documented in the comment for IsReadOnlyPointer. The first + // version assumes the module is a shader module. The second assumes a // kernel. - bool IsReadOnlyVariableShaders() const; - bool IsReadOnlyVariableKernel() const; + bool IsReadOnlyPointerShaders() const; + bool IsReadOnlyPointerKernel() const; // Returns true if the result of |inst| can be used as the base image for an // instruction that samples a image, reads an image, or writes to an image. diff --git a/3rdparty/spirv-tools/source/opt/ir_context.cpp b/3rdparty/spirv-tools/source/opt/ir_context.cpp index c4378d37b..df04066f3 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_context.cpp @@ -85,6 +85,9 @@ void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) { if (set & kAnalysisTypes) { BuildTypeManager(); } + if (set & kAnalysisDebugInfo) { + BuildDebugInfoManager(); + } } void IRContext::InvalidateAnalysesExceptFor( @@ -98,6 +101,7 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) { // away, the ConstantManager has to go away. if (analyses_to_invalidate & kAnalysisTypes) { analyses_to_invalidate |= kAnalysisConstants; + analyses_to_invalidate |= kAnalysisDebugInfo; } // The dominator analysis hold the psuedo entry and exit nodes from the CFG. @@ -148,6 +152,10 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) { type_mgr_.reset(nullptr); } + if (analyses_to_invalidate & kAnalysisDebugInfo) { + debug_info_mgr_.reset(nullptr); + } + valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate); } @@ -373,27 +381,6 @@ void IRContext::KillNamesAndDecorates(Instruction* inst) { KillNamesAndDecorates(rId); } -Instruction* IRContext::GetOpenCL100DebugInfoNone() { - if (debug_info_none_inst_) return debug_info_none_inst_; - assert(get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() && - "Module does not include debug info extension instruction."); - - // Create a new DebugInfoNone. - std::unique_ptr dbg_info_none(new Instruction( - this, SpvOpExtInst, get_type_mgr()->GetVoidTypeId(), TakeNextId(), - { - {SPV_OPERAND_TYPE_RESULT_ID, - {get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()}}, - {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugInfoNone)}}, - })); - - // Add to the front of |ext_inst_debuginfo_|. - debug_info_none_inst_ = module()->ext_inst_debuginfo_begin()->InsertBefore( - std::move(dbg_info_none)); - return debug_info_none_inst_; -} - void IRContext::KillOperandFromDebugInstructions(Instruction* inst) { const auto opcode = inst->opcode(); const uint32_t id = inst->result_id(); @@ -405,7 +392,8 @@ void IRContext::KillOperandFromDebugInstructions(Instruction* inst) { continue; auto& operand = it->GetOperand(kDebugFunctionOperandFunctionIndex); if (operand.words[0] == id) { - operand.words[0] = GetOpenCL100DebugInfoNone()->result_id(); + operand.words[0] = + get_debug_info_mgr()->GetDebugInfoNone()->result_id(); } } } @@ -418,7 +406,8 @@ void IRContext::KillOperandFromDebugInstructions(Instruction* inst) { continue; auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex); if (operand.words[0] == id) { - operand.words[0] = GetOpenCL100DebugInfoNone()->result_id(); + operand.words[0] = + get_debug_info_mgr()->GetDebugInfoNone()->result_id(); } } } diff --git a/3rdparty/spirv-tools/source/opt/ir_context.h b/3rdparty/spirv-tools/source/opt/ir_context.h index b275ae4ac..a1b63ff9e 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.h +++ b/3rdparty/spirv-tools/source/opt/ir_context.h @@ -29,6 +29,7 @@ #include "source/assembly_grammar.h" #include "source/opt/cfg.h" #include "source/opt/constants.h" +#include "source/opt/debug_info_manager.h" #include "source/opt/decoration_manager.h" #include "source/opt/def_use_manager.h" #include "source/opt/dominator_analysis.h" @@ -78,7 +79,8 @@ class IRContext { kAnalysisIdToFuncMapping = 1 << 13, kAnalysisConstants = 1 << 14, kAnalysisTypes = 1 << 15, - kAnalysisEnd = 1 << 16 + kAnalysisDebugInfo = 1 << 16, + kAnalysisEnd = 1 << 17 }; using ProcessFunction = std::function; @@ -102,8 +104,7 @@ class IRContext { id_to_name_(nullptr), max_id_bound_(kDefaultMaxIdBound), preserve_bindings_(false), - preserve_spec_constants_(false), - debug_info_none_inst_(nullptr) { + preserve_spec_constants_(false) { SetContextMessageConsumer(syntax_context_, consumer_); module_->SetContext(this); } @@ -120,8 +121,7 @@ class IRContext { id_to_name_(nullptr), max_id_bound_(kDefaultMaxIdBound), preserve_bindings_(false), - preserve_spec_constants_(false), - debug_info_none_inst_(nullptr) { + preserve_spec_constants_(false) { SetContextMessageConsumer(syntax_context_, consumer_); module_->SetContext(this); InitializeCombinators(); @@ -328,6 +328,17 @@ class IRContext { return type_mgr_.get(); } + // Returns a pointer to the debug information manager. If no debug + // information manager has been created yet, it creates one. + // NOTE: Once created, the debug information manager remains active + // it is never re-built. + analysis::DebugInfoManager* get_debug_info_mgr() { + if (!AreAnalysesValid(kAnalysisDebugInfo)) { + BuildDebugInfoManager(); + } + return debug_info_mgr_.get(); + } + // Returns a pointer to the scalar evolution analysis. If it is invalid it // will be rebuilt first. ScalarEvolutionAnalysis* GetScalarEvolutionAnalysis() { @@ -657,6 +668,13 @@ class IRContext { valid_analyses_ = valid_analyses_ | kAnalysisTypes; } + // Builds the debug information manager from scratch, even if it was + // already valid. + void BuildDebugInfoManager() { + debug_info_mgr_ = MakeUnique(this); + valid_analyses_ = valid_analyses_ | kAnalysisDebugInfo; + } + // Removes all computed dominator and post-dominator trees. This will force // the context to rebuild the trees on demand. void ResetDominatorAnalysis() { @@ -710,9 +728,6 @@ class IRContext { // Add |var_id| to all entry points in module. void AddVarToEntryPoints(uint32_t var_id); - // Get the existing DebugInfoNone. If it is null, create one and keep it. - Instruction* GetOpenCL100DebugInfoNone(); - // The SPIR-V syntax context containing grammar tables for opcodes and // operands. spv_context syntax_context_; @@ -782,6 +797,9 @@ class IRContext { // Type manager for |module_|. std::unique_ptr type_mgr_; + // Debug information manager for |module_|. + std::unique_ptr debug_info_mgr_; + // A map from an id to its corresponding OpName and OpMemberName instructions. std::unique_ptr> id_to_name_; @@ -806,10 +824,6 @@ class IRContext { // Whether all specialization constants within |module_| // should be preserved. bool preserve_spec_constants_; - - // DebugInfoNone instruction. We need only a single DebugInfoNone. - // To reuse the existing one, we keep it using this member variable. - Instruction* debug_info_none_inst_; }; inline IRContext::Analysis operator|(IRContext::Analysis lhs, diff --git a/3rdparty/spirv-tools/source/opt/ir_loader.cpp b/3rdparty/spirv-tools/source/opt/ir_loader.cpp index fcde0797b..acd41cd64 100644 --- a/3rdparty/spirv-tools/source/opt/ir_loader.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_loader.cpp @@ -135,6 +135,8 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { Error(consumer_, src, loc, "terminator instruction outside basic block"); return false; } + if (last_dbg_scope_.GetLexicalScope() != kNoDebugScope) + spv_inst->SetDebugScope(last_dbg_scope_); block_->AddInstruction(std::move(spv_inst)); function_->AddBasicBlock(std::move(block_)); block_ = nullptr; diff --git a/3rdparty/spirv-tools/source/spirv_reducer_options.cpp b/3rdparty/spirv-tools/source/spirv_reducer_options.cpp index 5801d0a16..e80787538 100644 --- a/3rdparty/spirv-tools/source/spirv_reducer_options.cpp +++ b/3rdparty/spirv-tools/source/spirv_reducer_options.cpp @@ -19,7 +19,7 @@ namespace { // The default maximum number of steps the reducer will take before giving up. -const uint32_t kDefaultStepLimit = 250; +const uint32_t kDefaultStepLimit = 2500; } // namespace spv_reducer_options_t::spv_reducer_options_t()