Procházet zdrojové kódy

Updated spirv-tools.

Бранимир Караџић před 5 roky
rodič
revize
bc166c21b5

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

+ 86 - 114
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<Operation, OperationHash, OperationEquals>;
+
   // 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<Operation, OperationHash, OperationEquals>>
+  std::unordered_map<const protobufs::DataDescriptor*, OperationSet>
       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<const protobufs::DataDescriptor*>& 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<Operation, OperationHash, OperationEquals>()});
+    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<Operation, OperationHash, OperationEquals>()});
+      id_equations_.insert({still_representative, OperationSet()});
     }
     auto still_representative_id_equations =
         id_equations_.find(still_representative);

+ 2 - 3
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()) {

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

+ 4 - 17
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);

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

+ 9 - 0
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;
 }
 

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

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

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

+ 208 - 0
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 <cassert>
+
+#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<Instruction> 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<uint32_t>(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<Instruction> 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<uint32_t>(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<Instruction> 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

+ 115 - 0
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 <unordered_map>
+
+#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<uint32_t, Instruction*> id_to_dbg_inst_;
+
+  // Mapping from function's ids to DebugFunction instructions whose
+  // operand is the function.
+  std::unordered_map<uint32_t, Instruction*> 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_

+ 2 - 2
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<BasicBlock> 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() {

+ 39 - 14
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;
 }
 

+ 26 - 6
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<Instruction> {
   // 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<Instruction> {
     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.

+ 12 - 23
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<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();
@@ -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();
       }
     }
   }

+ 26 - 12
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<bool(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<analysis::DebugInfoManager>(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<analysis::TypeManager> type_mgr_;
 
+  // Debug information manager for |module_|.
+  std::unique_ptr<analysis::DebugInfoManager> debug_info_mgr_;
+
   // A map from an id to its corresponding OpName and OpMemberName instructions.
   std::unique_ptr<std::multimap<uint32_t, Instruction*>> 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,

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

+ 1 - 1
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()