Browse Source

Updated spirv-tools.

Бранимир Караџић 4 years ago
parent
commit
22bb919338
20 changed files with 186 additions and 42 deletions
  1. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  2. 1 1
      3rdparty/spirv-tools/include/generated/core.insts-unified1.inc
  3. 2 1
      3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc
  4. 30 0
      3rdparty/spirv-tools/source/opt/constants.cpp
  5. 13 4
      3rdparty/spirv-tools/source/opt/constants.h
  6. 11 3
      3rdparty/spirv-tools/source/opt/eliminate_dead_functions_util.cpp
  7. 89 7
      3rdparty/spirv-tools/source/opt/folding_rules.cpp
  8. 3 2
      3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp
  9. 4 8
      3rdparty/spirv-tools/source/opt/ir_context.cpp
  10. 4 2
      3rdparty/spirv-tools/source/opt/ir_context.h
  11. 3 0
      3rdparty/spirv-tools/source/opt/loop_unroller.cpp
  12. 3 0
      3rdparty/spirv-tools/source/reduce/change_operand_reduction_opportunity.cpp
  13. 1 0
      3rdparty/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.cpp
  14. 4 7
      3rdparty/spirv-tools/source/reduce/remove_block_reduction_opportunity.cpp
  15. 3 1
      3rdparty/spirv-tools/source/reduce/remove_block_reduction_opportunity.h
  16. 2 2
      3rdparty/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.cpp
  17. 2 2
      3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity.cpp
  18. 2 0
      3rdparty/spirv-tools/source/reduce/remove_struct_member_reduction_opportunity.cpp
  19. 2 0
      3rdparty/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.cpp
  20. 6 1
      3rdparty/spirv-tools/source/val/construct.cpp

+ 1 - 1
3rdparty/spirv-tools/include/generated/build-version.inc

@@ -1 +1 @@
-"v2021.0-dev", "SPIRV-Tools v2021.0-dev a176685a2c84eb6c09ec716962a43bda10d74d3d"
+"v2021.2-dev", "SPIRV-Tools v2021.2-dev 3b87b65d18deee5705410438aff0ee5a7c72f307"

+ 1 - 1
3rdparty/spirv-tools/include/generated/core.insts-unified1.inc

@@ -666,7 +666,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
   {"RayQueryGetIntersectionObjectToWorldKHR", SpvOpRayQueryGetIntersectionObjectToWorldKHR, 1, pygen_variable_caps_RayQueryKHR, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_KHR_ray_query, 0xffffffffu, 0xffffffffu},
   {"RayQueryGetIntersectionWorldToObjectKHR", SpvOpRayQueryGetIntersectionWorldToObjectKHR, 1, pygen_variable_caps_RayQueryKHR, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_KHR_ray_query, 0xffffffffu, 0xffffffffu},
   {"AtomicFAddEXT", SpvOpAtomicFAddEXT, 2, pygen_variable_caps_AtomicFloat32AddEXTAtomicFloat64AddEXT, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float_add, 0xffffffffu, 0xffffffffu},
-  {"TypeBufferSurfaceINTEL", SpvOpTypeBufferSurfaceINTEL, 1, pygen_variable_caps_VectorComputeINTEL, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
+  {"TypeBufferSurfaceINTEL", SpvOpTypeBufferSurfaceINTEL, 1, pygen_variable_caps_VectorComputeINTEL, 2, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ACCESS_QUALIFIER}, 1, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"TypeStructContinuedINTEL", SpvOpTypeStructContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"ConstantCompositeContinuedINTEL", SpvOpConstantCompositeContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"SpecConstantCompositeContinuedINTEL", SpvOpSpecConstantCompositeContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}

+ 2 - 1
3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc

@@ -89,6 +89,7 @@ static const SpvCapability pygen_variable_caps_Shader[] = {SpvCapabilityShader};
 static const SpvCapability pygen_variable_caps_ShaderImageCubeArray[] = {SpvCapabilityShader, SpvCapabilityImageCubeArray};
 static const SpvCapability pygen_variable_caps_ShaderKernel[] = {SpvCapabilityShader, SpvCapabilityKernel};
 static const SpvCapability pygen_variable_caps_ShaderKernelImageMSArray[] = {SpvCapabilityShader, SpvCapabilityKernel, SpvCapabilityImageMSArray};
+static const SpvCapability pygen_variable_caps_ShaderVectorComputeINTEL[] = {SpvCapabilityShader, SpvCapabilityVectorComputeINTEL};
 static const SpvCapability pygen_variable_caps_ShaderNonUniform[] = {SpvCapabilityShaderNonUniform};
 static const SpvCapability pygen_variable_caps_ShaderSMBuiltinsNV[] = {SpvCapabilityShaderSMBuiltinsNV};
 static const SpvCapability pygen_variable_caps_ShaderStereoViewNV[] = {SpvCapabilityShaderStereoViewNV};
@@ -449,7 +450,7 @@ static const spv_operand_desc_t pygen_variable_StorageClassEntries[] = {
   {"Output", 3, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
   {"Workgroup", 4, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
   {"CrossWorkgroup", 5, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
-  {"Private", 6, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
+  {"Private", 6, 2, pygen_variable_caps_ShaderVectorComputeINTEL, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
   {"Function", 7, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
   {"Generic", 8, 1, pygen_variable_caps_GenericPointer, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
   {"PushConstant", 9, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},

+ 30 - 0
3rdparty/spirv-tools/source/opt/constants.cpp

@@ -389,6 +389,36 @@ const Constant* ConstantManager::GetConstant(
   return cst ? RegisterConstant(std::move(cst)) : nullptr;
 }
 
+const Constant* ConstantManager::GetNumericVectorConstantWithWords(
+    const Vector* type, const std::vector<uint32_t>& literal_words) {
+  const auto* element_type = type->element_type();
+  uint32_t words_per_element = 0;
+  if (const auto* float_type = element_type->AsFloat())
+    words_per_element = float_type->width() / 32;
+  else if (const auto* int_type = element_type->AsInteger())
+    words_per_element = int_type->width() / 32;
+
+  if (words_per_element != 1 && words_per_element != 2) return nullptr;
+
+  if (words_per_element * type->element_count() !=
+      static_cast<uint32_t>(literal_words.size())) {
+    return nullptr;
+  }
+
+  std::vector<uint32_t> element_ids;
+  for (uint32_t i = 0; i < type->element_count(); ++i) {
+    auto first_word = literal_words.begin() + (words_per_element * i);
+    std::vector<uint32_t> const_data(first_word,
+                                     first_word + words_per_element);
+    const analysis::Constant* element_constant =
+        GetConstant(element_type, const_data);
+    auto element_id = GetDefiningInstruction(element_constant)->result_id();
+    element_ids.push_back(element_id);
+  }
+
+  return GetConstant(type, element_ids);
+}
+
 uint32_t ConstantManager::GetFloatConst(float val) {
   Type* float_type = context()->get_type_mgr()->GetFloatType();
   utils::FloatProxy<float> v(val);

+ 13 - 4
3rdparty/spirv-tools/source/opt/constants.h

@@ -506,10 +506,11 @@ class ConstantManager {
   IRContext* context() const { return ctx_; }
 
   // Gets or creates a unique Constant instance of type |type| and a vector of
-  // constant defining words |words|. If a Constant instance existed already in
-  // the constant pool, it returns a pointer to it.  Otherwise, it creates one
-  // using CreateConstant. If a new Constant instance cannot be created, it
-  // returns nullptr.
+  // constant defining words or ids for elements of Vector type
+  // |literal_words_or_ids|. If a Constant instance existed already in the
+  // constant pool, it returns a pointer to it. Otherwise, it creates one using
+  // CreateConstant. If a new Constant instance cannot be created, it returns
+  // nullptr.
   const Constant* GetConstant(
       const Type* type, const std::vector<uint32_t>& literal_words_or_ids);
 
@@ -519,6 +520,14 @@ class ConstantManager {
                                                    literal_words_or_ids.end()));
   }
 
+  // Gets or creates a unique Constant instance of Vector type |type| with
+  // numeric elements and a vector of constant defining words |literal_words|.
+  // If a Constant instance existed already in the constant pool, it returns a
+  // pointer to it. Otherwise, it creates one using CreateConstant. If a new
+  // Constant instance cannot be created, it returns nullptr.
+  const Constant* GetNumericVectorConstantWithWords(
+      const Vector* type, const std::vector<uint32_t>& literal_words);
+
   // Gets or creates a Constant instance to hold the constant value of the given
   // instruction. It returns a pointer to a Constant instance or nullptr if it
   // could not create the constant.

+ 11 - 3
3rdparty/spirv-tools/source/opt/eliminate_dead_functions_util.cpp

@@ -23,9 +23,11 @@ Module::iterator EliminateFunction(IRContext* context,
                                    Module::iterator* func_iter) {
   bool first_func = *func_iter == context->module()->begin();
   bool seen_func_end = false;
+  std::unordered_set<Instruction*> to_kill;
   (*func_iter)
       ->ForEachInst(
-          [context, first_func, func_iter, &seen_func_end](Instruction* inst) {
+          [context, first_func, func_iter, &seen_func_end,
+           &to_kill](Instruction* inst) {
             if (inst->opcode() == SpvOpFunctionEnd) {
               seen_func_end = true;
             }
@@ -33,6 +35,7 @@ Module::iterator EliminateFunction(IRContext* context,
             // global values if this is the first function.
             if (seen_func_end && inst->opcode() == SpvOpExtInst) {
               assert(inst->IsNonSemanticInstruction());
+              if (to_kill.find(inst) != to_kill.end()) return;
               std::unique_ptr<Instruction> clone(inst->Clone(context));
               context->ForgetUses(inst);
               context->AnalyzeDefUse(clone.get());
@@ -44,12 +47,17 @@ Module::iterator EliminateFunction(IRContext* context,
                 prev_func_iter->AddNonSemanticInstruction(std::move(clone));
               }
               inst->ToNop();
-            } else {
-              context->KillNonSemanticInfo(inst);
+            } else if (to_kill.find(inst) == to_kill.end()) {
+              context->CollectNonSemanticTree(inst, &to_kill);
               context->KillInst(inst);
             }
           },
           true, true);
+
+  for (auto* dead : to_kill) {
+    context->KillInst(dead);
+  }
+
   return func_iter->Erase();
 }
 

+ 89 - 7
3rdparty/spirv-tools/source/opt/folding_rules.cpp

@@ -124,6 +124,66 @@ Instruction* NonConstInput(IRContext* context, const analysis::Constant* c,
       inst->GetSingleWordInOperand(in_op));
 }
 
+std::vector<uint32_t> ExtractInts(uint64_t val) {
+  std::vector<uint32_t> words;
+  words.push_back(static_cast<uint32_t>(val));
+  words.push_back(static_cast<uint32_t>(val >> 32));
+  return words;
+}
+
+std::vector<uint32_t> GetWordsFromScalarIntConstant(
+    const analysis::IntConstant* c) {
+  assert(c != nullptr);
+  uint32_t width = c->type()->AsInteger()->width();
+  assert(width == 32 || width == 64);
+  if (width == 64) {
+    uint64_t uval = static_cast<uint64_t>(c->GetU64());
+    return ExtractInts(uval);
+  }
+  return {c->GetU32()};
+}
+
+std::vector<uint32_t> GetWordsFromScalarFloatConstant(
+    const analysis::FloatConstant* c) {
+  assert(c != nullptr);
+  uint32_t width = c->type()->AsFloat()->width();
+  assert(width == 32 || width == 64);
+  if (width == 64) {
+    utils::FloatProxy<double> result(c->GetDouble());
+    return result.GetWords();
+  }
+  utils::FloatProxy<float> result(c->GetFloat());
+  return result.GetWords();
+}
+
+std::vector<uint32_t> GetWordsFromNumericScalarOrVectorConstant(
+    analysis::ConstantManager* const_mgr, const analysis::Constant* c) {
+  if (const auto* float_constant = c->AsFloatConstant()) {
+    return GetWordsFromScalarFloatConstant(float_constant);
+  } else if (const auto* int_constant = c->AsIntConstant()) {
+    return GetWordsFromScalarIntConstant(int_constant);
+  } else if (const auto* vec_constant = c->AsVectorConstant()) {
+    std::vector<uint32_t> words;
+    for (const auto* comp : vec_constant->GetComponents()) {
+      auto comp_in_words =
+          GetWordsFromNumericScalarOrVectorConstant(const_mgr, comp);
+      words.insert(words.end(), comp_in_words.begin(), comp_in_words.end());
+    }
+    return words;
+  }
+  return {};
+}
+
+const analysis::Constant* ConvertWordsToNumericScalarOrVectorConstant(
+    analysis::ConstantManager* const_mgr, const std::vector<uint32_t>& words,
+    const analysis::Type* type) {
+  if (type->AsInteger() || type->AsFloat())
+    return const_mgr->GetConstant(type, words);
+  if (const auto* vec_type = type->AsVector())
+    return const_mgr->GetNumericVectorConstantWithWords(vec_type, words);
+  return nullptr;
+}
+
 // Returns the negation of |c|. |c| must be a 32 or 64 bit floating point
 // constant.
 uint32_t NegateFloatingPointConstant(analysis::ConstantManager* const_mgr,
@@ -146,13 +206,6 @@ uint32_t NegateFloatingPointConstant(analysis::ConstantManager* const_mgr,
   return const_mgr->GetDefiningInstruction(negated_const)->result_id();
 }
 
-std::vector<uint32_t> ExtractInts(uint64_t val) {
-  std::vector<uint32_t> words;
-  words.push_back(static_cast<uint32_t>(val));
-  words.push_back(static_cast<uint32_t>(val >> 32));
-  return words;
-}
-
 // Negates the integer constant |c|. Returns the id of the defining instruction.
 uint32_t NegateIntegerConstant(analysis::ConstantManager* const_mgr,
                                const analysis::Constant* c) {
@@ -1796,6 +1849,33 @@ FoldingRule RedundantPhi() {
   };
 }
 
+FoldingRule BitCastScalarOrVector() {
+  return [](IRContext* context, Instruction* inst,
+            const std::vector<const analysis::Constant*>& constants) {
+    assert(inst->opcode() == SpvOpBitcast && constants.size() == 1);
+    if (constants[0] == nullptr) return false;
+
+    const analysis::Type* type =
+        context->get_type_mgr()->GetType(inst->type_id());
+    if (HasFloatingPoint(type) && !inst->IsFloatingPointFoldingAllowed())
+      return false;
+
+    analysis::ConstantManager* const_mgr = context->get_constant_mgr();
+    std::vector<uint32_t> words =
+        GetWordsFromNumericScalarOrVectorConstant(const_mgr, constants[0]);
+    if (words.size() == 0) return false;
+
+    const analysis::Constant* bitcasted_constant =
+        ConvertWordsToNumericScalarOrVectorConstant(const_mgr, words, type);
+    auto new_feeder_id =
+        const_mgr->GetDefiningInstruction(bitcasted_constant, inst->type_id())
+            ->result_id();
+    inst->SetOpcode(SpvOpCopyObject);
+    inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {new_feeder_id}}});
+    return true;
+  };
+}
+
 FoldingRule RedundantSelect() {
   // An OpSelect instruction where both values are the same or the condition is
   // constant can be replaced by one of the values
@@ -2423,6 +2503,8 @@ void FoldingRules::AddFoldingRules() {
   // Note that the order in which rules are added to the list matters. If a rule
   // applies to the instruction, the rest of the rules will not be attempted.
   // Take that into consideration.
+  rules_[SpvOpBitcast].push_back(BitCastScalarOrVector());
+
   rules_[SpvOpCompositeConstruct].push_back(CompositeExtractFeedingConstruct);
 
   rules_[SpvOpCompositeExtract].push_back(InsertFeedingExtract());

+ 3 - 2
3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp

@@ -272,10 +272,11 @@ void GraphicsRobustAccessPass::ClampIndicesForAccessChain(
 
   // Replaces one of the OpAccessChain index operands with a new value.
   // Updates def-use analysis.
-  auto replace_index = [&inst, def_use_mgr](uint32_t operand_index,
-                                            Instruction* new_value) {
+  auto replace_index = [this, &inst, def_use_mgr](uint32_t operand_index,
+                                                  Instruction* new_value) {
     inst.SetOperand(operand_index, {new_value->result_id()});
     def_use_mgr->AnalyzeInstUse(&inst);
+    module_status_.modified = true;
     return SPV_SUCCESS;
   };
 

+ 4 - 8
3rdparty/spirv-tools/source/opt/ir_context.cpp

@@ -214,10 +214,10 @@ Instruction* IRContext::KillInst(Instruction* inst) {
   return next_instruction;
 }
 
-void IRContext::KillNonSemanticInfo(Instruction* inst) {
+void IRContext::CollectNonSemanticTree(
+    Instruction* inst, std::unordered_set<Instruction*>* to_kill) {
   if (!inst->HasResultId()) return;
   std::vector<Instruction*> work_list;
-  std::vector<Instruction*> to_kill;
   std::unordered_set<Instruction*> seen;
   work_list.push_back(inst);
 
@@ -225,17 +225,13 @@ void IRContext::KillNonSemanticInfo(Instruction* inst) {
     auto* i = work_list.back();
     work_list.pop_back();
     get_def_use_mgr()->ForEachUser(
-        i, [&work_list, &to_kill, &seen](Instruction* user) {
+        i, [&work_list, to_kill, &seen](Instruction* user) {
           if (user->IsNonSemanticInstruction() && seen.insert(user).second) {
             work_list.push_back(user);
-            to_kill.push_back(user);
+            to_kill->insert(user);
           }
         });
   }
-
-  for (auto* dead : to_kill) {
-    KillInst(dead);
-  }
 }
 
 bool IRContext::KillDef(uint32_t id) {

+ 4 - 2
3rdparty/spirv-tools/source/opt/ir_context.h

@@ -403,8 +403,10 @@ class IRContext {
   // instruction exists.
   Instruction* KillInst(Instruction* inst);
 
-  // Removes the non-semantic instruction tree that uses |inst|'s result id.
-  void KillNonSemanticInfo(Instruction* inst);
+  // Collects the non-semantic instruction tree that uses |inst|'s result id
+  // to be killed later.
+  void CollectNonSemanticTree(Instruction* inst,
+                              std::unordered_set<Instruction*>* to_kill);
 
   // Returns true if all of the given analyses are valid.
   bool AreAnalysesValid(Analysis set) { return (set & valid_analyses_) == set; }

+ 3 - 0
3rdparty/spirv-tools/source/opt/loop_unroller.cpp

@@ -797,6 +797,9 @@ void LoopUnrollerUtilsImpl::CloseUnrolledLoop(Loop* loop) {
   for (BasicBlock* block : loop_blocks_inorder_) {
     RemapOperands(block);
   }
+  for (auto& block_itr : blocks_to_add_) {
+    RemapOperands(block_itr.get());
+  }
 
   // Rewrite the last phis, since they may still reference the original phi.
   for (Instruction* last_phi : state_.previous_phis_) {

+ 3 - 0
3rdparty/spirv-tools/source/reduce/change_operand_reduction_opportunity.cpp

@@ -14,6 +14,8 @@
 
 #include "source/reduce/change_operand_reduction_opportunity.h"
 
+#include "source/opt/ir_context.h"
+
 namespace spvtools {
 namespace reduce {
 
@@ -26,6 +28,7 @@ bool ChangeOperandReductionOpportunity::PreconditionHolds() {
 
 void ChangeOperandReductionOpportunity::Apply() {
   inst_->SetOperand(operand_index_, {new_id_});
+  inst_->context()->get_def_use_mgr()->UpdateDefUse(inst_);
 }
 
 }  // namespace reduce

+ 1 - 0
3rdparty/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.cpp

@@ -35,6 +35,7 @@ void ChangeOperandToUndefReductionOpportunity::Apply() {
   assert(operand_type_id);
   auto undef_id = FindOrCreateGlobalUndef(context_, operand_type_id);
   inst_->SetOperand(operand_index_, {undef_id});
+  context_->InvalidateAnalyses(opt::IRContext::kAnalysisDefUse);
 }
 
 }  // namespace reduce

+ 4 - 7
3rdparty/spirv-tools/source/reduce/remove_block_reduction_opportunity.cpp

@@ -20,12 +20,11 @@ namespace spvtools {
 namespace reduce {
 
 RemoveBlockReductionOpportunity::RemoveBlockReductionOpportunity(
-    opt::Function* function, opt::BasicBlock* block)
-    : function_(function), block_(block) {
+    opt::IRContext* context, opt::Function* function, opt::BasicBlock* block)
+    : context_(context), function_(function), block_(block) {
   // precondition:
   assert(block_->begin() != block_->end() &&
-         block_->begin()->context()->get_def_use_mgr()->NumUsers(
-             block_->id()) == 0 &&
+         context_->get_def_use_mgr()->NumUsers(block_->id()) == 0 &&
          "RemoveBlockReductionOpportunity block must have 0 references");
 }
 
@@ -38,10 +37,8 @@ void RemoveBlockReductionOpportunity::Apply() {
   // We need an iterator pointing to the block, hence the loop.
   for (auto bi = function_->begin(); bi != function_->end(); ++bi) {
     if (bi->id() == block_->id()) {
-      bi->KillAllInsts(true);
       bi.Erase();
-      // Block removal changes the function, but we don't use analyses, so no
-      // need to invalidate them.
+      context_->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
       return;
     }
   }

+ 3 - 1
3rdparty/spirv-tools/source/reduce/remove_block_reduction_opportunity.h

@@ -27,7 +27,8 @@ namespace reduce {
 class RemoveBlockReductionOpportunity : public ReductionOpportunity {
  public:
   // Creates the opportunity to remove |block| in |function| in |context|.
-  RemoveBlockReductionOpportunity(opt::Function* function,
+  RemoveBlockReductionOpportunity(opt::IRContext* context,
+                                  opt::Function* function,
                                   opt::BasicBlock* block);
 
   bool PreconditionHolds() override;
@@ -36,6 +37,7 @@ class RemoveBlockReductionOpportunity : public ReductionOpportunity {
   void Apply() override;
 
  private:
+  opt::IRContext* context_;
   opt::Function* function_;
   opt::BasicBlock* block_;
 };

+ 2 - 2
3rdparty/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.cpp

@@ -32,8 +32,8 @@ RemoveBlockReductionOpportunityFinder::GetAvailableOpportunities(
   for (auto* function : GetTargetFunctions(context, target_function)) {
     for (auto bi = function->begin(); bi != function->end(); ++bi) {
       if (IsBlockValidOpportunity(context, function, &bi)) {
-        result.push_back(
-            MakeUnique<RemoveBlockReductionOpportunity>(function, &*bi));
+        result.push_back(MakeUnique<RemoveBlockReductionOpportunity>(
+            context, function, &*bi));
       }
     }
   }

+ 2 - 2
3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity.cpp

@@ -29,8 +29,8 @@ void RemoveFunctionReductionOpportunity::Apply() {
   for (opt::Module::iterator function_it = context_->module()->begin();
        function_it != context_->module()->end(); ++function_it) {
     if (&*function_it == function_) {
-      opt::eliminatedeadfunctionsutil::EliminateFunction(context_,
-                                                         &function_it);
+      function_it.Erase();
+      context_->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
       return;
     }
   }

+ 2 - 0
3rdparty/spirv-tools/source/reduce/remove_struct_member_reduction_opportunity.cpp

@@ -129,6 +129,8 @@ void RemoveStructMemberReductionOpportunity::Apply() {
 
   // Remove the member from the struct type.
   struct_type_->RemoveInOperand(member_index_);
+
+  context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
 }
 
 void RemoveStructMemberReductionOpportunity::AdjustAccessedIndices(

+ 2 - 0
3rdparty/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.cpp

@@ -51,6 +51,8 @@ void SimpleConditionalBranchToBranchReductionOpportunity::Apply() {
       {{SPV_OPERAND_TYPE_ID,
         {conditional_branch_instruction_->GetSingleWordInOperand(
             kTrueBranchOperandIndex)}}});
+  conditional_branch_instruction_->context()->InvalidateAnalysesExceptFor(
+      opt::IRContext::kAnalysisNone);
 }
 
 }  // namespace reduce

+ 6 - 1
3rdparty/spirv-tools/source/val/construct.cpp

@@ -78,7 +78,12 @@ Construct::ConstructBlockSet Construct::blocks(Function* function) const {
   ConstructBlockSet construct_blocks;
   std::unordered_set<BasicBlock*> corresponding_headers;
   for (auto& other : corresponding_constructs()) {
-    corresponding_headers.insert(other->entry_block());
+    // The corresponding header can be the same block as this construct's
+    // header for loops with no loop construct. In those cases, don't add the
+    // loop header as it prevents finding any blocks in the construct.
+    if (type() != ConstructType::kContinue || other->entry_block() != header) {
+      corresponding_headers.insert(other->entry_block());
+    }
   }
   std::vector<BasicBlock*> stack;
   stack.push_back(const_cast<BasicBlock*>(header));