Sfoglia il codice sorgente

Updated spirv-tools.

Бранимир Караџић 5 anni fa
parent
commit
e262d3cf93

+ 1 - 1
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"

+ 6 - 4
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;
           }

+ 1 - 1
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<uint32_t, uint32_t>* 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<uint32_t, uint32_t>* original_id_to_donated_id);

+ 6 - 0
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;

+ 28 - 7
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<uint32_t, uint32_t> 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;
     }
   }

+ 3 - 0
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(

+ 28 - 2
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<uint32_t> 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(

+ 7 - 0
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

+ 8 - 0
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

+ 8 - 5
3rdparty/spirv-tools/source/opt/function.cpp

@@ -84,9 +84,12 @@ bool Function::WhileEachInst(const std::function<bool(Instruction*)>& 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<bool(const Instruction*)>& f,
   }
 
   for (const auto& di : debug_insts_in_header_) {
-    if (!di.WhileEachInst(f, run_on_debug_line_insts)) {
+    if (!static_cast<const Instruction*>(&di)->WhileEachInst(
+            f, run_on_debug_line_insts))
       return false;
-    }
   }
 
   for (const auto& bb : blocks_) {

+ 4 - 0
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(

+ 36 - 5
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();

+ 9 - 4
3rdparty/spirv-tools/source/opt/instruction.h

@@ -22,14 +22,14 @@
 #include <utility>
 #include <vector>
 
+#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 "source/latest_version_glsl_std_450_header.h"
-#include "source/latest_version_spirv_header.h"
-#include "source/opt/reflect.h"
 #include "spirv-tools/libspirv.h"
 
 const uint32_t kNoDebugScope = 0;
@@ -496,6 +496,11 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
   // 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;

+ 64 - 1
3rdparty/spirv-tools/source/opt/ir_context.cpp

@@ -16,6 +16,7 @@
 
 #include <cstring>
 
+#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<Instruction> 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<uint32_t>(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,

+ 14 - 2
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<uint32_t>::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,

+ 1 - 1
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") {

+ 6 - 1
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;

+ 7 - 0
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<const Type*, uint32_t, HashTypePointer,
                                          CompareTypePointers>;

+ 2 - 1
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<uint32_t>(), opcode);
+      break;
     }
-    // Fallthrough.
     case SpvOpKill:
     case SpvOpReturnValue:
     case SpvOpUnreachable: