Бранимир Караџић 4 лет назад
Родитель
Сommit
07fade381b
25 измененных файлов с 1243 добавлено и 151 удалено
  1. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  2. 4 1
      3rdparty/spirv-tools/include/generated/core.insts-unified1.inc
  3. 2 0
      3rdparty/spirv-tools/include/generated/enum_string_mapping.inc
  4. 1 0
      3rdparty/spirv-tools/include/generated/extension_enum.inc
  5. 1 1
      3rdparty/spirv-tools/include/generated/generators.inc
  6. 6 1
      3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc
  7. 12 0
      3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp
  8. 2 2
      3rdparty/spirv-tools/source/opt/const_folding_rules.cpp
  9. 6 0
      3rdparty/spirv-tools/source/opt/constants.cpp
  10. 3 0
      3rdparty/spirv-tools/source/opt/constants.h
  11. 437 0
      3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp
  12. 207 0
      3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.h
  13. 91 0
      3rdparty/spirv-tools/source/opt/dataflow.cpp
  14. 148 0
      3rdparty/spirv-tools/source/opt/dataflow.h
  15. 191 108
      3rdparty/spirv-tools/source/opt/debug_info_manager.cpp
  16. 11 5
      3rdparty/spirv-tools/source/opt/debug_info_manager.h
  17. 2 5
      3rdparty/spirv-tools/source/opt/folding_rules.cpp
  18. 27 0
      3rdparty/spirv-tools/source/opt/optimizer.cpp
  19. 1 0
      3rdparty/spirv-tools/source/opt/passes.h
  20. 7 4
      3rdparty/spirv-tools/source/val/validate_builtins.cpp
  21. 4 6
      3rdparty/spirv-tools/source/val/validate_decorations.cpp
  22. 20 0
      3rdparty/spirv-tools/source/val/validate_interfaces.cpp
  23. 6 0
      3rdparty/spirv-tools/source/val/validate_memory.cpp
  24. 42 17
      3rdparty/spirv-tools/source/val/validation_state.cpp
  25. 11 0
      3rdparty/spirv-tools/source/val/validation_state.h

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

@@ -1 +1 @@
-"v2021.3-dev", "SPIRV-Tools v2021.3-dev 25ef0e5c8566c2abe88852e3b72e0facccbbbcb9"
+"v2021.3-dev", "SPIRV-Tools v2021.3-dev 39e3d51fa1194e78df5376072164455270154b39"

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

@@ -44,6 +44,7 @@ static const SpvCapability pygen_variable_caps_Pipes[] = {SpvCapabilityPipes};
 static const SpvCapability pygen_variable_caps_RayQueryKHR[] = {SpvCapabilityRayQueryKHR};
 static const SpvCapability pygen_variable_caps_RayTracingKHR[] = {SpvCapabilityRayTracingKHR};
 static const SpvCapability pygen_variable_caps_RayTracingKHRRayQueryKHR[] = {SpvCapabilityRayTracingKHR, SpvCapabilityRayQueryKHR};
+static const SpvCapability pygen_variable_caps_RayTracingMotionBlurNV[] = {SpvCapabilityRayTracingMotionBlurNV};
 static const SpvCapability pygen_variable_caps_RayTracingNV[] = {SpvCapabilityRayTracingNV};
 static const SpvCapability pygen_variable_caps_RayTracingNVRayTracingKHR[] = {SpvCapabilityRayTracingNV, SpvCapabilityRayTracingKHR};
 static const SpvCapability pygen_variable_caps_RayTracingNVRayTracingKHRRayQueryKHR[] = {SpvCapabilityRayTracingNV, SpvCapabilityRayTracingKHR, SpvCapabilityRayQueryKHR};
@@ -90,6 +91,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shader[] = {spv
 static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing};
 static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing, spvtools::Extension::kSPV_KHR_ray_tracing};
 static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracingSPV_KHR_ray_query[] = {spvtools::Extension::kSPV_NV_ray_tracing, spvtools::Extension::kSPV_KHR_ray_tracing, spvtools::Extension::kSPV_KHR_ray_query};
+static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing_motion_blur[] = {spvtools::Extension::kSPV_NV_ray_tracing_motion_blur};
 static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_image_footprint[] = {spvtools::Extension::kSPV_NV_shader_image_footprint};
 static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_subgroup_partitioned[] = {spvtools::Extension::kSPV_NV_shader_subgroup_partitioned};
 
@@ -482,6 +484,8 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
   {"IgnoreIntersectionNV", SpvOpIgnoreIntersectionNV, 1, pygen_variable_caps_RayTracingNV, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu},
   {"TerminateRayNV", SpvOpTerminateRayNV, 1, pygen_variable_caps_RayTracingNV, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu},
   {"TraceNV", SpvOpTraceNV, 1, pygen_variable_caps_RayTracingNV, 11, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu},
+  {"TraceMotionNV", SpvOpTraceMotionNV, 1, pygen_variable_caps_RayTracingMotionBlurNV, 12, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, 0xffffffffu, 0xffffffffu},
+  {"TraceRayMotionNV", SpvOpTraceRayMotionNV, 1, pygen_variable_caps_RayTracingMotionBlurNV, 12, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, 0xffffffffu, 0xffffffffu},
   {"TypeAccelerationStructureKHR", SpvOpTypeAccelerationStructureKHR, 3, pygen_variable_caps_RayTracingNVRayTracingKHRRayQueryKHR, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 3, pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracingSPV_KHR_ray_query, 0xffffffffu, 0xffffffffu},
   {"TypeAccelerationStructureNV", SpvOpTypeAccelerationStructureNV, 3, pygen_variable_caps_RayTracingNVRayTracingKHRRayQueryKHR, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 3, pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracingSPV_KHR_ray_query, 0xffffffffu, 0xffffffffu},
   {"ExecuteCallableNV", SpvOpExecuteCallableNV, 1, pygen_variable_caps_RayTracingNV, 2, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu},
@@ -693,7 +697,6 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
   {"ArbitraryFloatPowINTEL", SpvOpArbitraryFloatPowINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 10, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"ArbitraryFloatPowRINTEL", SpvOpArbitraryFloatPowRINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 10, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"ArbitraryFloatPowNINTEL", SpvOpArbitraryFloatPowNINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
-  {"ArbitraryFloatPowNINTEL", SpvOpArbitraryFloatPowNINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"LoopControlINTEL", SpvOpLoopControlINTEL, 1, pygen_variable_caps_UnstructuredLoopControlsINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER}, 0, 0, 1, pygen_variable_exts_SPV_INTEL_unstructured_loop_controls, 0xffffffffu, 0xffffffffu},
   {"FixedSqrtINTEL", SpvOpFixedSqrtINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFixedPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"FixedRecipINTEL", SpvOpFixedRecipINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFixedPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},

Разница между файлами не показана из-за своего большого размера
+ 2 - 0
3rdparty/spirv-tools/include/generated/enum_string_mapping.inc


+ 1 - 0
3rdparty/spirv-tools/include/generated/extension_enum.inc

@@ -85,6 +85,7 @@ kSPV_NV_fragment_shader_barycentric,
 kSPV_NV_geometry_shader_passthrough,
 kSPV_NV_mesh_shader,
 kSPV_NV_ray_tracing,
+kSPV_NV_ray_tracing_motion_blur,
 kSPV_NV_sample_mask_override_coverage,
 kSPV_NV_shader_image_footprint,
 kSPV_NV_shader_sm_builtins,

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

@@ -17,7 +17,7 @@
 {16, "X-LEGEND", "Mesa-IR/SPIR-V Translator", "X-LEGEND Mesa-IR/SPIR-V Translator"},
 {17, "Khronos", "SPIR-V Tools Linker", "Khronos SPIR-V Tools Linker"},
 {18, "Wine", "VKD3D Shader Compiler", "Wine VKD3D Shader Compiler"},
-{19, "Clay", "Clay Shader Compiler", "Clay Clay Shader Compiler"},
+{19, "Tellusim", "Clay Shader Compiler", "Tellusim Clay Shader Compiler"},
 {20, "W3C WebGPU Group", "WHLSL Shader Translator", "W3C WebGPU Group WHLSL Shader Translator"},
 {21, "Google", "Clspv", "Google Clspv"},
 {22, "Google", "MLIR SPIR-V Serializer", "Google MLIR SPIR-V Serializer"},

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

@@ -64,12 +64,14 @@ static const SpvCapability pygen_variable_caps_MinLod[] = {SpvCapabilityMinLod};
 static const SpvCapability pygen_variable_caps_MultiView[] = {SpvCapabilityMultiView};
 static const SpvCapability pygen_variable_caps_MultiViewport[] = {SpvCapabilityMultiViewport};
 static const SpvCapability pygen_variable_caps_MultiViewportShaderViewportIndexShaderViewportIndexLayerEXTMeshShadingNV[] = {SpvCapabilityMultiViewport, SpvCapabilityShaderViewportIndex, SpvCapabilityShaderViewportIndexLayerEXT, SpvCapabilityMeshShadingNV};
+static const SpvCapability pygen_variable_caps_OptNoneINTEL[] = {SpvCapabilityOptNoneINTEL};
 static const SpvCapability pygen_variable_caps_PerViewAttributesNVMeshShadingNV[] = {SpvCapabilityPerViewAttributesNV, SpvCapabilityMeshShadingNV};
 static const SpvCapability pygen_variable_caps_PhysicalStorageBufferAddresses[] = {SpvCapabilityPhysicalStorageBufferAddresses};
 static const SpvCapability pygen_variable_caps_Pipes[] = {SpvCapabilityPipes};
 static const SpvCapability pygen_variable_caps_RayQueryKHR[] = {SpvCapabilityRayQueryKHR};
 static const SpvCapability pygen_variable_caps_RayQueryKHRRayTracingKHR[] = {SpvCapabilityRayQueryKHR, SpvCapabilityRayTracingKHR};
 static const SpvCapability pygen_variable_caps_RayTracingKHR[] = {SpvCapabilityRayTracingKHR};
+static const SpvCapability pygen_variable_caps_RayTracingMotionBlurNV[] = {SpvCapabilityRayTracingMotionBlurNV};
 static const SpvCapability pygen_variable_caps_RayTracingNV[] = {SpvCapabilityRayTracingNV};
 static const SpvCapability pygen_variable_caps_RayTracingNVRayTracingKHR[] = {SpvCapabilityRayTracingNV, SpvCapabilityRayTracingKHR};
 static const SpvCapability pygen_variable_caps_RayTraversalPrimitiveCullingKHR[] = {SpvCapabilityRayTraversalPrimitiveCullingKHR};
@@ -199,6 +201,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NV_geometry_shader_pass
 static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shader[] = {spvtools::Extension::kSPV_NV_mesh_shader};
 static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shaderSPV_NV_viewport_array2[] = {spvtools::Extension::kSPV_NV_mesh_shader, spvtools::Extension::kSPV_NV_viewport_array2};
 static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing};
+static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing_motion_blur[] = {spvtools::Extension::kSPV_NV_ray_tracing_motion_blur};
 static const spvtools::Extension pygen_variable_exts_SPV_NV_sample_mask_override_coverage[] = {spvtools::Extension::kSPV_NV_sample_mask_override_coverage};
 static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_image_footprint[] = {spvtools::Extension::kSPV_NV_shader_image_footprint};
 static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_sm_builtins[] = {spvtools::Extension::kSPV_NV_shader_sm_builtins};
@@ -272,7 +275,7 @@ static const spv_operand_desc_t pygen_variable_FunctionControlEntries[] = {
   {"DontInline", 0x0002, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
   {"Pure", 0x0004, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
   {"Const", 0x0008, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
-  {"OptNoneINTEL", 0x10000, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
+  {"OptNoneINTEL", 0x10000, 1, pygen_variable_caps_OptNoneINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
 };
 
 static const spv_operand_desc_t pygen_variable_MemorySemanticsEntries[] = {
@@ -876,6 +879,7 @@ static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = {
   {"HitTNV", 5332, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
   {"HitKindNV", 5333, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
   {"HitKindKHR", 5333, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
+  {"CurrentRayTimeNV", 5334, 1, pygen_variable_caps_RayTracingMotionBlurNV, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, {}, 0xffffffffu, 0xffffffffu},
   {"IncomingRayFlagsNV", 5351, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
   {"IncomingRayFlagsKHR", 5351, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
   {"RayGeometryIndexKHR", 5352, 1, pygen_variable_caps_RayTracingKHR, 1, pygen_variable_exts_SPV_KHR_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
@@ -1060,6 +1064,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
   {"StorageTexelBufferArrayNonUniformIndexing", 5312, 2, pygen_variable_caps_ImageBufferShaderNonUniform, 1, pygen_variable_exts_SPV_EXT_descriptor_indexing, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
   {"StorageTexelBufferArrayNonUniformIndexingEXT", 5312, 2, pygen_variable_caps_ImageBufferShaderNonUniform, 1, pygen_variable_exts_SPV_EXT_descriptor_indexing, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
   {"RayTracingNV", 5340, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
+  {"RayTracingMotionBlurNV", 5341, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, {}, 0xffffffffu, 0xffffffffu},
   {"VulkanMemoryModel", 5345, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
   {"VulkanMemoryModelKHR", 5345, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
   {"VulkanMemoryModelDeviceScope", 5346, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},

+ 12 - 0
3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp

@@ -19,6 +19,7 @@
 #include <ostream>
 #include <string>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 #include "libspirv.hpp"
@@ -27,6 +28,7 @@ namespace spvtools {
 
 namespace opt {
 class Pass;
+struct DescriptorSetAndBinding;
 }
 
 // C++ interface for SPIR-V optimization functionalities. It wraps the context
@@ -854,6 +856,16 @@ Optimizer::PassToken CreateAmdExtToKhrPass();
 // propagated into their final positions.
 Optimizer::PassToken CreateInterpolateFixupPass();
 
+// Creates a convert-to-sampled-image pass to convert images and/or
+// samplers with given pairs of descriptor set and binding to sampled image.
+// If a pair of an image and a sampler have the same pair of descriptor set and
+// binding that is one of the given pairs, they will be converted to a sampled
+// image. In addition, if only an image has the descriptor set and binding that
+// is one of the given pairs, it will be converted to a sampled image as well.
+Optimizer::PassToken CreateConvertToSampledImagePass(
+    const std::vector<opt::DescriptorSetAndBinding>&
+        descriptor_set_binding_pairs);
+
 }  // namespace spvtools
 
 #endif  // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_

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

@@ -1002,7 +1002,7 @@ const analysis::Constant* FoldClamp1(
          "Expecting a GLSLstd450 extended instruction.");
 
   // Make sure all Clamp operands are constants.
-  for (uint32_t i = 1; i < 3; i++) {
+  for (uint32_t i = 1; i < 4; i++) {
     if (constants[i] == nullptr) {
       return nullptr;
     }
@@ -1017,7 +1017,7 @@ const analysis::Constant* FoldClamp1(
                         context);
 }
 
-// Fold a clamp instruction when |x >= min_val|.
+// Fold a clamp instruction when |x <= min_val|.
 const analysis::Constant* FoldClamp2(
     IRContext* context, Instruction* inst,
     const std::vector<const analysis::Constant*>& constants) {

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

@@ -432,6 +432,12 @@ uint32_t ConstantManager::GetSIntConst(int32_t val) {
   return GetDefiningInstruction(c)->result_id();
 }
 
+uint32_t ConstantManager::GetUIntConst(uint32_t val) {
+  Type* uint_type = context()->get_type_mgr()->GetUIntType();
+  const Constant* c = GetConstant(uint_type, {val});
+  return GetDefiningInstruction(c)->result_id();
+}
+
 std::vector<const analysis::Constant*> Constant::GetVectorComponents(
     analysis::ConstantManager* const_mgr) const {
   std::vector<const analysis::Constant*> components;

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

@@ -642,6 +642,9 @@ class ConstantManager {
   // Returns the id of a 32-bit signed integer constant with value |val|.
   uint32_t GetSIntConst(int32_t val);
 
+  // Returns the id of a 32-bit unsigned integer constant with value |val|.
+  uint32_t GetUIntConst(uint32_t val);
+
  private:
   // Creates a Constant instance with the given type and a vector of constant
   // defining words. Returns a unique pointer to the created Constant instance

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

@@ -0,0 +1,437 @@
+// Copyright (c) 2021 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/convert_to_sampled_image_pass.h"
+
+#include <cctype>
+#include <cstring>
+#include <tuple>
+
+#include "source/opt/ir_builder.h"
+#include "source/util/make_unique.h"
+#include "source/util/parse_number.h"
+
+namespace spvtools {
+namespace opt {
+
+using VectorOfDescriptorSetAndBindingPairs =
+    std::vector<DescriptorSetAndBinding>;
+using DescriptorSetBindingToInstruction =
+    ConvertToSampledImagePass::DescriptorSetBindingToInstruction;
+
+namespace {
+
+using utils::ParseNumber;
+
+// Returns true if the given char is ':', '\0' or considered as blank space
+// (i.e.: '\n', '\r', '\v', '\t', '\f' and ' ').
+bool IsSeparator(char ch) {
+  return std::strchr(":\0", ch) || std::isspace(ch) != 0;
+}
+
+// Reads characters starting from |str| until it meets a separator. Parses a
+// number from the characters and stores it into |number|. Returns the pointer
+// to the separator if it succeeds. Otherwise, returns nullptr.
+const char* ParseNumberUntilSeparator(const char* str, uint32_t* number) {
+  const char* number_begin = str;
+  while (!IsSeparator(*str)) str++;
+  const char* number_end = str;
+  std::string number_in_str(number_begin, number_end - number_begin);
+  if (!utils::ParseNumber(number_in_str.c_str(), number)) {
+    // The descriptor set is not a valid uint32 number.
+    return nullptr;
+  }
+  return str;
+}
+
+// Returns id of the image type used for the sampled image type of
+// |sampled_image|.
+uint32_t GetImageTypeOfSampledImage(analysis::TypeManager* type_mgr,
+                                    Instruction* sampled_image) {
+  auto* sampled_image_type =
+      type_mgr->GetType(sampled_image->type_id())->AsSampledImage();
+  return type_mgr->GetTypeInstruction(sampled_image_type->image_type());
+}
+
+// Finds the instruction whose id is |inst_id|. Follows the operand of
+// OpCopyObject recursively if the opcode of the instruction is OpCopyObject
+// and returns the first instruction that does not have OpCopyObject as opcode.
+Instruction* GetNonCopyObjectDef(analysis::DefUseManager* def_use_mgr,
+                                 uint32_t inst_id) {
+  Instruction* inst = def_use_mgr->GetDef(inst_id);
+  while (inst->opcode() == SpvOpCopyObject) {
+    inst_id = inst->GetSingleWordInOperand(0u);
+    inst = def_use_mgr->GetDef(inst_id);
+  }
+  return inst;
+}
+
+}  // namespace
+
+bool ConvertToSampledImagePass::GetDescriptorSetBinding(
+    const Instruction& inst,
+    DescriptorSetAndBinding* descriptor_set_binding) const {
+  auto* decoration_manager = context()->get_decoration_mgr();
+  bool found_descriptor_set_to_convert = false;
+  bool found_binding_to_convert = false;
+  for (auto decorate :
+       decoration_manager->GetDecorationsFor(inst.result_id(), false)) {
+    uint32_t decoration = decorate->GetSingleWordInOperand(1u);
+    if (decoration == SpvDecorationDescriptorSet) {
+      if (found_descriptor_set_to_convert) {
+        assert(false && "A resource has two OpDecorate for the descriptor set");
+        return false;
+      }
+      descriptor_set_binding->descriptor_set =
+          decorate->GetSingleWordInOperand(2u);
+      found_descriptor_set_to_convert = true;
+    } else if (decoration == SpvDecorationBinding) {
+      if (found_binding_to_convert) {
+        assert(false && "A resource has two OpDecorate for the binding");
+        return false;
+      }
+      descriptor_set_binding->binding = decorate->GetSingleWordInOperand(2u);
+      found_binding_to_convert = true;
+    }
+  }
+  return found_descriptor_set_to_convert && found_binding_to_convert;
+}
+
+bool ConvertToSampledImagePass::ShouldResourceBeConverted(
+    const DescriptorSetAndBinding& descriptor_set_binding) const {
+  return descriptor_set_binding_pairs_.find(descriptor_set_binding) !=
+         descriptor_set_binding_pairs_.end();
+}
+
+const analysis::Type* ConvertToSampledImagePass::GetVariableType(
+    const Instruction& variable) const {
+  if (variable.opcode() != SpvOpVariable) return nullptr;
+  auto* type = context()->get_type_mgr()->GetType(variable.type_id());
+  auto* pointer_type = type->AsPointer();
+  if (!pointer_type) return nullptr;
+
+  return pointer_type->pointee_type();
+}
+
+SpvStorageClass ConvertToSampledImagePass::GetStorageClass(
+    const Instruction& variable) const {
+  assert(variable.opcode() == SpvOpVariable);
+  auto* type = context()->get_type_mgr()->GetType(variable.type_id());
+  auto* pointer_type = type->AsPointer();
+  if (!pointer_type) return SpvStorageClassMax;
+
+  return pointer_type->storage_class();
+}
+
+bool ConvertToSampledImagePass::CollectResourcesToConvert(
+    DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler,
+    DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image)
+    const {
+  for (auto& inst : context()->types_values()) {
+    const auto* variable_type = GetVariableType(inst);
+    if (variable_type == nullptr) continue;
+
+    DescriptorSetAndBinding descriptor_set_binding;
+    if (!GetDescriptorSetBinding(inst, &descriptor_set_binding)) continue;
+
+    if (!ShouldResourceBeConverted(descriptor_set_binding)) {
+      continue;
+    }
+
+    if (variable_type->AsImage()) {
+      if (!descriptor_set_binding_pair_to_image
+               ->insert({descriptor_set_binding, &inst})
+               .second) {
+        return false;
+      }
+    } else if (variable_type->AsSampler()) {
+      if (!descriptor_set_binding_pair_to_sampler
+               ->insert({descriptor_set_binding, &inst})
+               .second) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+Pass::Status ConvertToSampledImagePass::Process() {
+  Status status = Status::SuccessWithoutChange;
+
+  DescriptorSetBindingToInstruction descriptor_set_binding_pair_to_sampler,
+      descriptor_set_binding_pair_to_image;
+  if (!CollectResourcesToConvert(&descriptor_set_binding_pair_to_sampler,
+                                 &descriptor_set_binding_pair_to_image)) {
+    return Status::Failure;
+  }
+
+  for (auto& image : descriptor_set_binding_pair_to_image) {
+    status = CombineStatus(
+        status, UpdateImageVariableToSampledImage(image.second, image.first));
+    if (status == Status::Failure) {
+      return status;
+    }
+  }
+
+  for (const auto& sampler : descriptor_set_binding_pair_to_sampler) {
+    // Converting only a Sampler to Sampled Image is not allowed. It must have a
+    // corresponding image to combine the sampler with.
+    auto image_itr = descriptor_set_binding_pair_to_image.find(sampler.first);
+    if (image_itr == descriptor_set_binding_pair_to_image.end() ||
+        image_itr->second == nullptr) {
+      return Status::Failure;
+    }
+
+    status = CombineStatus(
+        status, CheckUsesOfSamplerVariable(sampler.second, image_itr->second));
+    if (status == Status::Failure) {
+      return status;
+    }
+  }
+
+  return status;
+}
+
+void ConvertToSampledImagePass::FindUses(const Instruction* inst,
+                                         std::vector<Instruction*>* uses,
+                                         uint32_t user_opcode) const {
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  def_use_mgr->ForEachUser(inst, [uses, user_opcode, this](Instruction* user) {
+    if (user->opcode() == user_opcode) {
+      uses->push_back(user);
+    } else if (user->opcode() == SpvOpCopyObject) {
+      FindUses(user, uses, user_opcode);
+    }
+  });
+}
+
+void ConvertToSampledImagePass::FindUsesOfImage(
+    const Instruction* image, std::vector<Instruction*>* uses) const {
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  def_use_mgr->ForEachUser(image, [uses, this](Instruction* user) {
+    switch (user->opcode()) {
+      case SpvOpImageFetch:
+      case SpvOpImageRead:
+      case SpvOpImageWrite:
+      case SpvOpImageQueryFormat:
+      case SpvOpImageQueryOrder:
+      case SpvOpImageQuerySizeLod:
+      case SpvOpImageQuerySize:
+      case SpvOpImageQueryLevels:
+      case SpvOpImageQuerySamples:
+      case SpvOpImageSparseFetch:
+        uses->push_back(user);
+      default:
+        break;
+    }
+    if (user->opcode() == SpvOpCopyObject) {
+      FindUsesOfImage(user, uses);
+    }
+  });
+}
+
+Instruction* ConvertToSampledImagePass::CreateImageExtraction(
+    Instruction* sampled_image) {
+  InstructionBuilder builder(
+      context(), sampled_image->NextNode(),
+      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+  return builder.AddUnaryOp(
+      GetImageTypeOfSampledImage(context()->get_type_mgr(), sampled_image),
+      SpvOpImage, sampled_image->result_id());
+}
+
+uint32_t ConvertToSampledImagePass::GetSampledImageTypeForImage(
+    Instruction* image_variable) {
+  const auto* variable_type = GetVariableType(*image_variable);
+  if (variable_type == nullptr) return 0;
+  const auto* image_type = variable_type->AsImage();
+  if (image_type == nullptr) return 0;
+
+  analysis::Image image_type_for_sampled_image(*image_type);
+  analysis::SampledImage sampled_image_type(&image_type_for_sampled_image);
+  return context()->get_type_mgr()->GetTypeInstruction(&sampled_image_type);
+}
+
+Instruction* ConvertToSampledImagePass::UpdateImageUses(
+    Instruction* sampled_image_load) {
+  std::vector<Instruction*> uses_of_load;
+  FindUsesOfImage(sampled_image_load, &uses_of_load);
+  if (uses_of_load.empty()) return nullptr;
+
+  auto* extracted_image = CreateImageExtraction(sampled_image_load);
+  for (auto* user : uses_of_load) {
+    user->SetInOperand(0, {extracted_image->result_id()});
+    context()->get_def_use_mgr()->AnalyzeInstUse(user);
+  }
+  return extracted_image;
+}
+
+bool ConvertToSampledImagePass::
+    IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
+        Instruction* sampled_image_inst,
+        const DescriptorSetAndBinding& descriptor_set_binding) {
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  uint32_t sampler_id = sampled_image_inst->GetSingleWordInOperand(1u);
+  auto* sampler_load = def_use_mgr->GetDef(sampler_id);
+  if (sampler_load->opcode() != SpvOpLoad) return false;
+  auto* sampler = def_use_mgr->GetDef(sampler_load->GetSingleWordInOperand(0u));
+  DescriptorSetAndBinding sampler_descriptor_set_binding;
+  return GetDescriptorSetBinding(*sampler, &sampler_descriptor_set_binding) &&
+         sampler_descriptor_set_binding == descriptor_set_binding;
+}
+
+void ConvertToSampledImagePass::UpdateSampledImageUses(
+    Instruction* image_load, Instruction* image_extraction,
+    const DescriptorSetAndBinding& image_descriptor_set_binding) {
+  std::vector<Instruction*> sampled_image_users;
+  FindUses(image_load, &sampled_image_users, SpvOpSampledImage);
+
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  for (auto* sampled_image_inst : sampled_image_users) {
+    if (IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
+            sampled_image_inst, image_descriptor_set_binding)) {
+      context()->ReplaceAllUsesWith(sampled_image_inst->result_id(),
+                                    image_load->result_id());
+      def_use_mgr->AnalyzeInstUse(image_load);
+      context()->KillInst(sampled_image_inst);
+    } else {
+      if (!image_extraction)
+        image_extraction = CreateImageExtraction(image_load);
+      sampled_image_inst->SetInOperand(0, {image_extraction->result_id()});
+      def_use_mgr->AnalyzeInstUse(sampled_image_inst);
+    }
+  }
+}
+
+void ConvertToSampledImagePass::MoveInstructionNextToType(Instruction* inst,
+                                                          uint32_t type_id) {
+  auto* type_inst = context()->get_def_use_mgr()->GetDef(type_id);
+  inst->SetResultType(type_id);
+  inst->RemoveFromList();
+  inst->InsertAfter(type_inst);
+}
+
+bool ConvertToSampledImagePass::ConvertImageVariableToSampledImage(
+    Instruction* image_variable, uint32_t sampled_image_type_id) {
+  auto* sampled_image_type =
+      context()->get_type_mgr()->GetType(sampled_image_type_id);
+  if (sampled_image_type == nullptr) return false;
+  auto storage_class = GetStorageClass(*image_variable);
+  if (storage_class == SpvStorageClassMax) return false;
+  analysis::Pointer sampled_image_pointer(sampled_image_type, storage_class);
+
+  // Make sure |image_variable| is behind its type i.e., avoid the forward
+  // reference.
+  uint32_t type_id =
+      context()->get_type_mgr()->GetTypeInstruction(&sampled_image_pointer);
+  MoveInstructionNextToType(image_variable, type_id);
+  return true;
+}
+
+Pass::Status ConvertToSampledImagePass::UpdateImageVariableToSampledImage(
+    Instruction* image_variable,
+    const DescriptorSetAndBinding& descriptor_set_binding) {
+  std::vector<Instruction*> image_variable_loads;
+  FindUses(image_variable, &image_variable_loads, SpvOpLoad);
+  if (image_variable_loads.empty()) return Status::SuccessWithoutChange;
+
+  const uint32_t sampled_image_type_id =
+      GetSampledImageTypeForImage(image_variable);
+  if (!sampled_image_type_id) return Status::Failure;
+
+  for (auto* load : image_variable_loads) {
+    load->SetResultType(sampled_image_type_id);
+    auto* image_extraction = UpdateImageUses(load);
+    UpdateSampledImageUses(load, image_extraction, descriptor_set_binding);
+  }
+
+  return ConvertImageVariableToSampledImage(image_variable,
+                                            sampled_image_type_id)
+             ? Status::SuccessWithChange
+             : Status::Failure;
+}
+
+bool ConvertToSampledImagePass::DoesSampledImageReferenceImage(
+    Instruction* sampled_image_inst, Instruction* image_variable) {
+  if (sampled_image_inst->opcode() != SpvOpSampledImage) return false;
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  auto* image_load = GetNonCopyObjectDef(
+      def_use_mgr, sampled_image_inst->GetSingleWordInOperand(0u));
+  if (image_load->opcode() != SpvOpLoad) return false;
+  auto* image =
+      GetNonCopyObjectDef(def_use_mgr, image_load->GetSingleWordInOperand(0u));
+  return image->opcode() == SpvOpVariable &&
+         image->result_id() == image_variable->result_id();
+}
+
+Pass::Status ConvertToSampledImagePass::CheckUsesOfSamplerVariable(
+    const Instruction* sampler_variable,
+    Instruction* image_to_be_combined_with) {
+  if (image_to_be_combined_with == nullptr) return Status::Failure;
+
+  std::vector<Instruction*> sampler_variable_loads;
+  FindUses(sampler_variable, &sampler_variable_loads, SpvOpLoad);
+  for (auto* load : sampler_variable_loads) {
+    std::vector<Instruction*> sampled_image_users;
+    FindUses(load, &sampled_image_users, SpvOpSampledImage);
+    for (auto* sampled_image_inst : sampled_image_users) {
+      if (!DoesSampledImageReferenceImage(sampled_image_inst,
+                                          image_to_be_combined_with)) {
+        return Status::Failure;
+      }
+    }
+  }
+  return Status::SuccessWithoutChange;
+}
+
+std::unique_ptr<VectorOfDescriptorSetAndBindingPairs>
+ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
+    const char* str) {
+  if (!str) return nullptr;
+
+  auto descriptor_set_binding_pairs =
+      MakeUnique<VectorOfDescriptorSetAndBindingPairs>();
+
+  while (std::isspace(*str)) str++;  // skip leading spaces.
+
+  // The parsing loop, break when points to the end.
+  while (*str) {
+    // Parse the descriptor set.
+    uint32_t descriptor_set = 0;
+    str = ParseNumberUntilSeparator(str, &descriptor_set);
+    if (str == nullptr) return nullptr;
+
+    // Find the ':', spaces between the descriptor set and the ':' are not
+    // allowed.
+    if (*str++ != ':') {
+      // ':' not found
+      return nullptr;
+    }
+
+    // Parse the binding.
+    uint32_t binding = 0;
+    str = ParseNumberUntilSeparator(str, &binding);
+    if (str == nullptr) return nullptr;
+
+    descriptor_set_binding_pairs->push_back({descriptor_set, binding});
+
+    // Skip trailing spaces.
+    while (std::isspace(*str)) str++;
+  }
+
+  return descriptor_set_binding_pairs;
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 207 - 0
3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.h

@@ -0,0 +1,207 @@
+// Copyright (c) 2021 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_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
+#define SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
+
+#include <memory>
+#include <unordered_set>
+#include <utility>
+
+#include "source/opt/pass.h"
+#include "source/opt/types.h"
+
+namespace spvtools {
+namespace opt {
+
+// A struct for a pair of descriptor set and binding.
+struct DescriptorSetAndBinding {
+  uint32_t descriptor_set;
+  uint32_t binding;
+
+  bool operator==(const DescriptorSetAndBinding& descriptor_set_binding) const {
+    return descriptor_set_binding.descriptor_set == descriptor_set &&
+           descriptor_set_binding.binding == binding;
+  }
+};
+
+// See optimizer.hpp for documentation.
+class ConvertToSampledImagePass : public Pass {
+ public:
+  // Hashing functor for the pair of descriptor set and binding.
+  struct DescriptorSetAndBindingHash {
+    size_t operator()(
+        const DescriptorSetAndBinding& descriptor_set_binding) const {
+      return std::hash<uint32_t>()(descriptor_set_binding.descriptor_set) ^
+             std::hash<uint32_t>()(descriptor_set_binding.binding);
+    }
+  };
+
+  using SetOfDescriptorSetAndBindingPairs =
+      std::unordered_set<DescriptorSetAndBinding, DescriptorSetAndBindingHash>;
+  using DescriptorSetBindingToInstruction =
+      std::unordered_map<DescriptorSetAndBinding, Instruction*,
+                         DescriptorSetAndBindingHash>;
+
+  explicit ConvertToSampledImagePass(
+      const std::vector<DescriptorSetAndBinding>& descriptor_set_binding_pairs)
+      : descriptor_set_binding_pairs_(descriptor_set_binding_pairs.begin(),
+                                      descriptor_set_binding_pairs.end()) {}
+
+  const char* name() const override { return "convert-to-sampled-image"; }
+  Status Process() override;
+
+  // Parses the given null-terminated C string to get a vector of descriptor set
+  // and binding pairs. Returns a unique pointer to the vector of descriptor set
+  // and binding pairs built from the given |str| on success. Returns a nullptr
+  // if the given string is not valid for building the vector of pairs.
+  // A valid string for building the vector of pairs should follow the rule
+  // below:
+  //
+  //  "<descriptor set>:<binding> <descriptor set>:<binding> ..."
+  //  Example:
+  //    "3:5 2:1 0:4"
+  //
+  //  Entries are separated with blank spaces (i.e.:' ', '\n', '\r', '\t',
+  //  '\f', '\v'). Each entry corresponds to a descriptor set and binding pair.
+  //  Multiple spaces between, before or after entries are allowed. However,
+  //  spaces are not allowed within a descriptor set or binding.
+  //
+  //  In each entry, the descriptor set and binding are separated by ':'.
+  //  Missing ':' in any entry is invalid. And it is invalid to have blank
+  //  spaces in between the descriptor set and ':' or ':' and the binding.
+  //
+  //  <descriptor set>: the descriptor set.
+  //    The text must represent a valid uint32_t number.
+  //
+  //  <binding>: the binding.
+  //    The text must represent a valid uint32_t number.
+  static std::unique_ptr<std::vector<DescriptorSetAndBinding>>
+  ParseDescriptorSetBindingPairsString(const char* str);
+
+ private:
+  // Collects resources to convert to sampled image and saves them in
+  // |descriptor_set_binding_pair_to_sampler| if the resource is a sampler and
+  // saves them in |descriptor_set_binding_pair_to_image| if the resource is an
+  // image. Returns false if two samplers or two images have the same descriptor
+  // set and binding. Otherwise, returns true.
+  bool CollectResourcesToConvert(
+      DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler,
+      DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image)
+      const;
+
+  // Finds an OpDecorate with DescriptorSet decorating |inst| and another
+  // OpDecorate with Binding decorating |inst|. Stores the descriptor set and
+  // binding in |descriptor_set_binding|. Returns whether it successfully finds
+  // the descriptor set and binding or not.
+  bool GetDescriptorSetBinding(
+      const Instruction& inst,
+      DescriptorSetAndBinding* descriptor_set_binding) const;
+
+  // Returns whether |descriptor_set_binding| is a pair of a descriptor set
+  // and a binding that we have to convert resources with it to a sampled image
+  // or not.
+  bool ShouldResourceBeConverted(
+      const DescriptorSetAndBinding& descriptor_set_binding) const;
+
+  // Returns the pointee type of the type of variable |variable|. If |variable|
+  // is not an OpVariable instruction, just returns nullptr.
+  const analysis::Type* GetVariableType(const Instruction& variable) const;
+
+  // Returns the storage class of |variable|.
+  SpvStorageClass GetStorageClass(const Instruction& variable) const;
+
+  // Finds |inst|'s users whose opcode is |user_opcode| or users of OpCopyObject
+  // instructions of |inst| whose opcode is |user_opcode| and puts them in
+  // |uses|.
+  void FindUses(const Instruction* inst, std::vector<Instruction*>* uses,
+                uint32_t user_opcode) const;
+
+  // Finds OpImage* instructions using |image| or OpCopyObject instructions that
+  // copy |image| and puts them in |uses|.
+  void FindUsesOfImage(const Instruction* image,
+                       std::vector<Instruction*>* uses) const;
+
+  // Creates an OpImage instruction that extracts the image from the sampled
+  // image |sampled_image|.
+  Instruction* CreateImageExtraction(Instruction* sampled_image);
+
+  // Converts |image_variable| whose type is an image pointer to sampled image
+  // type. Updates users of |image_variable| accordingly. If some instructions
+  // e.g., OpImageRead use |image_variable| as an Image operand, creates an
+  // image extracted from the sampled image using OpImage and replace the Image
+  // operands of the users with the extracted image. If some OpSampledImage
+  // instructions use |image_variable| and sampler whose descriptor set and
+  // binding are the same with |image_variable|, just combines |image_variable|
+  // and the sampler to a sampled image.
+  Pass::Status UpdateImageVariableToSampledImage(
+      Instruction* image_variable,
+      const DescriptorSetAndBinding& descriptor_set_binding);
+
+  // Returns the id of type sampled image type whose image type is the one of
+  // |image_variable|.
+  uint32_t GetSampledImageTypeForImage(Instruction* image_variable);
+
+  // Moves |inst| next to the OpType* instruction with |type_id|.
+  void MoveInstructionNextToType(Instruction* inst, uint32_t type_id);
+
+  // Converts |image_variable| whose type is an image pointer to sampled image
+  // with the type id |sampled_image_type_id|. Returns whether it successfully
+  // converts the type of |image_variable| or not.
+  bool ConvertImageVariableToSampledImage(Instruction* image_variable,
+                                          uint32_t sampled_image_type_id);
+
+  // Replaces |sampled_image_load| instruction used by OpImage* with the image
+  // extracted from |sampled_image_load|. Returns the extracted image or nullptr
+  // if it does not have uses.
+  Instruction* UpdateImageUses(Instruction* sampled_image_load);
+
+  // Returns true if the sampler of |sampled_image_inst| is decorated by a
+  // descriptor set and a binding |descriptor_set_binding|.
+  bool IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
+      Instruction* sampled_image_inst,
+      const DescriptorSetAndBinding& descriptor_set_binding);
+
+  // Replaces OpSampledImage instructions using |image_load| with |image_load|
+  // if the sampler of the OpSampledImage instruction has descriptor set and
+  // binding |image_descriptor_set_binding|. Otherwise, replaces |image_load|
+  // with |image_extraction|.
+  void UpdateSampledImageUses(
+      Instruction* image_load, Instruction* image_extraction,
+      const DescriptorSetAndBinding& image_descriptor_set_binding);
+
+  // Checks the uses of |sampler_variable|. When a sampler is used by
+  // OpSampledImage instruction, the corresponding image must be
+  // |image_to_be_combined_with| that should be already converted to a sampled
+  // image by UpdateImageVariableToSampledImage() method.
+  Pass::Status CheckUsesOfSamplerVariable(
+      const Instruction* sampler_variable,
+      Instruction* image_to_be_combined_with);
+
+  // Returns true if Image operand of |sampled_image_inst| is the image of
+  // |image_variable|.
+  bool DoesSampledImageReferenceImage(Instruction* sampled_image_inst,
+                                      Instruction* image_variable);
+
+  // A set of pairs of descriptor set and binding. If an image and/or a sampler
+  // have a pair of descriptor set and binding that is an element of
+  // |descriptor_set_binding_pairs_|, they/it will be converted to a sampled
+  // image by this pass.
+  const SetOfDescriptorSetAndBindingPairs descriptor_set_binding_pairs_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_

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

@@ -0,0 +1,91 @@
+// Copyright (c) 2021 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/dataflow.h"
+
+#include <algorithm>
+#include <cstdint>
+
+namespace spvtools {
+namespace opt {
+
+bool DataFlowAnalysis::Enqueue(Instruction* inst) {
+  bool& is_enqueued = on_worklist_[inst];
+  if (is_enqueued) return false;
+  is_enqueued = true;
+  worklist_.push(inst);
+  return true;
+}
+
+DataFlowAnalysis::VisitResult DataFlowAnalysis::RunOnce(
+    Function* function, bool is_first_iteration) {
+  InitializeWorklist(function, is_first_iteration);
+  VisitResult ret = VisitResult::kResultFixed;
+  while (!worklist_.empty()) {
+    Instruction* top = worklist_.front();
+    worklist_.pop();
+    on_worklist_[top] = false;
+    VisitResult result = Visit(top);
+    if (result == VisitResult::kResultChanged) {
+      EnqueueSuccessors(top);
+      ret = VisitResult::kResultChanged;
+    }
+  }
+  return ret;
+}
+
+void DataFlowAnalysis::Run(Function* function) {
+  VisitResult result = RunOnce(function, true);
+  while (result == VisitResult::kResultChanged) {
+    result = RunOnce(function, false);
+  }
+}
+
+void ForwardDataFlowAnalysis::InitializeWorklist(Function* function,
+                                                 bool /*is_first_iteration*/) {
+  context().cfg()->ForEachBlockInReversePostOrder(
+      function->entry().get(), [this](BasicBlock* bb) {
+        if (label_position_ == LabelPosition::kLabelsOnly) {
+          Enqueue(bb->GetLabelInst());
+          return;
+        }
+        if (label_position_ == LabelPosition::kLabelsAtBeginning) {
+          Enqueue(bb->GetLabelInst());
+        }
+        for (Instruction& inst : *bb) {
+          Enqueue(&inst);
+        }
+        if (label_position_ == LabelPosition::kLabelsAtEnd) {
+          Enqueue(bb->GetLabelInst());
+        }
+      });
+}
+
+void ForwardDataFlowAnalysis::EnqueueUsers(Instruction* inst) {
+  context().get_def_use_mgr()->ForEachUser(
+      inst, [this](Instruction* user) { Enqueue(user); });
+}
+
+void ForwardDataFlowAnalysis::EnqueueBlockSuccessors(Instruction* inst) {
+  if (inst->opcode() != SpvOpLabel) return;
+  context()
+      .cfg()
+      ->block(inst->result_id())
+      ->ForEachSuccessorLabel([this](uint32_t* label) {
+        Enqueue(context().cfg()->block(*label)->GetLabelInst());
+      });
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 148 - 0
3rdparty/spirv-tools/source/opt/dataflow.h

@@ -0,0 +1,148 @@
+// Copyright (c) 2021 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_DATAFLOW_H_
+#define SOURCE_OPT_DATAFLOW_H_
+
+#include <queue>
+#include <unordered_map>
+#include <vector>
+
+#include "source/opt/instruction.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace opt {
+
+// Generic data-flow analysis.
+// Maintains a worklist of instructions to process and processes them in a
+// specified order. See also ForwardDataFlowAnalysis, which is specialized for
+// forward data-flow analysis.
+class DataFlowAnalysis {
+ public:
+  // The result of a |Visit| operation on an instruction.
+  // This is used to determine when analysis has reached a fixpoint.
+  enum class VisitResult {
+    // The analysis result for this instruction has changed.
+    // This means that any instructions that depend on it (its successors) must
+    // be recomputed.
+    kResultChanged,
+    // The analysis result for this instruction has not changed.
+    // When all visit operations return |kResultFixed|, the analysis has reached
+    // a fixpoint (converged).
+    kResultFixed,
+  };
+
+  virtual ~DataFlowAnalysis() {}
+
+  // Run this analysis on a given function.
+  // For analyses which work interprocedurally, |function| may be ignored.
+  void Run(Function* function);
+
+ protected:
+  DataFlowAnalysis(IRContext& context) : context_(context) {}
+
+  // Initialize the worklist for a given function.
+  // |is_first_iteration| is true on the first call to |Run| and false
+  // afterwards. All subsequent runs are only necessary to check if the analysis
+  // has converged; if |EnqueueSuccessors| is complete, |InitializeWorklist|
+  // should do nothing after the first iteration.
+  virtual void InitializeWorklist(Function* function,
+                                  bool is_first_iteration) = 0;
+
+  // Enqueues the successors (instructions which use the analysis result) of
+  // |inst|. This is not required to be complete, but convergence is faster when
+  // it is. This is called whenever |Visit| returns |kResultChanged|.
+  virtual void EnqueueSuccessors(Instruction* inst) = 0;
+
+  // Visits the given instruction, recomputing the analysis result. This is
+  // called once per instruction queued in |InitializeWorklist| and afterward
+  // when a predecessor is changed, through |EnqueueSuccessors|.
+  virtual VisitResult Visit(Instruction* inst) = 0;
+
+  // Enqueues the given instruction to be visited. Ignored if already in the
+  // worklist.
+  bool Enqueue(Instruction* inst);
+
+  IRContext& context() { return context_; }
+
+ private:
+  // Runs one pass, calling |InitializeWorklist| and then iterating through the
+  // worklist until all fixed.
+  VisitResult RunOnce(Function* function, bool is_first_iteration);
+
+  IRContext& context_;
+  std::unordered_map<Instruction*, bool> on_worklist_;
+  // The worklist, which contains the list of instructions to be visited.
+  //
+  // The choice of data structure was influenced by the data in "Iterative
+  // Data-flow Analysis, Revisited" (Cooper et al, 2002).
+  // https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.125.1549&rep=rep1&type=pdf
+  // The paper shows that the overall performance benefit of a priority queue
+  // over a regular queue or stack is relatively small (or negative).
+  //
+  // A queue has the advantage that nodes are visited in the same order they are
+  // enqueued, which relieves the analysis from inserting nodes "backwards", for
+  // example in worklist initialization. Also, as the paper claims that sorting
+  // successors does not improve runtime, we can use a single queue which is
+  // modified during iteration.
+  std::queue<Instruction*> worklist_;
+};
+
+// A generic data flow analysis, specialized for forward analysis.
+class ForwardDataFlowAnalysis : public DataFlowAnalysis {
+ public:
+  // Indicates where labels should be in the worklist RPO ordering.
+  enum class LabelPosition {
+    // Labels should be placed at the beginning of their blocks.
+    kLabelsAtBeginning,
+    // Labels should be placed at the end of their blocks.
+    kLabelsAtEnd,
+    // Labels should not be in the worklist.
+    kNoLabels,
+    // Only labels should be placed in the worklist.
+    kLabelsOnly,
+  };
+
+  ForwardDataFlowAnalysis(IRContext& context, LabelPosition label_position)
+      : DataFlowAnalysis(context), label_position_(label_position) {}
+
+ protected:
+  // Initializes the worklist in reverse postorder, regardless of
+  // |is_first_iteration|. Labels are placed according to the label position
+  // specified in the constructor.
+  void InitializeWorklist(Function* function, bool is_first_iteration) override;
+
+  // Enqueues the users and block successors of the given instruction.
+  // See |EnqueueUsers| and |EnqueueBlockSuccessors|.
+  void EnqueueSuccessors(Instruction* inst) override {
+    EnqueueUsers(inst);
+    EnqueueBlockSuccessors(inst);
+  }
+
+  // Enqueues the users of the given instruction.
+  void EnqueueUsers(Instruction* inst);
+
+  // Enqueues the labels of the successors of the block corresponding to the
+  // given label instruction. Does nothing for other instructions.
+  void EnqueueBlockSuccessors(Instruction* inst);
+
+ private:
+  LabelPosition label_position_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_DATAFLOW_H_

+ 191 - 108
3rdparty/spirv-tools/source/opt/debug_info_manager.cpp

@@ -18,12 +18,15 @@
 
 #include "source/opt/ir_context.h"
 
-// Constants for OpenCL.DebugInfo.100 extension instructions.
+// Constants for OpenCL.DebugInfo.100 & NonSemantic.Vulkan.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;
+static const uint32_t kDebugFunctionDefinitionOperandDebugFunctionIndex = 4;
+static const uint32_t kDebugFunctionDefinitionOperandOpFunctionIndex = 5;
 static const uint32_t kDebugFunctionOperandParentIndex = 9;
 static const uint32_t kDebugTypeCompositeOperandParentIndex = 9;
 static const uint32_t kDebugLexicalBlockOperandParentIndex = 7;
@@ -46,8 +49,8 @@ namespace {
 
 void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) {
   assert(dbg_inlined_at);
-  assert(dbg_inlined_at->GetOpenCL100DebugOpcode() ==
-         OpenCLDebugInfo100DebugInlinedAt);
+  assert(dbg_inlined_at->GetCommonDebugOpcode() ==
+         CommonDebugInfoDebugInlinedAt);
   if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex) {
     dbg_inlined_at->AddOperand(
         {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inlined_operand}});
@@ -59,8 +62,8 @@ void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) {
 
 uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) {
   assert(dbg_inlined_at);
-  assert(dbg_inlined_at->GetOpenCL100DebugOpcode() ==
-         OpenCLDebugInfo100DebugInlinedAt);
+  assert(dbg_inlined_at->GetCommonDebugOpcode() ==
+         CommonDebugInfoDebugInlinedAt);
   if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex)
     return kNoInlinedAt;
   return dbg_inlined_at->GetSingleWordOperand(
@@ -68,8 +71,7 @@ uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) {
 }
 
 bool IsEmptyDebugExpression(Instruction* instr) {
-  return instr->GetOpenCL100DebugOpcode() ==
-             OpenCLDebugInfo100DebugExpression &&
+  return (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression) &&
          instr->NumOperands() == kDebugExpressOperandOperationIndex;
 }
 
@@ -79,43 +81,63 @@ DebugInfoManager::DebugInfoManager(IRContext* c) : context_(c) {
   AnalyzeDebugInsts(*c->module());
 }
 
+uint32_t DebugInfoManager::GetDbgSetImportId() {
+  uint32_t setId =
+      context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo();
+  if (setId == 0) {
+    setId =
+        context()->get_feature_mgr()->GetExtInstImportId_Vulkan100DebugInfo();
+  }
+  return setId;
+}
+
 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");
+  assert(inst->NumInOperands() != 0 &&
+         (GetDbgSetImportId() == 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);
-  // Do not register function that has been optimized away
-  auto fn_inst = GetDbgInst(fn_id);
-  if (fn_inst != nullptr) {
-    assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() ==
-           OpenCLDebugInfo100DebugInfoNone);
-    return;
+  if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
+    auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
+    // Do not register function that has been optimized away.
+    auto fn_inst = GetDbgInst(fn_id);
+    if (fn_inst != nullptr) {
+      assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() ==
+             OpenCLDebugInfo100DebugInfoNone);
+      return;
+    }
+    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;
+  } else if (inst->GetVulkan100DebugOpcode() ==
+             NonSemanticVulkanDebugInfo100DebugFunctionDefinition) {
+    auto fn_id = inst->GetSingleWordOperand(
+        kDebugFunctionDefinitionOperandOpFunctionIndex);
+    auto fn_inst = GetDbgInst(inst->GetSingleWordOperand(
+        kDebugFunctionDefinitionOperandDebugFunctionIndex));
+    assert(fn_inst && fn_inst->GetVulkan100DebugOpcode() ==
+                          NonSemanticVulkanDebugInfo100DebugFunction);
+    assert(fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() &&
+           "Register DebugFunctionDefinition for a function that already has "
+           "DebugFunctionDefinition");
+    fn_id_to_dbg_fn_[fn_id] = fn_inst;
+  } else {
+    assert(false && "inst is not a DebugFunction");
   }
-  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;
 }
 
 void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
                                           Instruction* dbg_declare) {
-  assert(dbg_declare->GetOpenCL100DebugOpcode() ==
-             OpenCLDebugInfo100DebugDeclare ||
-         dbg_declare->GetOpenCL100DebugOpcode() ==
-             OpenCLDebugInfo100DebugValue);
+  assert(dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare ||
+         dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugValue);
   auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_id);
   if (dbg_decl_itr == var_id_to_dbg_decl_.end()) {
     var_id_to_dbg_decl_[var_id] = {dbg_declare};
@@ -126,27 +148,36 @@ void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
 
 uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
                                                 const DebugScope& scope) {
-  if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() ==
-      0)
-    return kNoInlinedAt;
+  uint32_t setId = GetDbgSetImportId();
+
+  if (setId == 0) return kNoInlinedAt;
+
+  spv_operand_type_t line_number_type =
+      spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER;
+
+  // In NonSemantic.Vulkan.DebugInfo.100, all constants are IDs of OpConstant,
+  // not literals.
+  if (setId ==
+      context()->get_feature_mgr()->GetExtInstImportId_Vulkan100DebugInfo())
+    line_number_type = spv_operand_type_t::SPV_OPERAND_TYPE_ID;
 
   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();
+    CommonDebugInfoInstructions debug_opcode =
+        lexical_scope_inst->GetCommonDebugOpcode();
     switch (debug_opcode) {
-      case OpenCLDebugInfo100DebugFunction:
+      case CommonDebugInfoDebugFunction:
         line_number = lexical_scope_inst->GetSingleWordOperand(
             kLineOperandIndexDebugFunction);
         break;
-      case OpenCLDebugInfo100DebugLexicalBlock:
+      case CommonDebugInfoDebugLexicalBlock:
         line_number = lexical_scope_inst->GetSingleWordOperand(
             kLineOperandIndexDebugLexicalBlock);
         break;
-      case OpenCLDebugInfo100DebugTypeComposite:
-      case OpenCLDebugInfo100DebugCompilationUnit:
+      case CommonDebugInfoDebugTypeComposite:
+      case CommonDebugInfoDebugCompilationUnit:
         assert(false &&
                "DebugTypeComposite and DebugCompilationUnit are lexical "
                "scopes, but we inline functions into a function or a block "
@@ -161,6 +192,13 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
     }
   } else {
     line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex);
+
+    // If we need the line number as an ID, generate that constant now.
+    if (line_number_type == spv_operand_type_t::SPV_OPERAND_TYPE_ID) {
+      uint32_t line_id =
+          context()->get_constant_mgr()->GetUIntConst(line_number);
+      line_number = line_id;
+    }
   }
 
   uint32_t result_id = context()->TakeNextId();
@@ -168,13 +206,10 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
       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_ID, {setId}},
           {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}},
+           {static_cast<uint32_t>(CommonDebugInfoDebugInlinedAt)}},
+          {line_number_type, {line_number}},
           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetLexicalScope()}},
       }));
   // |scope| already has DebugInlinedAt. We put the existing DebugInlinedAt
@@ -257,19 +292,34 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
   if (deref_operation_ != nullptr) return deref_operation_;
 
   uint32_t result_id = context()->TakeNextId();
-  std::unique_ptr<Instruction> deref_operation(new Instruction(
-      context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
-      result_id,
-      {
-          {SPV_OPERAND_TYPE_ID,
-           {context()
-                ->get_feature_mgr()
-                ->GetExtInstImportId_OpenCL100DebugInfo()}},
-          {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
-           {static_cast<uint32_t>(OpenCLDebugInfo100DebugOperation)}},
-          {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION,
-           {static_cast<uint32_t>(OpenCLDebugInfo100Deref)}},
-      }));
+  std::unique_ptr<Instruction> deref_operation;
+
+  if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
+    deref_operation = std::unique_ptr<Instruction>(new Instruction(
+        context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
+        result_id,
+        {
+            {SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
+            {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
+             {static_cast<uint32_t>(OpenCLDebugInfo100DebugOperation)}},
+            {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION,
+             {static_cast<uint32_t>(OpenCLDebugInfo100Deref)}},
+        }));
+  } else {
+    uint32_t deref_id = context()->get_constant_mgr()->GetUIntConst(
+        NonSemanticVulkanDebugInfo100Deref);
+
+    deref_operation = std::unique_ptr<Instruction>(
+        new Instruction(context(), SpvOpExtInst,
+                        context()->get_type_mgr()->GetVoidTypeId(), result_id,
+                        {
+                            {SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
+                            {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
+                             {static_cast<uint32_t>(
+                                 NonSemanticVulkanDebugInfo100DebugOperation)}},
+                            {SPV_OPERAND_TYPE_ID, {deref_id}},
+                        }));
+  }
 
   // Add to the front of |ext_inst_debuginfo_|.
   deref_operation_ =
@@ -283,8 +333,7 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
 }
 
 Instruction* DebugInfoManager::DerefDebugExpression(Instruction* dbg_expr) {
-  assert(dbg_expr->GetOpenCL100DebugOpcode() ==
-         OpenCLDebugInfo100DebugExpression);
+  assert(dbg_expr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression);
   std::unique_ptr<Instruction> deref_expr(dbg_expr->Clone(context()));
   deref_expr->SetResultId(context()->TakeNextId());
   deref_expr->InsertOperand(
@@ -306,12 +355,9 @@ Instruction* DebugInfoManager::GetDebugInfoNone() {
       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_ID, {GetDbgSetImportId()}},
           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
-           {static_cast<uint32_t>(OpenCLDebugInfo100DebugInfoNone)}},
+           {static_cast<uint32_t>(CommonDebugInfoDebugInfoNone)}},
       }));
 
   // Add to the front of |ext_inst_debuginfo_|.
@@ -333,12 +379,9 @@ Instruction* DebugInfoManager::GetEmptyDebugExpression() {
       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_ID, {GetDbgSetImportId()}},
           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
-           {static_cast<uint32_t>(OpenCLDebugInfo100DebugExpression)}},
+           {static_cast<uint32_t>(CommonDebugInfoDebugExpression)}},
       }));
 
   // Add to the front of |ext_inst_debuginfo_|.
@@ -355,8 +398,7 @@ Instruction* DebugInfoManager::GetEmptyDebugExpression() {
 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) {
+  if (inlined_at->GetCommonDebugOpcode() != CommonDebugInfoDebugInlinedAt) {
     return nullptr;
   }
   return inlined_at;
@@ -403,23 +445,23 @@ bool DebugInfoManager::KillDebugDeclares(uint32_t variable_id) {
 uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) {
   auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope);
   assert(dbg_scope_itr != id_to_dbg_inst_.end());
-  OpenCLDebugInfo100Instructions debug_opcode =
-      dbg_scope_itr->second->GetOpenCL100DebugOpcode();
+  CommonDebugInfoInstructions debug_opcode =
+      dbg_scope_itr->second->GetCommonDebugOpcode();
   uint32_t parent_scope = kNoDebugScope;
   switch (debug_opcode) {
-    case OpenCLDebugInfo100DebugFunction:
+    case CommonDebugInfoDebugFunction:
       parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
           kDebugFunctionOperandParentIndex);
       break;
-    case OpenCLDebugInfo100DebugLexicalBlock:
+    case CommonDebugInfoDebugLexicalBlock:
       parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
           kDebugLexicalBlockOperandParentIndex);
       break;
-    case OpenCLDebugInfo100DebugTypeComposite:
+    case CommonDebugInfoDebugTypeComposite:
       parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
           kDebugTypeCompositeOperandParentIndex);
       break;
-    case OpenCLDebugInfo100DebugCompilationUnit:
+    case CommonDebugInfoDebugCompilationUnit:
       // DebugCompilationUnit does not have a parent scope.
       break;
     default:
@@ -513,8 +555,7 @@ Instruction* DebugInfoManager::AddDebugValueForDecl(
 
   std::unique_ptr<Instruction> dbg_val(dbg_decl->Clone(context()));
   dbg_val->SetResultId(context()->TakeNextId());
-  dbg_val->SetInOperand(kExtInstInstructionInIdx,
-                        {OpenCLDebugInfo100DebugValue});
+  dbg_val->SetInOperand(kExtInstInstructionInIdx, {CommonDebugInfoDebugValue});
   dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id});
   dbg_val->SetOperand(kDebugValueOperandExpressionIndex,
                       {GetEmptyDebugExpression()->result_id()});
@@ -532,9 +573,20 @@ Instruction* DebugInfoManager::AddDebugValueForDecl(
   return added_dbg_val;
 }
 
+uint32_t DebugInfoManager::GetVulkanDebugOperation(Instruction* inst) {
+  assert(inst->GetVulkan100DebugOpcode() ==
+             NonSemanticVulkanDebugInfo100DebugOperation &&
+         "inst must be Vulkan DebugOperation");
+  return context()
+      ->get_constant_mgr()
+      ->GetConstantFromInst(context()->get_def_use_mgr()->GetDef(
+          inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex)))
+      ->GetU32();
+}
+
 uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
     Instruction* inst) {
-  if (inst->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugValue) return 0;
+  if (inst->GetCommonDebugOpcode() != CommonDebugInfoDebugValue) return 0;
 
   auto* expr =
       GetDbgInst(inst->GetSingleWordOperand(kDebugValueOperandExpressionIndex));
@@ -544,9 +596,19 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
   auto* operation = GetDbgInst(
       expr->GetSingleWordOperand(kDebugExpressOperandOperationIndex));
   if (operation == nullptr) return 0;
-  if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) !=
-      OpenCLDebugInfo100Deref) {
-    return 0;
+
+  // OpenCL.DebugInfo.100 contains a literal for the operation, Vulkan uses an
+  // OpConstant.
+  if (inst->IsOpenCL100DebugInstr()) {
+    if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) !=
+        OpenCLDebugInfo100Deref) {
+      return 0;
+    }
+  } else {
+    uint32_t operation_const = GetVulkanDebugOperation(operation);
+    if (operation_const != NonSemanticVulkanDebugInfo100Deref) {
+      return 0;
+    }
   }
 
   uint32_t var_id =
@@ -567,8 +629,8 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
 }
 
 bool DebugInfoManager::IsDebugDeclare(Instruction* instr) {
-  if (!instr->IsOpenCL100DebugInstr()) return false;
-  return instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare ||
+  if (!instr->IsCommonDebugInstr()) return false;
+  return instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare ||
          GetVariableIdOfDebugValueUsedForDeclare(instr) != 0;
 }
 
@@ -615,14 +677,13 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
     users.insert(inst);
   }
 
-  if (!inst->IsOpenCL100DebugInstr()) return;
+  if (!inst->IsCommonDebugInstr()) return;
 
   RegisterDbgInst(inst);
 
-  if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
-    assert(GetDebugFunction(inst->GetSingleWordOperand(
-               kDebugFunctionOperandFunctionIndex)) == nullptr &&
-           "Two DebugFunction instruction exists for a single OpFunction.");
+  if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction ||
+      inst->GetVulkan100DebugOpcode() ==
+          NonSemanticVulkanDebugInfo100DebugFunctionDefinition) {
     RegisterDbgFunction(inst);
   }
 
@@ -633,8 +694,17 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
     deref_operation_ = inst;
   }
 
+  if (deref_operation_ == nullptr &&
+      inst->GetVulkan100DebugOpcode() ==
+          NonSemanticVulkanDebugInfo100DebugOperation) {
+    uint32_t operation_const = GetVulkanDebugOperation(inst);
+    if (operation_const == NonSemanticVulkanDebugInfo100Deref) {
+      deref_operation_ = inst;
+    }
+  }
+
   if (debug_info_none_inst_ == nullptr &&
-      inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) {
+      inst->GetCommonDebugOpcode() == CommonDebugInfoDebugInfoNone) {
     debug_info_none_inst_ = inst;
   }
 
@@ -642,7 +712,7 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
     empty_debug_expr_inst_ = inst;
   }
 
-  if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare) {
+  if (inst->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) {
     uint32_t var_id =
         inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
     RegisterDbgDeclare(var_id, inst);
@@ -655,8 +725,8 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
 
 void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
     Instruction* dbg_global_var, Instruction* local_var) {
-  if (dbg_global_var->GetOpenCL100DebugOpcode() !=
-      OpenCLDebugInfo100DebugGlobalVariable) {
+  if (dbg_global_var->GetCommonDebugOpcode() !=
+      CommonDebugInfoDebugGlobalVariable) {
     return;
   }
   assert(local_var->opcode() == SpvOpVariable ||
@@ -664,7 +734,7 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
 
   // Convert |dbg_global_var| to DebugLocalVariable
   dbg_global_var->SetInOperand(kExtInstInstructionInIdx,
-                               {OpenCLDebugInfo100DebugLocalVariable});
+                               {CommonDebugInfoDebugLocalVariable});
   auto flags = dbg_global_var->GetSingleWordOperand(
       kDebugGlobalVariableOperandFlagsIndex);
   for (uint32_t i = dbg_global_var->NumInOperands() - 1;
@@ -680,12 +750,9 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
       context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
       context()->TakeNextId(),
       {
-          {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
-           {context()
-                ->get_feature_mgr()
-                ->GetExtInstImportId_OpenCL100DebugInfo()}},
+          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
-           {static_cast<uint32_t>(OpenCLDebugInfo100DebugDeclare)}},
+           {static_cast<uint32_t>(CommonDebugInfoDebugDeclare)}},
           {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
            {dbg_global_var->result_id()}},
           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {local_var->result_id()}},
@@ -713,7 +780,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
   // list.
   if (empty_debug_expr_inst_ != nullptr &&
       empty_debug_expr_inst_->PreviousNode() != nullptr &&
-      empty_debug_expr_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
+      empty_debug_expr_inst_->PreviousNode()->IsCommonDebugInstr()) {
     empty_debug_expr_inst_->InsertBefore(
         &*context()->module()->ext_inst_debuginfo_begin());
   }
@@ -722,7 +789,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
   // list.
   if (debug_info_none_inst_ != nullptr &&
       debug_info_none_inst_->PreviousNode() != nullptr &&
-      debug_info_none_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
+      debug_info_none_inst_->PreviousNode()->IsCommonDebugInstr()) {
     debug_info_none_inst_->InsertBefore(
         &*context()->module()->ext_inst_debuginfo_begin());
   }
@@ -740,7 +807,7 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
     inlinedat_id_to_users_itr->second.erase(instr);
   }
 
-  if (instr == nullptr || !instr->IsOpenCL100DebugInstr()) {
+  if (instr == nullptr || !instr->IsCommonDebugInstr()) {
     return;
   }
 
@@ -751,9 +818,15 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
         instr->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
     fn_id_to_dbg_fn_.erase(fn_id);
   }
+  if (instr->GetVulkan100DebugOpcode() ==
+      NonSemanticVulkanDebugInfo100DebugFunction) {
+    auto fn_id = instr->GetSingleWordOperand(
+        kDebugFunctionDefinitionOperandOpFunctionIndex);
+    fn_id_to_dbg_fn_.erase(fn_id);
+  }
 
-  if (instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare ||
-      instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue) {
+  if (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare ||
+      instr->GetCommonDebugOpcode() == CommonDebugInfoDebugValue) {
     auto var_or_value_id =
         instr->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
     auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_or_value_id);
@@ -767,6 +840,8 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
          dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
          ++dbg_instr_itr) {
+      // OpenCL.DebugInfo.100 contains the operation as a literal operand, in
+      // Vulkan it's referenced as an OpConstant.
       if (instr != &*dbg_instr_itr &&
           dbg_instr_itr->GetOpenCL100DebugOpcode() ==
               OpenCLDebugInfo100DebugOperation &&
@@ -775,6 +850,15 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
               OpenCLDebugInfo100Deref) {
         deref_operation_ = &*dbg_instr_itr;
         break;
+      } else if (instr != &*dbg_instr_itr &&
+                 dbg_instr_itr->GetVulkan100DebugOpcode() ==
+                     NonSemanticVulkanDebugInfo100DebugOperation) {
+        uint32_t operation_const = GetVulkanDebugOperation(&*dbg_instr_itr);
+
+        if (operation_const == NonSemanticVulkanDebugInfo100Deref) {
+          deref_operation_ = &*dbg_instr_itr;
+          break;
+        }
       }
     }
   }
@@ -784,9 +868,8 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
          dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
          ++dbg_instr_itr) {
-      if (instr != &*dbg_instr_itr &&
-          dbg_instr_itr->GetOpenCL100DebugOpcode() ==
-              OpenCLDebugInfo100DebugInfoNone) {
+      if (instr != &*dbg_instr_itr && dbg_instr_itr->GetCommonDebugOpcode() ==
+                                          CommonDebugInfoDebugInfoNone) {
         debug_info_none_inst_ = &*dbg_instr_itr;
         break;
       }

+ 11 - 5
3rdparty/spirv-tools/source/opt/debug_info_manager.h

@@ -67,8 +67,8 @@ class DebugInlinedAtContext {
   std::unordered_map<uint32_t, uint32_t> callee_inlined_at2chain_;
 };
 
-// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 extension
-// instructions.
+// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 and
+// NonSemantic.Vulkan.DebugInfo.100 extension instructions.
 class DebugInfoManager {
  public:
   // Constructs a debug information manager from the given |context|.
@@ -85,7 +85,7 @@ class DebugInfoManager {
     return !(lhs == rhs);
   }
 
-  // Analyzes OpenCL.DebugInfo.100 instruction |dbg_inst|.
+  // Analyzes DebugInfo instruction |dbg_inst|.
   void AnalyzeDebugInst(Instruction* dbg_inst);
 
   // Creates new DebugInlinedAt and returns its id. Its line operand is the
@@ -164,6 +164,9 @@ class DebugInfoManager {
   // Erases |instr| from data structures of this class.
   void ClearDebugInfo(Instruction* instr);
 
+  // Return the opcode for the Vulkan DebugOperation inst
+  uint32_t GetVulkanDebugOperation(Instruction* inst);
+
   // Returns the id of Value operand if |inst| is DebugValue who has Deref
   // operation and its Value operand is a result id of OpVariable with
   // Function storage class. Otherwise, returns 0.
@@ -190,10 +193,13 @@ class DebugInfoManager {
  private:
   IRContext* context() { return context_; }
 
-  // Analyzes OpenCL.DebugInfo.100 instructions in the given |module| and
+  // Analyzes DebugInfo instructions in the given |module| and
   // populates data structures in this class.
   void AnalyzeDebugInsts(Module& module);
 
+  // Get the DebugInfo ExtInstImport Id, or 0 if no DebugInfo is available.
+  uint32_t GetDbgSetImportId();
+
   // Returns the debug instruction whose id is |id|. Returns |nullptr| if one
   // does not exists.
   Instruction* GetDbgInst(uint32_t id);
@@ -230,7 +236,7 @@ class DebugInfoManager {
 
   IRContext* context_;
 
-  // Mapping from ids of OpenCL.DebugInfo.100 extension instructions
+  // Mapping from ids of DebugInfo extension instructions.
   // to their Instruction instances.
   std::unordered_map<uint32_t, Instruction*> id_to_dbg_inst_;
 

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

@@ -967,12 +967,11 @@ FoldingRule MergeDivMulArithmetic() {
 // Fold divides of a constant and a negation.
 // Cases:
 // (-x) / 2 = x / -2
-// 2 / (-x) = 2 / -x
+// 2 / (-x) = -2 / x
 FoldingRule MergeDivNegateArithmetic() {
   return [](IRContext* context, Instruction* inst,
             const std::vector<const analysis::Constant*>& constants) {
-    assert(inst->opcode() == SpvOpFDiv || inst->opcode() == SpvOpSDiv ||
-           inst->opcode() == SpvOpUDiv);
+    assert(inst->opcode() == SpvOpFDiv || inst->opcode() == SpvOpSDiv);
     analysis::ConstantManager* const_mgr = context->get_constant_mgr();
     const analysis::Type* type =
         context->get_type_mgr()->GetType(inst->type_id());
@@ -2572,8 +2571,6 @@ void FoldingRules::AddFoldingRules() {
 
   rules_[SpvOpStore].push_back(StoringUndef());
 
-  rules_[SpvOpUDiv].push_back(MergeDivNegateArithmetic());
-
   rules_[SpvOpVectorShuffle].push_back(VectorShuffleFeedingShuffle());
 
   rules_[SpvOpImageSampleImplicitLod].push_back(UpdateImageOperands());

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

@@ -499,6 +499,26 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
     RegisterPass(CreateAmdExtToKhrPass());
   } else if (pass_name == "interpolate-fixup") {
     RegisterPass(CreateInterpolateFixupPass());
+  } else if (pass_name == "convert-to-sampled-image") {
+    if (pass_args.size() > 0) {
+      auto descriptor_set_binding_pairs =
+          opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
+              pass_args.c_str());
+      if (!descriptor_set_binding_pairs) {
+        Errorf(consumer(), nullptr, {},
+               "Invalid argument for --convert-to-sampled-image: %s",
+               pass_args.c_str());
+        return false;
+      }
+      RegisterPass(CreateConvertToSampledImagePass(
+          std::move(*descriptor_set_binding_pairs)));
+    } else {
+      Errorf(consumer(), nullptr, {},
+             "Invalid pairs of descriptor set and binding '%s'. Expected a "
+             "string of <descriptor set>:<binding> pairs.",
+             pass_args.c_str());
+      return false;
+    }
   } else {
     Errorf(consumer(), nullptr, {},
            "Unknown flag '--%s'. Use --help for a list of valid flags",
@@ -940,4 +960,11 @@ Optimizer::PassToken CreateInterpolateFixupPass() {
       MakeUnique<opt::InterpFixupPass>());
 }
 
+Optimizer::PassToken CreateConvertToSampledImagePass(
+    const std::vector<opt::DescriptorSetAndBinding>&
+        descriptor_set_binding_pairs) {
+  return MakeUnique<Optimizer::PassToken::Impl>(
+      MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs));
+}
+
 }  // namespace spvtools

+ 1 - 0
3rdparty/spirv-tools/source/opt/passes.h

@@ -26,6 +26,7 @@
 #include "source/opt/combine_access_chains.h"
 #include "source/opt/compact_ids_pass.h"
 #include "source/opt/convert_to_half_pass.h"
+#include "source/opt/convert_to_sampled_image_pass.h"
 #include "source/opt/copy_prop_arrays.h"
 #include "source/opt/dead_branch_elim_pass.h"
 #include "source/opt/dead_insert_elim_pass.h"

+ 7 - 4
3rdparty/spirv-tools/source/val/validate_builtins.cpp

@@ -2846,7 +2846,7 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
                << spvLogStringForEnv(_.context()->target_env)
                << " spec allows BuiltIn "
                << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
-               << " to be used only with GLCompute execution model. "
+               << " to be used only with GLCompute, MeshNV, or TaskNV execution model. "
                << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
                                    referenced_from_inst, execution_model);
       }
@@ -2928,7 +2928,7 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
                << spvLogStringForEnv(_.context()->target_env)
                << " spec allows BuiltIn "
                << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
-               << " to be used only with GLCompute execution model. "
+               << " to be used only with GLCompute, MeshNV, or TaskNV execution model. "
                << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
                                    referenced_from_inst, execution_model);
       }
@@ -3070,14 +3070,16 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
     const Instruction& referenced_from_inst) {
   if (spvIsVulkanEnv(_.context()->target_env)) {
     for (const SpvExecutionModel execution_model : execution_models_) {
-      if (execution_model != SpvExecutionModelGLCompute) {
+      if (execution_model != SpvExecutionModelGLCompute &&
+          execution_model != SpvExecutionModelTaskNV &&
+          execution_model != SpvExecutionModelMeshNV) {
         return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
                << _.VkErrorID(4425)
                << spvLogStringForEnv(_.context()->target_env)
                << " spec allows BuiltIn "
                << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
                                                 decoration.params()[0])
-               << " to be used only with GLCompute execution model. "
+               << " to be used only with GLCompute, MeshNV, or TaskNV execution model. "
                << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
                                    referenced_from_inst, execution_model);
       }
@@ -4190,6 +4192,7 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
     case SpvBuiltInMeshViewIndicesNV:
     case SpvBuiltInBaryCoordNV:
     case SpvBuiltInBaryCoordNoPerspNV:
+    case SpvBuiltInCurrentRayTimeNV:
       // No validation rules (for the moment).
       break;
 

+ 4 - 6
3rdparty/spirv-tools/source/val/validate_decorations.cpp

@@ -506,12 +506,10 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
       return recursive_status;
     // Check matrix stride.
     if (SpvOpTypeMatrix == opcode) {
-      for (auto& decoration : vstate.id_decorations(id)) {
-        if (SpvDecorationMatrixStride == decoration.dec_type() &&
-            !IsAlignedTo(decoration.params()[0], alignment))
-          return fail(memberIdx)
-                 << "is a matrix with stride " << decoration.params()[0]
-                 << " not satisfying alignment to " << alignment;
+      const auto stride = constraint.matrix_stride;
+      if (!IsAlignedTo(stride, alignment)) {
+        return fail(memberIdx) << "is a matrix with stride " << stride
+                               << " not satisfying alignment to " << alignment;
       }
     }
 

+ 20 - 0
3rdparty/spirv-tools/source/val/validate_interfaces.cpp

@@ -27,6 +27,10 @@ namespace spvtools {
 namespace val {
 namespace {
 
+// Limit the number of checked locations to 4096. Multiplied by 4 to represent
+// all the components. This limit is set to be well beyond practical use cases.
+const uint32_t kMaxLocations = 4096 * 4;
+
 // Returns true if \c inst is an input or output variable.
 bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) {
   if (is_spv_1_4) {
@@ -347,6 +351,11 @@ spv_result_t GetLocationsForVariable(
       uint32_t num_components = NumConsumedComponents(_, sub_type);
       uint32_t array_location = location + (num_locations * array_idx);
       uint32_t start = array_location * 4;
+      if (kMaxLocations <= start) {
+        // Too many locations, give up.
+        break;
+      }
+
       uint32_t end = (array_location + num_locations) * 4;
       if (num_components != 0) {
         start += component;
@@ -416,6 +425,11 @@ spv_result_t GetLocationsForVariable(
       }
 
       uint32_t start = location * 4;
+      if (kMaxLocations <= start) {
+        // Too many locations, give up.
+        continue;
+      }
+
       uint32_t end = (location + num_locations) * 4;
       if (num_components != 0) {
         start += component;
@@ -454,6 +468,7 @@ spv_result_t ValidateLocations(ValidationState_t& _,
   std::unordered_set<uint32_t> input_locations;
   std::unordered_set<uint32_t> output_locations_index0;
   std::unordered_set<uint32_t> output_locations_index1;
+  std::unordered_set<uint32_t> seen;
   for (uint32_t i = 3; i < entry_point->operands().size(); ++i) {
     auto interface_id = entry_point->GetOperandAs<uint32_t>(i);
     auto interface_var = _.FindDef(interface_id);
@@ -462,6 +477,11 @@ spv_result_t ValidateLocations(ValidationState_t& _,
         storage_class != SpvStorageClassOutput) {
       continue;
     }
+    if (!seen.insert(interface_id).second) {
+      // Pre-1.4 an interface variable could be listed multiple times in an
+      // entry point. Validation for 1.4 or later is done elsewhere.
+      continue;
+    }
 
     auto locations = (storage_class == SpvStorageClassInput)
                          ? &input_locations

+ 6 - 0
3rdparty/spirv-tools/source/val/validate_memory.cpp

@@ -893,6 +893,12 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) {
            << "'s type.";
   }
 
+  if (!_.options()->before_hlsl_legalization &&
+      _.ContainsRuntimeArray(inst->type_id())) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << "Cannot load a runtime-sized array";
+  }
+
   if (auto error = CheckMemoryAccess(_, inst, 3)) return error;
 
   if (_.HasCapability(SpvCapabilityShader) &&

+ 42 - 17
3rdparty/spirv-tools/source/val/validation_state.cpp

@@ -1262,16 +1262,13 @@ const Instruction* ValidationState_t::TracePointer(
   return base_ptr;
 }
 
-bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
-                                                    uint32_t width) const {
-  if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false;
-
+bool ValidationState_t::ContainsType(
+    uint32_t id, const std::function<bool(const Instruction*)>& f,
+    bool traverse_all_types) const {
   const auto inst = FindDef(id);
   if (!inst) return false;
 
-  if (inst->opcode() == type) {
-    return inst->GetOperandAs<uint32_t>(1u) == width;
-  }
+  if (f(inst)) return true;
 
   switch (inst->opcode()) {
     case SpvOpTypeArray:
@@ -1281,24 +1278,45 @@ bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
     case SpvOpTypeImage:
     case SpvOpTypeSampledImage:
     case SpvOpTypeCooperativeMatrixNV:
-      return ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(1u), type,
-                                         width);
+      return ContainsType(inst->GetOperandAs<uint32_t>(1u), f,
+                          traverse_all_types);
     case SpvOpTypePointer:
       if (IsForwardPointer(id)) return false;
-      return ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(2u), type,
-                                         width);
+      if (traverse_all_types) {
+        return ContainsType(inst->GetOperandAs<uint32_t>(2u), f,
+                            traverse_all_types);
+      }
+      break;
     case SpvOpTypeFunction:
-    case SpvOpTypeStruct: {
+    case SpvOpTypeStruct:
+      if (inst->opcode() == SpvOpTypeFunction && !traverse_all_types) {
+        return false;
+      }
       for (uint32_t i = 1; i < inst->operands().size(); ++i) {
-        if (ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(i), type,
-                                        width))
+        if (ContainsType(inst->GetOperandAs<uint32_t>(i), f,
+                         traverse_all_types)) {
           return true;
+        }
       }
-      return false;
-    }
+      break;
     default:
-      return false;
+      break;
   }
+
+  return false;
+}
+
+bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
+                                                    uint32_t width) const {
+  if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false;
+
+  const auto f = [type, width](const Instruction* inst) {
+    if (inst->opcode() == type) {
+      return inst->GetOperandAs<uint32_t>(1u) == width;
+    }
+    return false;
+  };
+  return ContainsType(id, f);
 }
 
 bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
@@ -1313,6 +1331,13 @@ bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
   return false;
 }
 
+bool ValidationState_t::ContainsRuntimeArray(uint32_t id) const {
+  const auto f = [](const Instruction* inst) {
+    return inst->opcode() == SpvOpTypeRuntimeArray;
+  };
+  return ContainsType(id, f, /* traverse_all_types = */ false);
+}
+
 bool ValidationState_t::IsValidStorageClass(
     SpvStorageClass storage_class) const {
   if (spvIsVulkanEnv(context()->target_env)) {

+ 11 - 0
3rdparty/spirv-tools/source/val/validation_state.h

@@ -595,6 +595,17 @@ class ValidationState_t {
   // 16-bit float that is not generally enabled for use.
   bool ContainsLimitedUseIntOrFloatType(uint32_t id) const;
 
+  // Returns true if |id| is a type that contains a runtime-sized array.
+  // Does not consider a pointers as contains the array.
+  bool ContainsRuntimeArray(uint32_t id) const;
+
+  // Generic type traversal.
+  // Only traverse pointers and functions if |traverse_all_types| is true.
+  // Recursively tests |f| against the type hierarchy headed by |id|.
+  bool ContainsType(uint32_t id,
+                    const std::function<bool(const Instruction*)>& f,
+                    bool traverse_all_types = true) const;
+
   // Gets value from OpConstant and OpSpecConstant as uint64.
   // Returns false on failure (no instruction, wrong instruction, not int).
   bool GetConstantValUint64(uint32_t id, uint64_t* val) const;

Некоторые файлы не были показаны из-за большого количества измененных файлов