diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 0346bce31..43c0400d3 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 36e37dd5b53636024ccb44310450d4128dae0842" +"v2020.3-dev", "SPIRV-Tools v2020.3-dev 0778398f58d93ce8a861aeeb7a6a60324383525e" diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp index bb48303ef..fc71d344c 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp @@ -124,6 +124,7 @@ SpvStorageClass FuzzerPassDonateModules::AdaptStorageClass( case SpvStorageClassUniform: case SpvStorageClassUniformConstant: case SpvStorageClassPushConstant: + case SpvStorageClassImage: // We change these to Private return SpvStorageClassPrivate; default: @@ -721,11 +722,12 @@ bool FuzzerPassDonateModules::CanDonateInstruction( // We do not have a mapped result id for this id operand. That either // means that it is a forward reference (which is OK), that we skipped // the instruction that generated it (which is not OK), or that it is - // the id of a function that we did not donate (which is not OK). We - // check for the latter two cases. + // the id of a function or global value that we did not donate (which + // is not OK). We check for the latter two cases. if (skipped_instructions.count(*in_id) || - donor_ir_context->get_def_use_mgr()->GetDef(*in_id)->opcode() == - SpvOpFunction) { + // A function or global value does not have an associated basic + // block. + !donor_ir_context->get_instr_block(*in_id)) { result = false; return false; } diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h index e61572c53..c59ad71d1 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h @@ -66,7 +66,7 @@ class FuzzerPassDonateModules : public FuzzerPass { opt::IRContext* donor_ir_context, std::map* original_id_to_donated_id); - // TODO comment + // Helper method for HandleTypesAndValues, to handle a single type/value. void HandleTypeOrValue( const opt::Instruction& type_or_value, std::map* original_id_to_donated_id); diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp index 4d85984c5..f09943fe6 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp @@ -218,6 +218,12 @@ bool CanInsertOpcodeBeforeInstruction( } bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst) { + if (inst->opcode() == SpvOpSampledImage) { + // The SPIR-V data rules say that only very specific instructions may + // may consume the result id of an OpSampledImage, and this excludes the + // instructions that are used for making synonyms. + return false; + } if (!inst->HasResultId()) { // We can only make a synonym of an instruction that generates an id. return false; diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp index 117cdc6f8..d84545a29 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp @@ -198,10 +198,23 @@ bool TransformationOutlineFunction::IsApplicable( for (auto& block : *entry_block->GetParent()) { if (&block == exit_block) { // 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. + // 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; + } + } + continue; } @@ -274,12 +287,20 @@ bool TransformationOutlineFunction::IsApplicable( } // For each region output id -- i.e. every id defined inside the region but - // used outside the region -- there needs to be a corresponding fresh id that - // can hold the value for this id computed in the outlined function. + // used outside the region, ... std::map output_id_to_fresh_id_map = PairSequenceToMap(message_.output_id_to_fresh_id()); for (auto id : GetRegionOutputIds(ir_context, region_set, exit_block)) { - if (output_id_to_fresh_id_map.count(id) == 0) { + if ( + // ... there needs to be a corresponding fresh id that can hold the + // value for this id computed in the outlined function, and ... + output_id_to_fresh_id_map.count(id) == 0 + // ... the output id must not have pointer type (to avoid creating a + // struct with pointer members to pass data out of the outlined + // function) + || ir_context->get_def_use_mgr() + ->GetDef(fuzzerutil::GetTypeId(ir_context, id)) + ->opcode() == SpvOpTypePointer) { return false; } } 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 87194c8eb..89343b496 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 @@ -125,6 +125,9 @@ bool TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym( } else if (composite_type_being_accessed->AsArray()) { composite_type_being_accessed = composite_type_being_accessed->AsArray()->element_type(); + } else if (composite_type_being_accessed->AsRuntimeArray()) { + composite_type_being_accessed = + composite_type_being_accessed->AsRuntimeArray()->element_type(); } else { assert(composite_type_being_accessed->AsStruct()); auto constant_index_instruction = ir_context->get_def_use_mgr()->GetDef( diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp index 3de081e03..b020d98a0 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp @@ -76,8 +76,34 @@ bool TransformationSplitBlock::IsApplicable( } // We cannot split before an OpPhi unless the OpPhi has exactly one // associated incoming edge. - return !(split_before->opcode() == SpvOpPhi && - split_before->NumInOperands() != 2); + if (split_before->opcode() == SpvOpPhi && + split_before->NumInOperands() != 2) { + return false; + } + + // Splitting the block must not separate the definition of an OpSampledImage + // from its use: the SPIR-V data rules require them to be in the same block. + std::set sampled_image_result_ids; + bool before_split = true; + for (auto& instruction : *block_to_split) { + if (&instruction == &*split_before) { + before_split = false; + } + if (before_split) { + if (instruction.opcode() == SpvOpSampledImage) { + sampled_image_result_ids.insert(instruction.result_id()); + } + } else { + if (!instruction.WhileEachInId( + [&sampled_image_result_ids](uint32_t* id) -> bool { + return !sampled_image_result_ids.count(*id); + })) { + return false; + } + } + } + + return true; } void TransformationSplitBlock::Apply( diff --git a/3rdparty/spirv-tools/source/opt/feature_manager.cpp b/3rdparty/spirv-tools/source/opt/feature_manager.cpp index b4d6f1ba5..ad70c1e4f 100644 --- a/3rdparty/spirv-tools/source/opt/feature_manager.cpp +++ b/3rdparty/spirv-tools/source/opt/feature_manager.cpp @@ -78,6 +78,8 @@ void FeatureManager::AddCapabilities(Module* module) { void FeatureManager::AddExtInstImportIds(Module* module) { extinst_importid_GLSLstd450_ = module->GetExtInstImportId("GLSL.std.450"); + extinst_importid_OpenCL100DebugInfo_ = + module->GetExtInstImportId("OpenCL.DebugInfo.100"); } bool operator==(const FeatureManager& a, const FeatureManager& b) { @@ -100,6 +102,11 @@ bool operator==(const FeatureManager& a, const FeatureManager& b) { return false; } + if (a.extinst_importid_OpenCL100DebugInfo_ != + b.extinst_importid_OpenCL100DebugInfo_) { + return false; + } + return true; } } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/feature_manager.h b/3rdparty/spirv-tools/source/opt/feature_manager.h index 881d5e601..66d1cbac3 100644 --- a/3rdparty/spirv-tools/source/opt/feature_manager.h +++ b/3rdparty/spirv-tools/source/opt/feature_manager.h @@ -51,6 +51,10 @@ class FeatureManager { return extinst_importid_GLSLstd450_; } + uint32_t GetExtInstImportId_OpenCL100DebugInfo() const { + return extinst_importid_OpenCL100DebugInfo_; + } + friend bool operator==(const FeatureManager& a, const FeatureManager& b); friend bool operator!=(const FeatureManager& a, const FeatureManager& b) { return !(a == b); @@ -84,6 +88,10 @@ class FeatureManager { // Common external instruction import ids, cached for performance. uint32_t extinst_importid_GLSLstd450_ = 0; + + // Common OpenCL100DebugInfo external instruction import ids, cached + // for performance. + uint32_t extinst_importid_OpenCL100DebugInfo_ = 0; }; } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/function.cpp b/3rdparty/spirv-tools/source/opt/function.cpp index 5d50f37c6..2b7b4fb80 100644 --- a/3rdparty/spirv-tools/source/opt/function.cpp +++ b/3rdparty/spirv-tools/source/opt/function.cpp @@ -84,9 +84,12 @@ bool Function::WhileEachInst(const std::function& f, } } - for (auto& di : debug_insts_in_header_) { - if (!di.WhileEachInst(f, run_on_debug_line_insts)) { - return false; + if (!debug_insts_in_header_.empty()) { + Instruction* di = &debug_insts_in_header_.front(); + while (di != nullptr) { + Instruction* next_instruction = di->NextNode(); + if (!di->WhileEachInst(f, run_on_debug_line_insts)) return false; + di = next_instruction; } } @@ -118,9 +121,9 @@ bool Function::WhileEachInst(const std::function& f, } for (const auto& di : debug_insts_in_header_) { - if (!di.WhileEachInst(f, run_on_debug_line_insts)) { + if (!static_cast(&di)->WhileEachInst( + f, run_on_debug_line_insts)) return false; - } } for (const auto& bb : blocks_) { diff --git a/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp b/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp index 22c979cf3..db14020db 100644 --- a/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp @@ -802,8 +802,11 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer( opt::Instruction* image_texel_pointer) { // TODO(dneto): Write tests for this code. // TODO(dneto): Use signed-clamp + (void)(image_texel_pointer); return SPV_SUCCESS; + // Do not compile this code until it is ready to be used. +#if 0 // Example: // %texel_ptr = OpImageTexelPointer %texel_ptr_type %image_ptr %coord // %sample @@ -1035,6 +1038,7 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer( def_use_mgr->AnalyzeInstUse(image_texel_pointer); return SPV_SUCCESS; +#endif } opt::Instruction* GraphicsRobustAccessPass::InsertInst( diff --git a/3rdparty/spirv-tools/source/opt/instruction.cpp b/3rdparty/spirv-tools/source/opt/instruction.cpp index 3ce38a9a7..9e54e7e8d 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.cpp +++ b/3rdparty/spirv-tools/source/opt/instruction.cpp @@ -33,6 +33,8 @@ const uint32_t kVariableStorageClassIndex = 0; const uint32_t kTypeImageSampledIndex = 5; // Constants for OpenCL.DebugInfo.100 extension instructions. +const uint32_t kExtInstSetIdInIdx = 0; +const uint32_t kExtInstInstructionInIdx = 1; const uint32_t kDebugScopeNumWords = 7; const uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6; const uint32_t kDebugNoScopeNumWords = 5; @@ -180,10 +182,27 @@ void Instruction::ReplaceOperands(const OperandList& new_operands) { bool Instruction::IsReadOnlyLoad() const { if (IsLoad()) { Instruction* address_def = GetBaseAddress(); - if (!address_def || address_def->opcode() != SpvOpVariable) { + if (!address_def) { return false; } - return address_def->IsReadOnlyVariable(); + + if (address_def->opcode() == SpvOpVariable) { + if (address_def->IsReadOnlyVariable()) { + return true; + } + } + + if (address_def->opcode() == SpvOpLoad) { + const analysis::Type* address_type = + context()->get_type_mgr()->GetType(address_def->type_id()); + if (address_type->AsSampledImage() != nullptr) { + const auto* image_type = + address_type->AsSampledImage()->image_type()->AsImage(); + if (image_type->sampled() == 1) { + return true; + } + } + } } return false; } @@ -510,6 +529,21 @@ bool Instruction::IsValidBasePointer() const { return false; } +OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const { + if (opcode() != SpvOpExtInst) return OpenCLDebugInfo100InstructionsMax; + + if (!context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) + return OpenCLDebugInfo100InstructionsMax; + + if (GetSingleWordInOperand(kExtInstSetIdInIdx) != + context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) { + return OpenCLDebugInfo100InstructionsMax; + } + + return OpenCLDebugInfo100Instructions( + GetSingleWordInOperand(kExtInstInstructionInIdx)); +} + bool Instruction::IsValidBaseImage() const { uint32_t tid = type_id(); if (tid == 0) { @@ -714,9 +748,6 @@ bool Instruction::IsScalarizable() const { return true; } - const uint32_t kExtInstSetIdInIdx = 0; - const uint32_t kExtInstInstructionInIdx = 1; - if (opcode() == SpvOpExtInst) { uint32_t instSetId = context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); diff --git a/3rdparty/spirv-tools/source/opt/instruction.h b/3rdparty/spirv-tools/source/opt/instruction.h index a3342c616..008a831bb 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.h +++ b/3rdparty/spirv-tools/source/opt/instruction.h @@ -22,14 +22,14 @@ #include #include -#include "source/opcode.h" -#include "source/operand.h" -#include "source/util/ilist_node.h" -#include "source/util/small_vector.h" - +#include "OpenCLDebugInfo100.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/latest_version_spirv_header.h" +#include "source/opcode.h" +#include "source/operand.h" #include "source/opt/reflect.h" +#include "source/util/ilist_node.h" +#include "source/util/small_vector.h" #include "spirv-tools/libspirv.h" const uint32_t kNoDebugScope = 0; @@ -496,6 +496,11 @@ class Instruction : public utils::IntrusiveNodeBase { // rules for physical addressing. bool IsValidBasePointer() const; + // Returns debug opcode of an OpenCL.100.DebugInfo instruction. If + // it is not an OpenCL.100.DebugInfo instruction, just returns + // OpenCLDebugInfo100InstructionsMax. + OpenCLDebugInfo100Instructions GetOpenCL100DebugOpcode() const; + // Dump this instruction on stderr. Useful when running interactive // debuggers. void Dump() const; diff --git a/3rdparty/spirv-tools/source/opt/ir_context.cpp b/3rdparty/spirv-tools/source/opt/ir_context.cpp index 72993fd64..c4378d37b 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_context.cpp @@ -16,6 +16,7 @@ #include +#include "OpenCLDebugInfo100.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/opt/log.h" #include "source/opt/mem_pass.h" @@ -29,6 +30,10 @@ static const int kSpvDecorateBuiltinInIdx = 2; static const int kEntryPointInterfaceInIdx = 3; static const int kEntryPointFunctionIdInIdx = 1; +// Constants for OpenCL.DebugInfo.100 extension instructions. +static const uint32_t kDebugFunctionOperandFunctionIndex = 13; +static const uint32_t kDebugGlobalVariableOperandVariableIndex = 11; + } // anonymous namespace namespace spvtools { @@ -153,6 +158,8 @@ Instruction* IRContext::KillInst(Instruction* inst) { KillNamesAndDecorates(inst); + KillOperandFromDebugInstructions(inst); + if (AreAnalysesValid(kAnalysisDefUse)) { get_def_use_mgr()->ClearInst(inst); } @@ -265,7 +272,7 @@ bool IRContext::ReplaceAllUsesWithPredicate( bool IRContext::IsConsistent() { #ifndef SPIRV_CHECK_CONTEXT return true; -#endif +#else if (AreAnalysesValid(kAnalysisDefUse)) { analysis::DefUseManager new_def_use(module()); if (*get_def_use_mgr() != new_def_use) { @@ -317,6 +324,7 @@ bool IRContext::IsConsistent() { } } return true; +#endif } void IRContext::ForgetUses(Instruction* inst) { @@ -365,6 +373,61 @@ 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(); + // Kill id of OpFunction from DebugFunction. + if (opcode == SpvOpFunction) { + 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] = GetOpenCL100DebugInfoNone()->result_id(); + } + } + } + // Kill id of OpVariable for global variable from DebugGlobalVariable. + if (opcode == SpvOpVariable || IsConstantInst(opcode)) { + for (auto it = module()->ext_inst_debuginfo_begin(); + it != module()->ext_inst_debuginfo_end(); ++it) { + if (it->GetOpenCL100DebugOpcode() != + OpenCLDebugInfo100DebugGlobalVariable) + continue; + auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex); + if (operand.words[0] == id) { + operand.words[0] = GetOpenCL100DebugInfoNone()->result_id(); + } + } + } + // Notice that we do not need anythings to do for local variables. + // DebugLocalVariable does not have an OpVariable operand. Instead, + // DebugDeclare/DebugValue has an OpVariable operand for a local + // variable. The function inlining pass handles it properly. +} + void IRContext::AddCombinatorsForCapability(uint32_t capability) { if (capability == SpvCapabilityShader) { combinator_ops_[0].insert({SpvOpNop, diff --git a/3rdparty/spirv-tools/source/opt/ir_context.h b/3rdparty/spirv-tools/source/opt/ir_context.h index 723a2bbb6..b275ae4ac 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.h +++ b/3rdparty/spirv-tools/source/opt/ir_context.h @@ -102,7 +102,8 @@ class IRContext { id_to_name_(nullptr), max_id_bound_(kDefaultMaxIdBound), preserve_bindings_(false), - preserve_spec_constants_(false) { + preserve_spec_constants_(false), + debug_info_none_inst_(nullptr) { SetContextMessageConsumer(syntax_context_, consumer_); module_->SetContext(this); } @@ -119,7 +120,8 @@ class IRContext { id_to_name_(nullptr), max_id_bound_(kDefaultMaxIdBound), preserve_bindings_(false), - preserve_spec_constants_(false) { + preserve_spec_constants_(false), + debug_info_none_inst_(nullptr) { SetContextMessageConsumer(syntax_context_, consumer_); module_->SetContext(this); InitializeCombinators(); @@ -426,6 +428,9 @@ class IRContext { // Kill all name and decorate ops targeting the result id of |inst|. void KillNamesAndDecorates(Instruction* inst); + // Change operands of debug instruction to DebugInfoNone. + void KillOperandFromDebugInstructions(Instruction* inst); + // Returns the next unique id for use by an instruction. inline uint32_t TakeNextUniqueId() { assert(unique_id_ != std::numeric_limits::max()); @@ -705,6 +710,9 @@ 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_; @@ -798,6 +806,10 @@ 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/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index 0a937e857..f11dc346f 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -498,7 +498,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { } else if (pass_name == "legalize-vector-shuffle") { RegisterPass(CreateLegalizeVectorShufflePass()); } else if (pass_name == "split-invalid-unreachable") { - RegisterPass(CreateLegalizeVectorShufflePass()); + RegisterPass(CreateSplitInvalidUnreachablePass()); } else if (pass_name == "decompose-initialized-variables") { RegisterPass(CreateDecomposeInitializedVariablesPass()); } else if (pass_name == "graphics-robust-access") { diff --git a/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.cpp b/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.cpp index b16322c1f..57fc49c1c 100644 --- a/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.cpp +++ b/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.cpp @@ -85,9 +85,14 @@ void StructuredCFGAnalysis::AddBlocksInFunction(Function* func) { if (merge_inst->opcode() == SpvOpLoopMerge) { new_state.cinfo.containing_loop = block->id(); new_state.cinfo.containing_switch = 0; - new_state.cinfo.in_continue = false; new_state.continue_node = merge_inst->GetSingleWordInOperand(kContinueNodeIndex); + if (block->id() == new_state.continue_node) { + new_state.cinfo.in_continue = true; + bb_to_construct_[block->id()].in_continue = true; + } else { + new_state.cinfo.in_continue = false; + } } else { new_state.cinfo.containing_loop = state.back().cinfo.containing_loop; new_state.cinfo.in_continue = state.back().cinfo.in_continue; diff --git a/3rdparty/spirv-tools/source/opt/type_manager.h b/3rdparty/spirv-tools/source/opt/type_manager.h index 8fcf8aa63..ce9d83d41 100644 --- a/3rdparty/spirv-tools/source/opt/type_manager.h +++ b/3rdparty/spirv-tools/source/opt/type_manager.h @@ -194,6 +194,13 @@ class TypeManager { uint32_t GetBoolTypeId() { return GetTypeInstruction(GetBoolType()); } + Type* GetVoidType() { + Void void_type; + return GetRegisteredType(&void_type); + } + + uint32_t GetVoidTypeId() { return GetTypeInstruction(GetVoidType()); } + private: using TypeToIdMap = std::unordered_map; diff --git a/3rdparty/spirv-tools/source/val/validate_cfg.cpp b/3rdparty/spirv-tools/source/val/validate_cfg.cpp index 1c279f654..1e33e5105 100644 --- a/3rdparty/spirv-tools/source/val/validate_cfg.cpp +++ b/3rdparty/spirv-tools/source/val/validate_cfg.cpp @@ -1090,8 +1090,9 @@ spv_result_t CfgPass(ValidationState_t& _, const Instruction* inst) { return _.diag(SPV_ERROR_INVALID_CFG, inst) << "OpReturn can only be called from a function with void " << "return type."; + _.current_function().RegisterBlockEnd(std::vector(), opcode); + break; } - // Fallthrough. case SpvOpKill: case SpvOpReturnValue: case SpvOpUnreachable: