Browse Source

Updated spirv-tools.

Бранимир Караџић 5 years ago
parent
commit
28649aec87
34 changed files with 496 additions and 439 deletions
  1. 31 4
      3rdparty/spirv-tools/README.md
  2. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  3. 0 35
      3rdparty/spirv-tools/include/spirv-tools/instrument.hpp
  4. 2 5
      3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp
  5. 0 2
      3rdparty/spirv-tools/source/fuzz/CMakeLists.txt
  6. 0 11
      3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
  7. 29 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp
  8. 8 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h
  9. 7 2
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp
  10. 6 2
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp
  11. 6 1
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp
  12. 0 222
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp
  13. 0 46
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h
  14. 1 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp
  15. 69 17
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
  16. 5 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h
  17. 1 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_util.h
  18. 89 0
      3rdparty/spirv-tools/source/opt/debug_info_manager.cpp
  19. 54 0
      3rdparty/spirv-tools/source/opt/debug_info_manager.h
  20. 12 0
      3rdparty/spirv-tools/source/opt/function.cpp
  21. 5 0
      3rdparty/spirv-tools/source/opt/function.h
  22. 98 33
      3rdparty/spirv-tools/source/opt/inline_pass.cpp
  23. 17 8
      3rdparty/spirv-tools/source/opt/inline_pass.h
  24. 0 7
      3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h
  25. 0 4
      3rdparty/spirv-tools/source/opt/inst_buff_addr_check_pass.h
  26. 2 3
      3rdparty/spirv-tools/source/opt/inst_debug_printf_pass.h
  27. 13 1
      3rdparty/spirv-tools/source/opt/instruction.cpp
  28. 16 0
      3rdparty/spirv-tools/source/opt/instruction.h
  29. 0 8
      3rdparty/spirv-tools/source/opt/instrument_pass.cpp
  30. 1 15
      3rdparty/spirv-tools/source/opt/instrument_pass.h
  31. 5 0
      3rdparty/spirv-tools/source/opt/mem_pass.cpp
  32. 0 1
      3rdparty/spirv-tools/source/opt/merge_return_pass.cpp
  33. 17 11
      3rdparty/spirv-tools/source/opt/optimizer.cpp
  34. 1 0
      3rdparty/spirv-tools/source/val/validate_function.cpp

+ 31 - 4
3rdparty/spirv-tools/README.md

@@ -324,8 +324,7 @@ The script `utils/git-sync-deps` can be used to checkout and/or update the
 contents of the repos under `external/` instead of manually maintaining them.
 
 ### Build using CMake
-You can build The project using [CMake][cmake] to generate platform-specific
-build configurations.
+You can build the project using [CMake][cmake]:
 
 ```sh
 cd <spirv-dir>
@@ -333,8 +332,36 @@ mkdir build && cd build
 cmake [-G <platform-generator>] <spirv-dir>
 ```
 
-Once the build files have been generated, build using your preferred
-development environment.
+Once the build files have been generated, build using the appropriate build
+command (e.g. `ninja`, `make`, `msbuild`, etc.; this depends on the platform
+generator used above), or use your IDE, or use CMake to run the appropriate build
+command for you:
+
+```sh
+cmake --build . [--config Debug]  # runs `make` or `ninja` or `msbuild` etc.
+```
+
+#### Note about the fuzzer
+
+The SPIR-V fuzzer, `spirv-fuzz`, can only be built via CMake, and is disabled by
+default. To build it, clone protobuf and use the `SPIRV_BUILD_FUZZER` CMake
+option, like so:
+
+```sh
+# In <spirv-dir> (the SPIRV-Tools repo root):
+git clone https://github.com/protocolbuffers/protobuf external/protobuf
+pushd external/protobuf
+git checkout v3.7.1
+popd
+
+# In your build directory:
+cmake [-G <platform-generator>] <spirv-dir> -DSPIRV_BUILD_FUZZER=ON
+cmake --build . --config Debug
+```
+
+You can also add `-DSPIRV_ENABLE_LONG_FUZZER_TESTS=ON` to build additional
+fuzzer tests.
+
 
 ### Build using Bazel
 You can also use [Bazel](https://bazel.build/) to build the project.

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

@@ -1 +1 @@
-"v2020.3-dev", "SPIRV-Tools v2020.3-dev 8848e0dad1e2109f2c8d9e3cfb84ad016ce6f8cf"
+"v2020.3-dev", "SPIRV-Tools v2020.3-dev 2a43c86c2428dd427bb5c8dc62e57774d87952a8"

+ 0 - 35
3rdparty/spirv-tools/include/spirv-tools/instrument.hpp

@@ -35,10 +35,6 @@ namespace spvtools {
 // generated by InstrumentPass::GenDebugStreamWrite. This method is utilized
 // by InstBindlessCheckPass.
 //
-// kInst2* values support version 2 of the output record format and were used
-// for the transition to this format. These values have now been transferred
-// to the original kInst* values. The kInst2* values are therefore DEPRECATED.
-//
 // The first member of the debug output buffer contains the next available word
 // in the data stream to be written. Shaders will atomically read and update
 // this value so as not to overwrite each others records. This value must be
@@ -94,10 +90,6 @@ static const int kInstCompOutGlobalInvocationIdX = kInstCommonOutCnt;
 static const int kInstCompOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
 static const int kInstCompOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;
 
-// Compute Shader Output Record Offsets - Version 1 (DEPRECATED)
-static const int kInstCompOutGlobalInvocationId = kInstCommonOutCnt;
-static const int kInstCompOutUnused = kInstCommonOutCnt + 1;
-
 // Tessellation Control Shader Output Record Offsets
 static const int kInstTessCtlOutInvocationId = kInstCommonOutCnt;
 static const int kInstTessCtlOutPrimitiveId = kInstCommonOutCnt + 1;
@@ -108,10 +100,6 @@ static const int kInstTessEvalOutPrimitiveId = kInstCommonOutCnt;
 static const int kInstTessEvalOutTessCoordU = kInstCommonOutCnt + 1;
 static const int kInstTessEvalOutTessCoordV = kInstCommonOutCnt + 2;
 
-// Tessellation Shader Output Record Offsets - Version 1 (DEPRECATED)
-static const int kInstTessOutInvocationId = kInstCommonOutCnt;
-static const int kInstTessOutUnused = kInstCommonOutCnt + 1;
-
 // Geometry Shader Output Record Offsets
 static const int kInstGeomOutPrimitiveId = kInstCommonOutCnt;
 static const int kInstGeomOutInvocationId = kInstCommonOutCnt + 1;
@@ -124,14 +112,12 @@ static const int kInstRayTracingOutLaunchIdZ = kInstCommonOutCnt + 2;
 
 // Size of Common and Stage-specific Members
 static const int kInstStageOutCnt = kInstCommonOutCnt + 3;
-static const int kInst2StageOutCnt = kInstCommonOutCnt + 3;
 
 // Validation Error Code Offset
 //
 // This identifies the validation error. It also helps to identify
 // how many words follow in the record and their meaning.
 static const int kInstValidationOutError = kInstStageOutCnt;
-static const int kInst2ValidationOutError = kInst2StageOutCnt;
 
 // Validation-specific Output Record Offsets
 //
@@ -144,37 +130,19 @@ static const int kInstBindlessBoundsOutDescIndex = kInstStageOutCnt + 1;
 static const int kInstBindlessBoundsOutDescBound = kInstStageOutCnt + 2;
 static const int kInstBindlessBoundsOutCnt = kInstStageOutCnt + 3;
 
-static const int kInst2BindlessBoundsOutDescIndex = kInst2StageOutCnt + 1;
-static const int kInst2BindlessBoundsOutDescBound = kInst2StageOutCnt + 2;
-static const int kInst2BindlessBoundsOutCnt = kInst2StageOutCnt + 3;
-
 // A bindless uninitialized error will output the index.
 static const int kInstBindlessUninitOutDescIndex = kInstStageOutCnt + 1;
 static const int kInstBindlessUninitOutUnused = kInstStageOutCnt + 2;
 static const int kInstBindlessUninitOutCnt = kInstStageOutCnt + 3;
 
-static const int kInst2BindlessUninitOutDescIndex = kInst2StageOutCnt + 1;
-static const int kInst2BindlessUninitOutUnused = kInst2StageOutCnt + 2;
-static const int kInst2BindlessUninitOutCnt = kInst2StageOutCnt + 3;
-
 // A buffer address unalloc error will output the 64-bit pointer in
 // two 32-bit pieces, lower bits first.
 static const int kInstBuffAddrUnallocOutDescPtrLo = kInstStageOutCnt + 1;
 static const int kInstBuffAddrUnallocOutDescPtrHi = kInstStageOutCnt + 2;
 static const int kInstBuffAddrUnallocOutCnt = kInstStageOutCnt + 3;
 
-static const int kInst2BuffAddrUnallocOutDescPtrLo = kInst2StageOutCnt + 1;
-static const int kInst2BuffAddrUnallocOutDescPtrHi = kInst2StageOutCnt + 2;
-static const int kInst2BuffAddrUnallocOutCnt = kInst2StageOutCnt + 3;
-
-// DEPRECATED
-static const int kInstBindlessOutDescIndex = kInstStageOutCnt + 1;
-static const int kInstBindlessOutDescBound = kInstStageOutCnt + 2;
-static const int kInstBindlessOutCnt = kInstStageOutCnt + 3;
-
 // Maximum Output Record Member Count
 static const int kInstMaxOutCnt = kInstStageOutCnt + 3;
-static const int kInst2MaxOutCnt = kInst2StageOutCnt + 3;
 
 // Validation Error Codes
 //
@@ -223,9 +191,6 @@ static const int kDebugOutputPrintfStream = 3;
 // Data[ i + Data[ b + Data[ s + Data[ kDebugInputBindlessInitOffset ] ] ] ]
 static const int kDebugInputBindlessInitOffset = 0;
 
-// DEPRECATED
-static const int kDebugInputBindlessOffsetReserved = 0;
-
 // At offset kDebugInputBindlessOffsetLengths is some number of uints which
 // provide the bindless length data. More specifically, the number of
 // descriptors at (set=s, binding=b) is:

+ 2 - 5
3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp

@@ -762,10 +762,9 @@ Optimizer::PassToken CreateCombineAccessChainsPass();
 // |input_length_enable| controls instrumentation of runtime descriptor array
 // references, and |input_init_enable| controls instrumentation of descriptor
 // initialization checking, both of which require input buffer support.
-// |version| specifies the buffer record format.
 Optimizer::PassToken CreateInstBindlessCheckPass(
     uint32_t desc_set, uint32_t shader_id, bool input_length_enable = false,
-    bool input_init_enable = false, uint32_t version = 2);
+    bool input_init_enable = false);
 
 // Create a pass to instrument physical buffer address checking
 // This pass instruments all physical buffer address references to check that
@@ -786,10 +785,8 @@ Optimizer::PassToken CreateInstBindlessCheckPass(
 // The instrumentation will read and write buffers in debug
 // descriptor set |desc_set|. It will write |shader_id| in each output record
 // to identify the shader module which generated the record.
-// |version| specifies the output buffer record format.
 Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
-                                                 uint32_t shader_id,
-                                                 uint32_t version = 2);
+                                                 uint32_t shader_id);
 
 // Create a pass to instrument OpDebugPrintf instructions.
 // This pass replaces all OpDebugPrintf instructions with instructions to write

+ 0 - 2
3rdparty/spirv-tools/source/fuzz/CMakeLists.txt

@@ -49,7 +49,6 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_add_local_variables.h
         fuzzer_pass_add_no_contraction_decorations.h
         fuzzer_pass_add_stores.h
-        fuzzer_pass_add_useful_constructs.h
         fuzzer_pass_adjust_branch_weights.h
         fuzzer_pass_adjust_function_controls.h
         fuzzer_pass_adjust_loop_controls.h
@@ -146,7 +145,6 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_add_local_variables.cpp
         fuzzer_pass_add_no_contraction_decorations.cpp
         fuzzer_pass_add_stores.cpp
-        fuzzer_pass_add_useful_constructs.cpp
         fuzzer_pass_adjust_branch_weights.cpp
         fuzzer_pass_adjust_function_controls.cpp
         fuzzer_pass_adjust_loop_controls.cpp

+ 0 - 11
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp

@@ -33,7 +33,6 @@
 #include "source/fuzz/fuzzer_pass_add_local_variables.h"
 #include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
 #include "source/fuzz/fuzzer_pass_add_stores.h"
-#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
 #include "source/fuzz/fuzzer_pass_adjust_branch_weights.h"
 #include "source/fuzz/fuzzer_pass_adjust_function_controls.h"
 #include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
@@ -187,16 +186,6 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
   TransformationContext transformation_context(&fact_manager,
                                                impl_->validator_options);
 
-  // Add some essential ingredients to the module if they are not already
-  // present, such as boolean constants.
-  FuzzerPassAddUsefulConstructs add_useful_constructs(
-      ir_context.get(), &transformation_context, &fuzzer_context,
-      transformation_sequence_out);
-  if (!impl_->ApplyPassAndCheckValidity(&add_useful_constructs, *ir_context,
-                                        tools)) {
-    return Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule;
-  }
-
   // Apply some semantics-preserving passes.
   std::vector<std::unique_ptr<FuzzerPass>> passes;
   while (passes.empty()) {

+ 29 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp

@@ -319,6 +319,35 @@ uint32_t FuzzerPass::FindOrCreateBoolConstant(bool value) {
   return result;
 }
 
+uint32_t FuzzerPass::FindOrCreateConstant(const std::vector<uint32_t>& words,
+                                          uint32_t type_id) {
+  assert(type_id && "Constant's type id can't be 0.");
+
+  const auto* type = GetIRContext()->get_type_mgr()->GetType(type_id);
+  assert(type && "Type does not exist.");
+
+  if (type->AsBool()) {
+    assert(words.size() == 1);
+    return FindOrCreateBoolConstant(words[0]);
+  } else if (const auto* integer = type->AsInteger()) {
+    assert(integer->width() == 32 && words.size() == 1 &&
+           "Integer must have 32-bit width");
+    return FindOrCreate32BitIntegerConstant(words[0], integer->IsSigned());
+  } else if (const auto* floating = type->AsFloat()) {
+    // Assertions are not evaluated in release builds so |floating|
+    // variable will be unused.
+    (void)floating;
+    assert(floating->width() == 32 && words.size() == 1 &&
+           "Floating point number must have 32-bit width");
+    return FindOrCreate32BitFloatConstant(words[0]);
+  }
+
+  // This assertion will fail in debug build but not in release build
+  // so we return 0 to make compiler happy.
+  assert(false && "Constant type is not supported");
+  return 0;
+}
+
 uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) {
   for (auto& inst : GetIRContext()->types_values()) {
     if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) {

+ 8 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h

@@ -164,6 +164,14 @@ class FuzzerPass {
   // type do not exist, transformations are applied to add them.
   uint32_t FindOrCreateBoolConstant(bool value);
 
+  // Returns the id of an OpConstant instruction of type with |type_id|
+  // that consists of |words|. If that instruction doesn't exist,
+  // transformations are applied to add it. |type_id| must be a valid
+  // result id of either scalar or boolean OpType* instruction that exists
+  // in the module.
+  uint32_t FindOrCreateConstant(const std::vector<uint32_t>& words,
+                                uint32_t type_id);
+
   // Returns the result id of an instruction of the form:
   //   %id = OpUndef %|type_id|
   // If no such instruction exists, a transformation is applied to add it.

+ 7 - 2
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp

@@ -41,6 +41,12 @@ void FuzzerPassAddDeadBlocks::Apply() {
               GetFuzzerContext()->GetChanceOfAddingDeadBlock())) {
         continue;
       }
+
+      // Make sure the module contains a boolean constant equal to
+      // |condition_value|.
+      bool condition_value = GetFuzzerContext()->ChooseEven();
+      FindOrCreateBoolConstant(condition_value);
+
       // We speculatively create a transformation, and then apply it (below) if
       // it turns out to be applicable.  This avoids duplicating the logic for
       // applicability checking.
@@ -48,8 +54,7 @@ void FuzzerPassAddDeadBlocks::Apply() {
       // It means that fresh ids for transformations that turn out not to be
       // applicable end up being unused.
       candidate_transformations.emplace_back(TransformationAddDeadBlock(
-          GetFuzzerContext()->GetFreshId(), block.id(),
-          GetFuzzerContext()->ChooseEven()));
+          GetFuzzerContext()->GetFreshId(), block.id(), condition_value));
     }
   }
   // Apply all those transformations that are in fact applicable.

+ 6 - 2
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp

@@ -77,9 +77,13 @@ void FuzzerPassAddDeadBreaks::Apply() {
           });
         }
 
+        // Make sure the module has a required boolean constant to be used in
+        // OpBranchConditional instruction.
+        auto break_condition = GetFuzzerContext()->ChooseEven();
+        FindOrCreateBoolConstant(break_condition);
+
         auto candidate_transformation = TransformationAddDeadBreak(
-            block.id(), merge_block->id(), GetFuzzerContext()->ChooseEven(),
-            std::move(phi_ids));
+            block.id(), merge_block->id(), break_condition, std::move(phi_ids));
         if (candidate_transformation.IsApplicable(
                 GetIRContext(), *GetTransformationContext())) {
           // Only consider a transformation as a candidate if it is applicable.

+ 6 - 1
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp

@@ -68,11 +68,16 @@ void FuzzerPassAddDeadContinues::Apply() {
         });
       }
 
+      // Make sure the module contains a boolean constant equal to
+      // |condition_value|.
+      bool condition_value = GetFuzzerContext()->ChooseEven();
+      FindOrCreateBoolConstant(condition_value);
+
       // Make a transformation to add a dead continue from this node; if the
       // node turns out to be inappropriate (e.g. by not being in a loop) the
       // precondition for the transformation will fail and it will be ignored.
       auto candidate_transformation = TransformationAddDeadContinue(
-          block.id(), GetFuzzerContext()->ChooseEven(), std::move(phi_ids));
+          block.id(), condition_value, std::move(phi_ids));
       // Probabilistically decide whether to apply the transformation in the
       // case that it is applicable.
       if (candidate_transformation.IsApplicable(GetIRContext(),

+ 0 - 222
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp

@@ -1,222 +0,0 @@
-// Copyright (c) 2019 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/fuzz/fuzzer_pass_add_useful_constructs.h"
-
-#include "source/fuzz/transformation_add_constant_boolean.h"
-#include "source/fuzz/transformation_add_constant_scalar.h"
-#include "source/fuzz/transformation_add_type_boolean.h"
-#include "source/fuzz/transformation_add_type_float.h"
-#include "source/fuzz/transformation_add_type_int.h"
-#include "source/fuzz/transformation_add_type_pointer.h"
-
-namespace spvtools {
-namespace fuzz {
-
-FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs(
-    opt::IRContext* ir_context, TransformationContext* transformation_context,
-    FuzzerContext* fuzzer_context,
-    protobufs::TransformationSequence* transformations)
-    : FuzzerPass(ir_context, transformation_context, fuzzer_context,
-                 transformations) {}
-
-FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default;
-
-void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant(
-    uint32_t width, bool is_signed, std::vector<uint32_t> data) const {
-  opt::analysis::Integer temp_int_type(width, is_signed);
-  assert(GetIRContext()->get_type_mgr()->GetId(&temp_int_type) &&
-         "int type should already be registered.");
-  auto registered_int_type = GetIRContext()
-                                 ->get_type_mgr()
-                                 ->GetRegisteredType(&temp_int_type)
-                                 ->AsInteger();
-  auto int_type_id = GetIRContext()->get_type_mgr()->GetId(registered_int_type);
-  assert(int_type_id &&
-         "The relevant int type should have been added to the module already.");
-  opt::analysis::IntConstant int_constant(registered_int_type, data);
-  if (!GetIRContext()->get_constant_mgr()->FindConstant(&int_constant)) {
-    TransformationAddConstantScalar add_constant_int =
-        TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
-                                        int_type_id, data);
-    assert(add_constant_int.IsApplicable(GetIRContext(),
-                                         *GetTransformationContext()) &&
-           "Should be applicable by construction.");
-    add_constant_int.Apply(GetIRContext(), GetTransformationContext());
-    *GetTransformations()->add_transformation() = add_constant_int.ToMessage();
-  }
-}
-
-void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant(
-    uint32_t width, std::vector<uint32_t> data) const {
-  opt::analysis::Float temp_float_type(width);
-  assert(GetIRContext()->get_type_mgr()->GetId(&temp_float_type) &&
-         "float type should already be registered.");
-  auto registered_float_type = GetIRContext()
-                                   ->get_type_mgr()
-                                   ->GetRegisteredType(&temp_float_type)
-                                   ->AsFloat();
-  auto float_type_id =
-      GetIRContext()->get_type_mgr()->GetId(registered_float_type);
-  assert(
-      float_type_id &&
-      "The relevant float type should have been added to the module already.");
-  opt::analysis::FloatConstant float_constant(registered_float_type, data);
-  if (!GetIRContext()->get_constant_mgr()->FindConstant(&float_constant)) {
-    TransformationAddConstantScalar add_constant_float =
-        TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
-                                        float_type_id, data);
-    assert(add_constant_float.IsApplicable(GetIRContext(),
-                                           *GetTransformationContext()) &&
-           "Should be applicable by construction.");
-    add_constant_float.Apply(GetIRContext(), GetTransformationContext());
-    *GetTransformations()->add_transformation() =
-        add_constant_float.ToMessage();
-  }
-}
-
-void FuzzerPassAddUsefulConstructs::Apply() {
-  {
-    // Add boolean type if not present.
-    opt::analysis::Bool temp_bool_type;
-    if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) {
-      auto add_type_boolean =
-          TransformationAddTypeBoolean(GetFuzzerContext()->GetFreshId());
-      assert(add_type_boolean.IsApplicable(GetIRContext(),
-                                           *GetTransformationContext()) &&
-             "Should be applicable by construction.");
-      add_type_boolean.Apply(GetIRContext(), GetTransformationContext());
-      *GetTransformations()->add_transformation() =
-          add_type_boolean.ToMessage();
-    }
-  }
-
-  {
-    // Add signed and unsigned 32-bit integer types if not present.
-    for (auto is_signed : {true, false}) {
-      opt::analysis::Integer temp_int_type(32, is_signed);
-      if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) {
-        TransformationAddTypeInt add_type_int = TransformationAddTypeInt(
-            GetFuzzerContext()->GetFreshId(), 32, is_signed);
-        assert(add_type_int.IsApplicable(GetIRContext(),
-                                         *GetTransformationContext()) &&
-               "Should be applicable by construction.");
-        add_type_int.Apply(GetIRContext(), GetTransformationContext());
-        *GetTransformations()->add_transformation() = add_type_int.ToMessage();
-      }
-    }
-  }
-
-  {
-    // Add 32-bit float type if not present.
-    opt::analysis::Float temp_float_type(32);
-    if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) {
-      TransformationAddTypeFloat add_type_float =
-          TransformationAddTypeFloat(GetFuzzerContext()->GetFreshId(), 32);
-      assert(add_type_float.IsApplicable(GetIRContext(),
-                                         *GetTransformationContext()) &&
-             "Should be applicable by construction.");
-      add_type_float.Apply(GetIRContext(), GetTransformationContext());
-      *GetTransformations()->add_transformation() = add_type_float.ToMessage();
-    }
-  }
-
-  // Add boolean constants true and false if not present.
-  opt::analysis::Bool temp_bool_type;
-  auto bool_type = GetIRContext()
-                       ->get_type_mgr()
-                       ->GetRegisteredType(&temp_bool_type)
-                       ->AsBool();
-  for (auto boolean_value : {true, false}) {
-    // Add OpConstantTrue/False if not already there.
-    opt::analysis::BoolConstant bool_constant(bool_type, boolean_value);
-    if (!GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant)) {
-      TransformationAddConstantBoolean add_constant_boolean(
-          GetFuzzerContext()->GetFreshId(), boolean_value);
-      assert(add_constant_boolean.IsApplicable(GetIRContext(),
-                                               *GetTransformationContext()) &&
-             "Should be applicable by construction.");
-      add_constant_boolean.Apply(GetIRContext(), GetTransformationContext());
-      *GetTransformations()->add_transformation() =
-          add_constant_boolean.ToMessage();
-    }
-  }
-
-  // Add signed and unsigned 32-bit integer constants 0 and 1 if not present.
-  for (auto is_signed : {true, false}) {
-    for (auto value : {0u, 1u}) {
-      MaybeAddIntConstant(32, is_signed, {value});
-    }
-  }
-
-  // Add 32-bit float constants 0.0 and 1.0 if not present.
-  uint32_t uint_data[2];
-  float float_data[2] = {0.0, 1.0};
-  memcpy(uint_data, float_data, sizeof(float_data));
-  for (unsigned int& datum : uint_data) {
-    MaybeAddFloatConstant(32, {datum});
-  }
-
-  // For every known-to-be-constant uniform, make sure we have instructions
-  // declaring:
-  // - a pointer type with uniform storage class, whose pointee type is the type
-  //   of the element
-  // - a signed integer constant for each index required to access the element
-  // - a constant for the constant value itself
-  for (auto& fact_and_type_id : GetTransformationContext()
-                                    ->GetFactManager()
-                                    ->GetConstantUniformFactsAndTypes()) {
-    uint32_t element_type_id = fact_and_type_id.second;
-    assert(element_type_id);
-    auto element_type =
-        GetIRContext()->get_type_mgr()->GetType(element_type_id);
-    assert(element_type &&
-           "If the constant uniform fact is well-formed, the module must "
-           "already have a declaration of the type for the uniform element.");
-    opt::analysis::Pointer uniform_pointer(element_type,
-                                           SpvStorageClassUniform);
-    if (!GetIRContext()->get_type_mgr()->GetId(&uniform_pointer)) {
-      auto add_pointer =
-          TransformationAddTypePointer(GetFuzzerContext()->GetFreshId(),
-                                       SpvStorageClassUniform, element_type_id);
-      assert(add_pointer.IsApplicable(GetIRContext(),
-                                      *GetTransformationContext()) &&
-             "Should be applicable by construction.");
-      add_pointer.Apply(GetIRContext(), GetTransformationContext());
-      *GetTransformations()->add_transformation() = add_pointer.ToMessage();
-    }
-    std::vector<uint32_t> words;
-    for (auto word : fact_and_type_id.first.constant_word()) {
-      words.push_back(word);
-    }
-    // We get the element type again as the type manager may have been
-    // invalidated since we last retrieved it.
-    element_type = GetIRContext()->get_type_mgr()->GetType(element_type_id);
-    if (element_type->AsInteger()) {
-      MaybeAddIntConstant(element_type->AsInteger()->width(),
-                          element_type->AsInteger()->IsSigned(), words);
-    } else {
-      assert(element_type->AsFloat() &&
-             "Known uniform values must be integer or floating-point.");
-      MaybeAddFloatConstant(element_type->AsFloat()->width(), words);
-    }
-    for (auto index :
-         fact_and_type_id.first.uniform_buffer_element_descriptor().index()) {
-      MaybeAddIntConstant(32, true, {index});
-    }
-  }
-}
-
-}  // namespace fuzz
-}  // namespace spvtools

+ 0 - 46
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h

@@ -1,46 +0,0 @@
-// Copyright (c) 2019 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_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_
-#define SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_
-
-#include "source/fuzz/fuzzer_pass.h"
-
-namespace spvtools {
-namespace fuzz {
-
-// An initial pass for adding useful ingredients to the module, such as boolean
-// constants, if they are not present.
-class FuzzerPassAddUsefulConstructs : public FuzzerPass {
- public:
-  FuzzerPassAddUsefulConstructs(
-      opt::IRContext* ir_context, TransformationContext* transformation_context,
-      FuzzerContext* fuzzer_context,
-      protobufs::TransformationSequence* transformations);
-
-  ~FuzzerPassAddUsefulConstructs() override;
-
-  void Apply() override;
-
- private:
-  void MaybeAddIntConstant(uint32_t width, bool is_signed,
-                           std::vector<uint32_t> data) const;
-
-  void MaybeAddFloatConstant(uint32_t width, std::vector<uint32_t> data) const;
-};
-
-}  // namespace fuzz
-}  // namespace spvtools
-
-#endif  // SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_

+ 1 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp

@@ -125,6 +125,7 @@ SpvStorageClass FuzzerPassDonateModules::AdaptStorageClass(
     case SpvStorageClassUniformConstant:
     case SpvStorageClassPushConstant:
     case SpvStorageClassImage:
+    case SpvStorageClassStorageBuffer:
       // We change these to Private
       return SpvStorageClassPrivate;
     default:

+ 69 - 17
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp

@@ -14,11 +14,14 @@
 
 #include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
 
+#include <algorithm>
 #include <cmath>
 
+#include "source/fuzz/fuzzer_util.h"
 #include "source/fuzz/instruction_descriptor.h"
 #include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
 #include "source/fuzz/transformation_replace_constant_with_uniform.h"
+#include "source/fuzz/uniform_buffer_element_descriptor.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
@@ -240,6 +243,29 @@ void FuzzerPassObfuscateConstants::
       first_constant_is_larger);
 }
 
+std::vector<std::vector<uint32_t>>
+FuzzerPassObfuscateConstants::GetConstantWordsFromUniformsForType(
+    uint32_t type_id) {
+  assert(type_id && "Type id can't be 0");
+  std::vector<std::vector<uint32_t>> result;
+
+  for (const auto& facts_and_types : GetTransformationContext()
+                                         ->GetFactManager()
+                                         ->GetConstantUniformFactsAndTypes()) {
+    if (facts_and_types.second != type_id) {
+      continue;
+    }
+
+    std::vector<uint32_t> words(facts_and_types.first.constant_word().begin(),
+                                facts_and_types.first.constant_word().end());
+    if (std::find(result.begin(), result.end(), words) == result.end()) {
+      result.push_back(std::move(words));
+    }
+  }
+
+  return result;
+}
+
 void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
     uint32_t depth, const protobufs::IdUseDescriptor& constant_use) {
   // We want to replace the boolean constant use with a binary expression over
@@ -258,11 +284,9 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
   auto chosen_type_id =
       available_types_with_uniforms[GetFuzzerContext()->RandomIndex(
           available_types_with_uniforms)];
-  auto available_constants = GetTransformationContext()
-                                 ->GetFactManager()
-                                 ->GetConstantsAvailableFromUniformsForType(
-                                     GetIRContext(), chosen_type_id);
-  if (available_constants.size() == 1) {
+  auto available_constant_words =
+      GetConstantWordsFromUniformsForType(chosen_type_id);
+  if (available_constant_words.size() == 1) {
     // TODO(afd): for now we only obfuscate a boolean if there are at least
     //  two constants available from uniforms, so that we can do a
     //  comparison between them. It would be good to be able to do the
@@ -271,18 +295,25 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
     return;
   }
 
+  assert(!available_constant_words.empty() &&
+         "There exists a fact but no constants - impossible");
+
   // We know we have at least two known-to-be-constant uniforms of the chosen
   // type.  Pick one of them at random.
-  auto constant_index_1 = GetFuzzerContext()->RandomIndex(available_constants);
+  auto constant_index_1 =
+      GetFuzzerContext()->RandomIndex(available_constant_words);
   uint32_t constant_index_2;
 
   // Now choose another one distinct from the first one.
   do {
-    constant_index_2 = GetFuzzerContext()->RandomIndex(available_constants);
+    constant_index_2 =
+        GetFuzzerContext()->RandomIndex(available_constant_words);
   } while (constant_index_1 == constant_index_2);
 
-  auto constant_id_1 = available_constants[constant_index_1];
-  auto constant_id_2 = available_constants[constant_index_2];
+  auto constant_id_1 = FindOrCreateConstant(
+      available_constant_words[constant_index_1], chosen_type_id);
+  auto constant_id_2 = FindOrCreateConstant(
+      available_constant_words[constant_index_2], chosen_type_id);
 
   assert(constant_id_1 != 0 && constant_id_2 != 0 &&
          "We should not find an available constant with an id of 0.");
@@ -324,18 +355,39 @@ void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
   }
 
   // Choose a random available uniform known to be equal to the constant.
-  protobufs::UniformBufferElementDescriptor uniform_descriptor =
+  const auto& uniform_descriptor =
       uniform_descriptors[GetFuzzerContext()->RandomIndex(uniform_descriptors)];
+
+  // Make sure the module has OpConstant instructions for each index used to
+  // access a uniform.
+  for (auto index : uniform_descriptor.index()) {
+    FindOrCreate32BitIntegerConstant(index, true);
+  }
+
+  // Make sure the module has OpTypePointer that points to the element type of
+  // the uniform.
+  const auto* uniform_variable_instr =
+      FindUniformVariable(uniform_descriptor, GetIRContext(), true);
+  assert(uniform_variable_instr &&
+         "Uniform variable does not exist or not unique.");
+
+  const auto* uniform_variable_type_intr =
+      GetIRContext()->get_def_use_mgr()->GetDef(
+          uniform_variable_instr->type_id());
+  assert(uniform_variable_type_intr && "Uniform variable has invalid type");
+
+  auto element_type_id = fuzzerutil::WalkCompositeTypeIndices(
+      GetIRContext(), uniform_variable_type_intr->GetSingleWordInOperand(1),
+      uniform_descriptor.index());
+  assert(element_type_id && "Type of uniform variable is invalid");
+
+  FindOrCreatePointerType(element_type_id, SpvStorageClassUniform);
+
   // Create, apply and record a transformation to replace the constant use with
   // the result of a load from the chosen uniform.
-  auto transformation = TransformationReplaceConstantWithUniform(
+  ApplyTransformation(TransformationReplaceConstantWithUniform(
       constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
-      GetFuzzerContext()->GetFreshId());
-  // Transformation should be applicable by construction.
-  assert(
-      transformation.IsApplicable(GetIRContext(), *GetTransformationContext()));
-  transformation.Apply(GetIRContext(), GetTransformationContext());
-  *GetTransformations()->add_transformation() = transformation.ToMessage();
+      GetFuzzerContext()->GetFreshId()));
 }
 
 void FuzzerPassObfuscateConstants::ObfuscateConstant(

+ 5 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h

@@ -99,6 +99,11 @@ class FuzzerPassObfuscateConstants : public FuzzerPass {
       uint32_t base_instruction_result_id,
       const std::map<SpvOp, uint32_t>& skipped_opcode_count,
       std::vector<protobufs::IdUseDescriptor>* constant_uses);
+
+  // Returns a vector of unique words that denote constants. Every such constant
+  // is used in |FactConstantUniform| and has type with id equal to |type_id|.
+  std::vector<std::vector<uint32_t>> GetConstantWordsFromUniformsForType(
+      uint32_t type_id);
 };
 
 }  // namespace fuzz

+ 1 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_util.h

@@ -18,6 +18,7 @@
 #include <vector>
 
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation_context.h"
 #include "source/opt/basic_block.h"
 #include "source/opt/instruction.h"
 #include "source/opt/ir_context.h"

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

@@ -24,10 +24,36 @@ static const uint32_t kOpLineOperandLineIndex = 1;
 static const uint32_t kLineOperandIndexDebugFunction = 7;
 static const uint32_t kLineOperandIndexDebugLexicalBlock = 5;
 static const uint32_t kDebugFunctionOperandFunctionIndex = 13;
+static const uint32_t kDebugInlinedAtOperandInlinedIndex = 6;
 
 namespace spvtools {
 namespace opt {
 namespace analysis {
+namespace {
+
+void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) {
+  assert(dbg_inlined_at);
+  assert(dbg_inlined_at->GetOpenCL100DebugOpcode() ==
+         OpenCLDebugInfo100DebugInlinedAt);
+  if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex) {
+    dbg_inlined_at->AddOperand({SPV_OPERAND_TYPE_RESULT_ID, {inlined_operand}});
+  } else {
+    dbg_inlined_at->SetOperand(kDebugInlinedAtOperandInlinedIndex,
+                               {inlined_operand});
+  }
+}
+
+uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) {
+  assert(dbg_inlined_at);
+  assert(dbg_inlined_at->GetOpenCL100DebugOpcode() ==
+         OpenCLDebugInfo100DebugInlinedAt);
+  if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex)
+    return kNoInlinedAt;
+  return dbg_inlined_at->GetSingleWordOperand(
+      kDebugInlinedAtOperandInlinedIndex);
+}
+
+}  // namespace
 
 DebugInfoManager::DebugInfoManager(IRContext* c) : context_(c) {
   AnalyzeDebugInsts(*c->module());
@@ -121,6 +147,69 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
   return result_id;
 }
 
+DebugScope DebugInfoManager::BuildDebugScope(
+    const DebugScope& callee_instr_scope,
+    DebugInlinedAtContext* inlined_at_ctx) {
+  return DebugScope(callee_instr_scope.GetLexicalScope(),
+                    BuildDebugInlinedAtChain(callee_instr_scope.GetInlinedAt(),
+                                             inlined_at_ctx));
+}
+
+uint32_t DebugInfoManager::BuildDebugInlinedAtChain(
+    uint32_t callee_inlined_at, DebugInlinedAtContext* inlined_at_ctx) {
+  if (inlined_at_ctx->GetScopeOfCallInstruction().GetLexicalScope() ==
+      kNoDebugScope)
+    return kNoInlinedAt;
+
+  // Reuse the already generated DebugInlinedAt chain if exists.
+  uint32_t already_generated_chain_head_id =
+      inlined_at_ctx->GetDebugInlinedAtChain(callee_inlined_at);
+  if (already_generated_chain_head_id != kNoInlinedAt) {
+    return already_generated_chain_head_id;
+  }
+
+  const uint32_t new_dbg_inlined_at_id =
+      CreateDebugInlinedAt(inlined_at_ctx->GetLineOfCallInstruction(),
+                           inlined_at_ctx->GetScopeOfCallInstruction());
+  if (new_dbg_inlined_at_id == kNoInlinedAt) return kNoInlinedAt;
+
+  if (callee_inlined_at == kNoInlinedAt) {
+    inlined_at_ctx->SetDebugInlinedAtChain(kNoInlinedAt, new_dbg_inlined_at_id);
+    return new_dbg_inlined_at_id;
+  }
+
+  uint32_t chain_head_id = kNoInlinedAt;
+  uint32_t chain_iter_id = callee_inlined_at;
+  Instruction* last_inlined_at_in_chain = nullptr;
+  do {
+    Instruction* new_inlined_at_in_chain = CloneDebugInlinedAt(
+        chain_iter_id, /* insert_before */ last_inlined_at_in_chain);
+    assert(new_inlined_at_in_chain != nullptr);
+
+    // Set DebugInlinedAt of the new scope as the head of the chain.
+    if (chain_head_id == kNoInlinedAt)
+      chain_head_id = new_inlined_at_in_chain->result_id();
+
+    // Previous DebugInlinedAt of the chain must point to the new
+    // DebugInlinedAt as its Inlined operand to build a recursive
+    // chain.
+    if (last_inlined_at_in_chain != nullptr) {
+      SetInlinedOperand(last_inlined_at_in_chain,
+                        new_inlined_at_in_chain->result_id());
+    }
+    last_inlined_at_in_chain = new_inlined_at_in_chain;
+
+    chain_iter_id = GetInlinedOperand(new_inlined_at_in_chain);
+  } while (chain_iter_id != kNoInlinedAt);
+
+  // Put |new_dbg_inlined_at_id| into the end of the chain.
+  SetInlinedOperand(last_inlined_at_in_chain, new_dbg_inlined_at_id);
+
+  // Keep the new chain information that will be reused it.
+  inlined_at_ctx->SetDebugInlinedAtChain(callee_inlined_at, chain_head_id);
+  return chain_head_id;
+}
+
 Instruction* DebugInfoManager::GetDebugInfoNone() {
   if (debug_info_none_inst_ != nullptr) return debug_info_none_inst_;
 

+ 54 - 0
3rdparty/spirv-tools/source/opt/debug_info_manager.h

@@ -24,6 +24,48 @@ namespace spvtools {
 namespace opt {
 namespace analysis {
 
+// When an instruction of a callee function is inlined to its caller function,
+// we need the line and the scope information of the function call instruction
+// to generate DebugInlinedAt. This class keeps the data. For multiple inlining
+// of a single instruction, we have to create multiple DebugInlinedAt
+// instructions as a chain. This class keeps the information of the generated
+// DebugInlinedAt chains to reduce the number of chains.
+class DebugInlinedAtContext {
+ public:
+  explicit DebugInlinedAtContext(Instruction* call_inst)
+      : call_inst_line_(call_inst->dbg_line_inst()),
+        call_inst_scope_(call_inst->GetDebugScope()) {}
+
+  const Instruction* GetLineOfCallInstruction() { return call_inst_line_; }
+  const DebugScope& GetScopeOfCallInstruction() { return call_inst_scope_; }
+  // Puts the DebugInlinedAt chain that is generated for the callee instruction
+  // whose DebugInlinedAt of DebugScope is |callee_instr_inlined_at| into
+  // |callee_inlined_at2chain_|.
+  void SetDebugInlinedAtChain(uint32_t callee_instr_inlined_at,
+                              uint32_t chain_head_id) {
+    callee_inlined_at2chain_[callee_instr_inlined_at] = chain_head_id;
+  }
+  // Gets the DebugInlinedAt chain from |callee_inlined_at2chain_|.
+  uint32_t GetDebugInlinedAtChain(uint32_t callee_instr_inlined_at) {
+    auto chain_itr = callee_inlined_at2chain_.find(callee_instr_inlined_at);
+    if (chain_itr != callee_inlined_at2chain_.end()) return chain_itr->second;
+    return kNoInlinedAt;
+  }
+
+ private:
+  // The line information of the function call instruction that will be
+  // replaced by the callee function.
+  const Instruction* call_inst_line_;
+
+  // The scope information of the function call instruction that will be
+  // replaced by the callee function.
+  const DebugScope call_inst_scope_;
+
+  // Map from DebugInlinedAt ids of callee to head ids of new generated
+  // DebugInlinedAt chain.
+  std::unordered_map<uint32_t, uint32_t> callee_inlined_at2chain_;
+};
+
 // A class for analyzing, managing, and creating OpenCL.DebugInfo.100 extension
 // instructions.
 class DebugInfoManager {
@@ -74,6 +116,18 @@ class DebugInfoManager {
   Instruction* CloneDebugInlinedAt(uint32_t clone_inlined_at_id,
                                    Instruction* insert_before = nullptr);
 
+  // Returns the debug scope corresponding to an inlining instruction in the
+  // scope |callee_instr_scope| into |inlined_at_ctx|. Generates all new
+  // debug instructions needed to represent the scope.
+  DebugScope BuildDebugScope(const DebugScope& callee_instr_scope,
+                             DebugInlinedAtContext* inlined_at_ctx);
+
+  // Returns DebugInlinedAt corresponding to inlining an instruction, which
+  // was inlined at |callee_inlined_at|, into |inlined_at_ctx|. Generates all
+  // new debug instructions needed to represent the DebugInlinedAt.
+  uint32_t BuildDebugInlinedAtChain(uint32_t callee_inlined_at,
+                                    DebugInlinedAtContext* inlined_at_ctx);
+
  private:
   IRContext* context() { return context_; }
 

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

@@ -154,6 +154,18 @@ void Function::ForEachParam(const std::function<void(const Instruction*)>& f,
         ->ForEachInst(f, run_on_debug_line_insts);
 }
 
+void Function::ForEachDebugInstructionsInHeader(
+    const std::function<void(Instruction*)>& f) {
+  if (debug_insts_in_header_.empty()) return;
+
+  Instruction* di = &debug_insts_in_header_.front();
+  while (di != nullptr) {
+    Instruction* next_instruction = di->NextNode();
+    di->ForEachInst(f);
+    di = next_instruction;
+  }
+}
+
 BasicBlock* Function::InsertBasicBlockAfter(
     std::unique_ptr<BasicBlock>&& new_block, BasicBlock* position) {
   for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) {

+ 5 - 0
3rdparty/spirv-tools/source/opt/function.h

@@ -133,6 +133,11 @@ class Function {
   void ForEachParam(const std::function<void(Instruction*)>& f,
                     bool run_on_debug_line_insts = false);
 
+  // Runs the given function |f| on each debug instruction in this function's
+  // header in order.
+  void ForEachDebugInstructionsInHeader(
+      const std::function<void(Instruction*)>& f);
+
   BasicBlock* InsertBasicBlockAfter(std::unique_ptr<BasicBlock>&& new_block,
                                     BasicBlock* position);
 

+ 98 - 33
3rdparty/spirv-tools/source/opt/inline_pass.cpp

@@ -84,19 +84,31 @@ void InlinePass::AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
 }
 
 void InlinePass::AddStore(uint32_t ptr_id, uint32_t val_id,
-                          std::unique_ptr<BasicBlock>* block_ptr) {
+                          std::unique_ptr<BasicBlock>* block_ptr,
+                          const Instruction* line_inst,
+                          const DebugScope& dbg_scope) {
   std::unique_ptr<Instruction> newStore(
       new Instruction(context(), SpvOpStore, 0, 0,
                       {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}},
                        {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {val_id}}}));
+  if (line_inst != nullptr) {
+    newStore->dbg_line_insts().push_back(*line_inst);
+  }
+  newStore->SetDebugScope(dbg_scope);
   (*block_ptr)->AddInstruction(std::move(newStore));
 }
 
 void InlinePass::AddLoad(uint32_t type_id, uint32_t resultId, uint32_t ptr_id,
-                         std::unique_ptr<BasicBlock>* block_ptr) {
+                         std::unique_ptr<BasicBlock>* block_ptr,
+                         const Instruction* line_inst,
+                         const DebugScope& dbg_scope) {
   std::unique_ptr<Instruction> newLoad(
       new Instruction(context(), SpvOpLoad, type_id, resultId,
                       {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}}}));
+  if (line_inst != nullptr) {
+    newLoad->dbg_line_insts().push_back(*line_inst);
+  }
+  newLoad->SetDebugScope(dbg_scope);
   (*block_ptr)->AddInstruction(std::move(newLoad));
 }
 
@@ -141,10 +153,18 @@ void InlinePass::MapParams(
 
 bool InlinePass::CloneAndMapLocals(
     Function* calleeFn, std::vector<std::unique_ptr<Instruction>>* new_vars,
-    std::unordered_map<uint32_t, uint32_t>* callee2caller) {
+    std::unordered_map<uint32_t, uint32_t>* callee2caller,
+    analysis::DebugInlinedAtContext* inlined_at_ctx) {
   auto callee_block_itr = calleeFn->begin();
   auto callee_var_itr = callee_block_itr->begin();
-  while (callee_var_itr->opcode() == SpvOp::SpvOpVariable) {
+  while (callee_var_itr->opcode() == SpvOp::SpvOpVariable ||
+         callee_var_itr->GetOpenCL100DebugOpcode() ==
+             OpenCLDebugInfo100DebugDeclare) {
+    if (callee_var_itr->opcode() != SpvOp::SpvOpVariable) {
+      ++callee_var_itr;
+      continue;
+    }
+
     std::unique_ptr<Instruction> var_inst(callee_var_itr->Clone(context()));
     uint32_t newId = context()->TakeNextId();
     if (newId == 0) {
@@ -152,6 +172,9 @@ bool InlinePass::CloneAndMapLocals(
     }
     get_decoration_mgr()->CloneDecorations(callee_var_itr->result_id(), newId);
     var_inst->SetResultId(newId);
+    var_inst->UpdateDebugInlinedAt(
+        context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
+            callee_var_itr->GetDebugInlinedAt(), inlined_at_ctx));
     (*callee2caller)[callee_var_itr->result_id()] = newId;
     new_vars->push_back(std::move(var_inst));
     ++callee_var_itr;
@@ -272,28 +295,41 @@ std::unique_ptr<BasicBlock> InlinePass::AddGuardBlock(
 
 InstructionList::iterator InlinePass::AddStoresForVariableInitializers(
     const std::unordered_map<uint32_t, uint32_t>& callee2caller,
+    analysis::DebugInlinedAtContext* inlined_at_ctx,
     std::unique_ptr<BasicBlock>* new_blk_ptr,
     UptrVectorIterator<BasicBlock> callee_first_block_itr) {
-  auto callee_var_itr = callee_first_block_itr->begin();
-  while (callee_var_itr->opcode() == SpvOp::SpvOpVariable) {
-    if (callee_var_itr->NumInOperands() == 2) {
-      assert(callee2caller.count(callee_var_itr->result_id()) &&
+  auto callee_itr = callee_first_block_itr->begin();
+  while (callee_itr->opcode() == SpvOp::SpvOpVariable ||
+         callee_itr->GetOpenCL100DebugOpcode() ==
+             OpenCLDebugInfo100DebugDeclare) {
+    if (callee_itr->opcode() == SpvOp::SpvOpVariable &&
+        callee_itr->NumInOperands() == 2) {
+      assert(callee2caller.count(callee_itr->result_id()) &&
              "Expected the variable to have already been mapped.");
-      uint32_t new_var_id = callee2caller.at(callee_var_itr->result_id());
+      uint32_t new_var_id = callee2caller.at(callee_itr->result_id());
 
       // The initializer must be a constant or global value.  No mapped
       // should be used.
-      uint32_t val_id = callee_var_itr->GetSingleWordInOperand(1);
-      AddStore(new_var_id, val_id, new_blk_ptr);
+      uint32_t val_id = callee_itr->GetSingleWordInOperand(1);
+      AddStore(new_var_id, val_id, new_blk_ptr, callee_itr->dbg_line_inst(),
+               context()->get_debug_info_mgr()->BuildDebugScope(
+                   callee_itr->GetDebugScope(), inlined_at_ctx));
     }
-    ++callee_var_itr;
+    if (callee_itr->GetOpenCL100DebugOpcode() ==
+        OpenCLDebugInfo100DebugDeclare) {
+      InlineSingleInstruction(
+          callee2caller, new_blk_ptr->get(), &*callee_itr,
+          context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
+              callee_itr->GetDebugScope().GetInlinedAt(), inlined_at_ctx));
+    }
+    ++callee_itr;
   }
-  return callee_var_itr;
+  return callee_itr;
 }
 
-bool InlinePass::InlineInstructionInBB(
+bool InlinePass::InlineSingleInstruction(
     const std::unordered_map<uint32_t, uint32_t>& callee2caller,
-    BasicBlock* new_blk_ptr, const Instruction* inst) {
+    BasicBlock* new_blk_ptr, const Instruction* inst, uint32_t dbg_inlined_at) {
   // If we have return, it must be at the end of the callee. We will handle
   // it at the end.
   if (inst->opcode() == SpvOpReturnValue || inst->opcode() == SpvOpReturn)
@@ -307,15 +343,20 @@ bool InlinePass::InlineInstructionInBB(
       *iid = mapItr->second;
     }
   });
+
   // If result id is non-zero, remap it.
   const uint32_t rid = cp_inst->result_id();
   if (rid != 0) {
     const auto mapItr = callee2caller.find(rid);
-    if (mapItr == callee2caller.end()) return false;
+    if (mapItr == callee2caller.end()) {
+      return false;
+    }
     uint32_t nid = mapItr->second;
     cp_inst->SetResultId(nid);
     get_decoration_mgr()->CloneDecorations(rid, nid);
   }
+
+  cp_inst->UpdateDebugInlinedAt(dbg_inlined_at);
   new_blk_ptr->AddInstruction(std::move(cp_inst));
   return true;
 }
@@ -323,7 +364,8 @@ bool InlinePass::InlineInstructionInBB(
 std::unique_ptr<BasicBlock> InlinePass::InlineReturn(
     const std::unordered_map<uint32_t, uint32_t>& callee2caller,
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
-    std::unique_ptr<BasicBlock> new_blk_ptr, Function* calleeFn,
+    std::unique_ptr<BasicBlock> new_blk_ptr,
+    analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn,
     const Instruction* inst, uint32_t returnVarId) {
   // Store return value to return variable.
   if (inst->opcode() == SpvOpReturnValue) {
@@ -333,7 +375,9 @@ std::unique_ptr<BasicBlock> InlinePass::InlineReturn(
     if (mapItr != callee2caller.end()) {
       valId = mapItr->second;
     }
-    AddStore(returnVarId, valId, &new_blk_ptr);
+    AddStore(returnVarId, valId, &new_blk_ptr, inst->dbg_line_inst(),
+             context()->get_debug_info_mgr()->BuildDebugScope(
+                 inst->GetDebugScope(), inlined_at_ctx));
   }
 
   uint32_t returnLabelId = 0;
@@ -356,13 +400,17 @@ std::unique_ptr<BasicBlock> InlinePass::InlineReturn(
 bool InlinePass::InlineEntryBlock(
     const std::unordered_map<uint32_t, uint32_t>& callee2caller,
     std::unique_ptr<BasicBlock>* new_blk_ptr,
-    UptrVectorIterator<BasicBlock> callee_first_block) {
+    UptrVectorIterator<BasicBlock> callee_first_block,
+    analysis::DebugInlinedAtContext* inlined_at_ctx) {
   auto callee_inst_itr = AddStoresForVariableInitializers(
-      callee2caller, new_blk_ptr, callee_first_block);
+      callee2caller, inlined_at_ctx, new_blk_ptr, callee_first_block);
 
   while (callee_inst_itr != callee_first_block->end()) {
-    if (!InlineInstructionInBB(callee2caller, new_blk_ptr->get(),
-                               &*callee_inst_itr)) {
+    if (!InlineSingleInstruction(
+            callee2caller, new_blk_ptr->get(), &*callee_inst_itr,
+            context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
+                callee_inst_itr->GetDebugScope().GetInlinedAt(),
+                inlined_at_ctx))) {
       return false;
     }
     ++callee_inst_itr;
@@ -373,7 +421,8 @@ bool InlinePass::InlineEntryBlock(
 std::unique_ptr<BasicBlock> InlinePass::InlineBasicBlocks(
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
     const std::unordered_map<uint32_t, uint32_t>& callee2caller,
-    std::unique_ptr<BasicBlock> new_blk_ptr, Function* calleeFn) {
+    std::unique_ptr<BasicBlock> new_blk_ptr,
+    analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn) {
   auto callee_block_itr = calleeFn->begin();
   ++callee_block_itr;
 
@@ -387,8 +436,10 @@ std::unique_ptr<BasicBlock> InlinePass::InlineBasicBlocks(
     auto tail_inst_itr = callee_block_itr->end();
     for (auto inst_itr = callee_block_itr->begin(); inst_itr != tail_inst_itr;
          ++inst_itr) {
-      if (!InlineInstructionInBB(callee2caller, new_blk_ptr.get(),
-                                 &*inst_itr)) {
+      if (!InlineSingleInstruction(
+              callee2caller, new_blk_ptr.get(), &*inst_itr,
+              context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
+                  inst_itr->GetDebugScope().GetInlinedAt(), inlined_at_ctx))) {
         return nullptr;
       }
     }
@@ -460,6 +511,8 @@ bool InlinePass::GenInlineCode(
   // Post-call same-block op ids
   std::unordered_map<uint32_t, uint32_t> postCallSB;
 
+  analysis::DebugInlinedAtContext inlined_at_ctx(&*call_inst_itr);
+
   // Invalidate the def-use chains.  They are not kept up to date while
   // inlining.  However, certain calls try to keep them up-to-date if they are
   // valid.  These operations can fail.
@@ -483,7 +536,7 @@ bool InlinePass::GenInlineCode(
 
   // Define caller local variables for all callee variables and create map to
   // them.
-  if (!CloneAndMapLocals(calleeFn, new_vars, &callee2caller)) {
+  if (!CloneAndMapLocals(calleeFn, new_vars, &callee2caller, &inlined_at_ctx)) {
     return false;
   }
 
@@ -534,25 +587,37 @@ bool InlinePass::GenInlineCode(
     return true;
   });
 
+  // Inline DebugClare instructions in the callee's header.
+  calleeFn->ForEachDebugInstructionsInHeader(
+      [&new_blk_ptr, &callee2caller, &inlined_at_ctx, this](Instruction* inst) {
+        InlineSingleInstruction(
+            callee2caller, new_blk_ptr.get(), inst,
+            context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
+                inst->GetDebugScope().GetInlinedAt(), &inlined_at_ctx));
+      });
+
   // Inline the entry block of the callee function.
-  if (!InlineEntryBlock(callee2caller, &new_blk_ptr, calleeFn->begin())) {
+  if (!InlineEntryBlock(callee2caller, &new_blk_ptr, calleeFn->begin(),
+                        &inlined_at_ctx)) {
     return false;
   }
 
   // Inline blocks of the callee function other than the entry block.
-  new_blk_ptr = InlineBasicBlocks(new_blocks, callee2caller,
-                                  std::move(new_blk_ptr), calleeFn);
+  new_blk_ptr =
+      InlineBasicBlocks(new_blocks, callee2caller, std::move(new_blk_ptr),
+                        &inlined_at_ctx, calleeFn);
   if (new_blk_ptr == nullptr) return false;
 
-  new_blk_ptr =
-      InlineReturn(callee2caller, new_blocks, std::move(new_blk_ptr), calleeFn,
-                   &*(calleeFn->tail()->tail()), returnVarId);
+  new_blk_ptr = InlineReturn(callee2caller, new_blocks, std::move(new_blk_ptr),
+                             &inlined_at_ctx, calleeFn,
+                             &*(calleeFn->tail()->tail()), returnVarId);
 
   // Load return value into result id of call, if it exists.
   if (returnVarId != 0) {
     const uint32_t resId = call_inst_itr->result_id();
     assert(resId != 0);
-    AddLoad(calleeTypeId, resId, returnVarId, &new_blk_ptr);
+    AddLoad(calleeTypeId, resId, returnVarId, &new_blk_ptr,
+            call_inst_itr->dbg_line_inst(), call_inst_itr->GetDebugScope());
   }
 
   // Move instructions of original caller block after call instruction.

+ 17 - 8
3rdparty/spirv-tools/source/opt/inline_pass.h

@@ -24,6 +24,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include "source/opt/debug_info_manager.h"
 #include "source/opt/decoration_manager.h"
 #include "source/opt/module.h"
 #include "source/opt/pass.h"
@@ -58,11 +59,13 @@ class InlinePass : public Pass {
 
   // Add store of valId to ptrId to end of block block_ptr.
   void AddStore(uint32_t ptrId, uint32_t valId,
-                std::unique_ptr<BasicBlock>* block_ptr);
+                std::unique_ptr<BasicBlock>* block_ptr,
+                const Instruction* line_inst, const DebugScope& dbg_scope);
 
   // Add load of ptrId into resultId to end of block block_ptr.
   void AddLoad(uint32_t typeId, uint32_t resultId, uint32_t ptrId,
-               std::unique_ptr<BasicBlock>* block_ptr);
+               std::unique_ptr<BasicBlock>* block_ptr,
+               const Instruction* line_inst, const DebugScope& dbg_scope);
 
   // Return new label.
   std::unique_ptr<Instruction> NewLabel(uint32_t label_id);
@@ -79,7 +82,8 @@ class InlinePass : public Pass {
   // Clone and map callee locals.  Return true if successful.
   bool CloneAndMapLocals(Function* calleeFn,
                          std::vector<std::unique_ptr<Instruction>>* new_vars,
-                         std::unordered_map<uint32_t, uint32_t>* callee2caller);
+                         std::unordered_map<uint32_t, uint32_t>* callee2caller,
+                         analysis::DebugInlinedAtContext* inlined_at_ctx);
 
   // Create return variable for callee clone code.  The return type of
   // |calleeFn| must not be void.  Returns  the id of the return variable if
@@ -186,33 +190,38 @@ class InlinePass : public Pass {
   // Add store instructions for initializers of variables.
   InstructionList::iterator AddStoresForVariableInitializers(
       const std::unordered_map<uint32_t, uint32_t>& callee2caller,
+      analysis::DebugInlinedAtContext* inlined_at_ctx,
       std::unique_ptr<BasicBlock>* new_blk_ptr,
       UptrVectorIterator<BasicBlock> callee_block_itr);
 
   // Inlines a single instruction of the callee function.
-  bool InlineInstructionInBB(
+  bool InlineSingleInstruction(
       const std::unordered_map<uint32_t, uint32_t>& callee2caller,
-      BasicBlock* new_blk_ptr, const Instruction* inst);
+      BasicBlock* new_blk_ptr, const Instruction* inst,
+      uint32_t dbg_inlined_at);
 
   // Inlines the return instruction of the callee function.
   std::unique_ptr<BasicBlock> InlineReturn(
       const std::unordered_map<uint32_t, uint32_t>& callee2caller,
       std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
-      std::unique_ptr<BasicBlock> new_blk_ptr, Function* calleeFn,
+      std::unique_ptr<BasicBlock> new_blk_ptr,
+      analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn,
       const Instruction* inst, uint32_t returnVarId);
 
   // Inlines the entry block of the callee function.
   bool InlineEntryBlock(
       const std::unordered_map<uint32_t, uint32_t>& callee2caller,
       std::unique_ptr<BasicBlock>* new_blk_ptr,
-      UptrVectorIterator<BasicBlock> callee_first_block);
+      UptrVectorIterator<BasicBlock> callee_first_block,
+      analysis::DebugInlinedAtContext* inlined_at_ctx);
 
   // Inlines basic blocks of the callee function other than the entry basic
   // block.
   std::unique_ptr<BasicBlock> InlineBasicBlocks(
       std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
       const std::unordered_map<uint32_t, uint32_t>& callee2caller,
-      std::unique_ptr<BasicBlock> new_blk_ptr, Function* calleeFn);
+      std::unique_ptr<BasicBlock> new_blk_ptr,
+      analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn);
 
   // Moves instructions of the caller function after the call instruction
   // to |new_blk_ptr|.

+ 0 - 7
3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h

@@ -28,13 +28,6 @@ namespace opt {
 // external design may change as the layer evolves.
 class InstBindlessCheckPass : public InstrumentPass {
  public:
-  // Deprecated interface
-  InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
-                        bool input_length_enable, bool input_init_enable,
-                        uint32_t version)
-      : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, version),
-        input_length_enabled_(input_length_enable),
-        input_init_enabled_(input_init_enable) {}
   // Preferred Interface
   InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
                         bool input_length_enable, bool input_init_enable)

+ 0 - 4
3rdparty/spirv-tools/source/opt/inst_buff_addr_check_pass.h

@@ -28,10 +28,6 @@ namespace opt {
 // external design of this class may change as the layer evolves.
 class InstBuffAddrCheckPass : public InstrumentPass {
  public:
-  // Deprecated interface
-  InstBuffAddrCheckPass(uint32_t desc_set, uint32_t shader_id, uint32_t version)
-      : InstrumentPass(desc_set, shader_id, kInstValidationIdBuffAddr,
-                       version) {}
   // Preferred interface
   InstBuffAddrCheckPass(uint32_t desc_set, uint32_t shader_id)
       : InstrumentPass(desc_set, shader_id, kInstValidationIdBuffAddr) {}

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

@@ -28,11 +28,10 @@ namespace opt {
 class InstDebugPrintfPass : public InstrumentPass {
  public:
   // For test harness only
-  InstDebugPrintfPass()
-      : InstrumentPass(7, 23, kInstValidationIdDebugPrintf, 2) {}
+  InstDebugPrintfPass() : InstrumentPass(7, 23, kInstValidationIdDebugPrintf) {}
   // For all other interfaces
   InstDebugPrintfPass(uint32_t desc_set, uint32_t shader_id)
-      : InstrumentPass(desc_set, shader_id, kInstValidationIdDebugPrintf, 2) {}
+      : InstrumentPass(desc_set, shader_id, kInstValidationIdDebugPrintf) {}
 
   ~InstDebugPrintfPass() override = default;
 

+ 13 - 1
3rdparty/spirv-tools/source/opt/instruction.cpp

@@ -623,7 +623,19 @@ bool Instruction::IsFoldableByFoldScalar() const {
     return false;
   }
   Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
-  return folder.IsFoldableType(type);
+  if (!folder.IsFoldableType(type)) {
+    return false;
+  }
+
+  // Even if the type of the instruction is foldable, its operands may not be
+  // foldable (e.g., comparisons of 64bit types).  Check that all operand types
+  // are foldable before accepting the instruction.
+  return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
+    Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
+    Instruction* def_inst_type =
+        context()->get_def_use_mgr()->GetDef(def_inst->type_id());
+    return folder.IsFoldableType(def_inst_type);
+  });
 }
 
 bool Instruction::IsFloatingPointFoldingAllowed() const {

+ 16 - 0
3rdparty/spirv-tools/source/opt/instruction.h

@@ -239,6 +239,10 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
     return dbg_line_insts_;
   }
 
+  const Instruction* dbg_line_inst() const {
+    return dbg_line_insts_.empty() ? nullptr : &dbg_line_insts_[0];
+  }
+
   // Clear line-related debug instructions attached to this instruction.
   void clear_dbg_line_insts() { dbg_line_insts_.clear(); }
 
@@ -291,6 +295,11 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
   // Sets DebugScope.
   inline void SetDebugScope(const DebugScope& scope);
   inline const DebugScope& GetDebugScope() const { return dbg_scope_; }
+  // Updates DebugInlinedAt of DebugScope and OpLine.
+  inline void UpdateDebugInlinedAt(uint32_t new_inlined_at);
+  inline uint32_t GetDebugInlinedAt() const {
+    return dbg_scope_.GetInlinedAt();
+  }
   // Updates OpLine and DebugScope based on the information of |from|.
   inline void UpdateDebugInfo(const Instruction* from);
   // Remove the |index|-th operand
@@ -642,6 +651,13 @@ inline void Instruction::SetDebugScope(const DebugScope& scope) {
   }
 }
 
+inline void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) {
+  dbg_scope_.SetInlinedAt(new_inlined_at);
+  for (auto& i : dbg_line_insts_) {
+    i.dbg_scope_.SetInlinedAt(new_inlined_at);
+  }
+}
+
 inline void Instruction::UpdateDebugInfo(const Instruction* from) {
   if (from == nullptr) return;
   clear_dbg_line_insts();

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

@@ -885,14 +885,6 @@ bool InstrumentPass::InstProcessCallTreeFromRoots(InstProcessFunction& pfn,
 }
 
 bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
-  // Check that format version 2 requested
-  if (version_ != 2u) {
-    if (consumer()) {
-      std::string message = "Unsupported instrumentation format requested";
-      consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
-    }
-    return false;
-  }
   // Make sure all entry points have the same execution model. Do not
   // instrument if they do not.
   // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module

+ 1 - 15
3rdparty/spirv-tools/source/opt/instrument_pass.h

@@ -87,18 +87,7 @@ class InstrumentPass : public Pass {
       : Pass(),
         desc_set_(desc_set),
         shader_id_(shader_id),
-        validation_id_(validation_id),
-        version_(2u) {}
-  // Create instrumentation pass for |validation_id| which utilizes descriptor
-  // set |desc_set| for debug input and output buffers and writes |shader_id|
-  // into debug output records with format |version|. Deprecated.
-  InstrumentPass(uint32_t desc_set, uint32_t shader_id, uint32_t validation_id,
-                 uint32_t version)
-      : Pass(),
-        desc_set_(desc_set),
-        shader_id_(shader_id),
-        validation_id_(validation_id),
-        version_(version) {}
+        validation_id_(validation_id) {}
 
   // Initialize state for instrumentation of module.
   void InitializeInstrument();
@@ -425,9 +414,6 @@ class InstrumentPass : public Pass {
   // id for void type
   uint32_t void_id_;
 
-  // Record format version
-  uint32_t version_;
-
   // boolean to remember storage buffer extension
   bool storage_buffer_ext_defined_;
 

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

@@ -97,6 +97,11 @@ Instruction* MemPass::GetPtr(uint32_t ptrId, uint32_t* varId) {
   Instruction* ptrInst = get_def_use_mgr()->GetDef(*varId);
   Instruction* varInst;
 
+  if (ptrInst->opcode() == SpvOpConstantNull) {
+    *varId = 0;
+    return ptrInst;
+  }
+
   if (ptrInst->opcode() != SpvOpVariable &&
       ptrInst->opcode() != SpvOpFunctionParameter) {
     varInst = ptrInst->GetBaseAddress();

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

@@ -424,7 +424,6 @@ bool MergeReturnPass::BreakFromConstruct(
   auto old_body_id = TakeNextId();
   BasicBlock* old_body = block->SplitBasicBlock(context(), old_body_id, iter);
   predicated->insert(old_body);
-  cfg()->AddEdges(old_body);
 
   // If a return block is being split, mark the new body block also as a return
   // block.

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

@@ -175,9 +175,18 @@ Optimizer& Optimizer::RegisterPerformancePasses() {
       .RegisterPass(CreateAggressiveDCEPass())
       .RegisterPass(CreateCCPPass())
       .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateLoopUnrollPass(true))
+      .RegisterPass(CreateDeadBranchElimPass())
       .RegisterPass(CreateRedundancyEliminationPass())
       .RegisterPass(CreateCombineAccessChainsPass())
       .RegisterPass(CreateSimplificationPass())
+      .RegisterPass(CreateScalarReplacementPass())
+      .RegisterPass(CreateLocalAccessChainConvertPass())
+      .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
+      .RegisterPass(CreateLocalSingleStoreElimPass())
+      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateSSARewritePass())
+      .RegisterPass(CreateAggressiveDCEPass())
       .RegisterPass(CreateVectorDCEPass())
       .RegisterPass(CreateDeadInsertElimPass())
       .RegisterPass(CreateDeadBranchElimPass())
@@ -407,19 +416,19 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
   } else if (pass_name == "replace-invalid-opcode") {
     RegisterPass(CreateReplaceInvalidOpcodePass());
   } else if (pass_name == "inst-bindless-check") {
-    RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, 2));
+    RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false));
     RegisterPass(CreateSimplificationPass());
     RegisterPass(CreateDeadBranchElimPass());
     RegisterPass(CreateBlockMergePass());
     RegisterPass(CreateAggressiveDCEPass());
   } else if (pass_name == "inst-desc-idx-check") {
-    RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true, 2));
+    RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true));
     RegisterPass(CreateSimplificationPass());
     RegisterPass(CreateDeadBranchElimPass());
     RegisterPass(CreateBlockMergePass());
     RegisterPass(CreateAggressiveDCEPass());
   } else if (pass_name == "inst-buff-addr-check") {
-    RegisterPass(CreateInstBuffAddrCheckPass(7, 23, 2));
+    RegisterPass(CreateInstBuffAddrCheckPass(7, 23));
     RegisterPass(CreateAggressiveDCEPass());
   } else if (pass_name == "convert-relaxed-to-half") {
     RegisterPass(CreateConvertRelaxedToHalfPass());
@@ -885,12 +894,10 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass() {
 Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set,
                                                  uint32_t shader_id,
                                                  bool input_length_enable,
-                                                 bool input_init_enable,
-                                                 uint32_t version) {
+                                                 bool input_init_enable) {
   return MakeUnique<Optimizer::PassToken::Impl>(
-      MakeUnique<opt::InstBindlessCheckPass>(desc_set, shader_id,
-                                             input_length_enable,
-                                             input_init_enable, version));
+      MakeUnique<opt::InstBindlessCheckPass>(
+          desc_set, shader_id, input_length_enable, input_init_enable));
 }
 
 Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
@@ -900,10 +907,9 @@ Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
 }
 
 Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
-                                                 uint32_t shader_id,
-                                                 uint32_t version) {
+                                                 uint32_t shader_id) {
   return MakeUnique<Optimizer::PassToken::Impl>(
-      MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id, version));
+      MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id));
 }
 
 Optimizer::PassToken CreateConvertRelaxedToHalfPass() {

+ 1 - 0
3rdparty/spirv-tools/source/val/validate_function.cpp

@@ -71,6 +71,7 @@ spv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) {
   }
 
   const std::vector<SpvOp> acceptable = {
+      SpvOpGroupDecorate,
       SpvOpDecorate,
       SpvOpEnqueueKernel,
       SpvOpEntryPoint,