Browse Source

Updated spirv-tools.

Бранимир Караџић 2 years ago
parent
commit
efb7f66a0e
30 changed files with 802 additions and 157 deletions
  1. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  2. 2 0
      3rdparty/spirv-tools/include/generated/enum_string_mapping.inc
  3. 1 0
      3rdparty/spirv-tools/include/generated/extension_enum.inc
  4. 10 6
      3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc
  5. 1 0
      3rdparty/spirv-tools/include/spirv-tools/libspirv.h
  6. 11 0
      3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp
  7. 7 0
      3rdparty/spirv-tools/source/binary.cpp
  8. 4 0
      3rdparty/spirv-tools/source/diff/diff.cpp
  9. 2 1
      3rdparty/spirv-tools/source/disassemble.cpp
  10. 18 0
      3rdparty/spirv-tools/source/enum_set.h
  11. 2 0
      3rdparty/spirv-tools/source/operand.cpp
  12. 4 0
      3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp
  13. 5 0
      3rdparty/spirv-tools/source/opt/const_folding_rules.cpp
  14. 6 1
      3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp
  15. 6 3
      3rdparty/spirv-tools/source/opt/convert_to_half_pass.h
  16. 24 19
      3rdparty/spirv-tools/source/opt/feature_manager.h
  17. 3 3
      3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp
  18. 1 9
      3rdparty/spirv-tools/source/opt/inst_debug_printf_pass.cpp
  19. 53 1
      3rdparty/spirv-tools/source/opt/ir_context.cpp
  20. 43 3
      3rdparty/spirv-tools/source/opt/ir_context.h
  21. 1 1
      3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp
  22. 55 56
      3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp
  23. 52 53
      3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp
  24. 5 0
      3rdparty/spirv-tools/source/opt/mem_pass.cpp
  25. 1 0
      3rdparty/spirv-tools/source/opt/module.h
  26. 1 0
      3rdparty/spirv-tools/source/opt/passes.h
  27. 320 0
      3rdparty/spirv-tools/source/opt/trim_capabilities_pass.cpp
  28. 151 0
      3rdparty/spirv-tools/source/opt/trim_capabilities_pass.h
  29. 1 0
      3rdparty/spirv-tools/source/parsed_operand.cpp
  30. 11 0
      3rdparty/spirv-tools/source/text.cpp

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

@@ -1 +1 @@
-"v2023.3", "SPIRV-Tools v2023.3 v2022.4-269-g34399abb"
+"v2023.4", "SPIRV-Tools v2023.4 v2022.4-291-ga913df4a"

File diff suppressed because it is too large
+ 2 - 0
3rdparty/spirv-tools/include/generated/enum_string_mapping.inc


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

@@ -37,6 +37,7 @@ kSPV_INTEL_debug_module,
 kSPV_INTEL_device_side_avc_motion_estimation,
 kSPV_INTEL_device_side_avc_motion_estimation,
 kSPV_INTEL_float_controls2,
 kSPV_INTEL_float_controls2,
 kSPV_INTEL_fp_fast_math_mode,
 kSPV_INTEL_fp_fast_math_mode,
+kSPV_INTEL_fp_max_error,
 kSPV_INTEL_fpga_argument_interfaces,
 kSPV_INTEL_fpga_argument_interfaces,
 kSPV_INTEL_fpga_buffer_location,
 kSPV_INTEL_fpga_buffer_location,
 kSPV_INTEL_fpga_cluster_attributes,
 kSPV_INTEL_fpga_cluster_attributes,

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

@@ -27,6 +27,7 @@ static const spv::Capability pygen_variable_caps_FPGALatencyControlINTEL[] = {sp
 static const spv::Capability pygen_variable_caps_FPGALoopControlsINTEL[] = {spv::Capability::FPGALoopControlsINTEL};
 static const spv::Capability pygen_variable_caps_FPGALoopControlsINTEL[] = {spv::Capability::FPGALoopControlsINTEL};
 static const spv::Capability pygen_variable_caps_FPGAMemoryAccessesINTEL[] = {spv::Capability::FPGAMemoryAccessesINTEL};
 static const spv::Capability pygen_variable_caps_FPGAMemoryAccessesINTEL[] = {spv::Capability::FPGAMemoryAccessesINTEL};
 static const spv::Capability pygen_variable_caps_FPGAMemoryAttributesINTEL[] = {spv::Capability::FPGAMemoryAttributesINTEL};
 static const spv::Capability pygen_variable_caps_FPGAMemoryAttributesINTEL[] = {spv::Capability::FPGAMemoryAttributesINTEL};
+static const spv::Capability pygen_variable_caps_FPMaxErrorINTEL[] = {spv::Capability::FPMaxErrorINTEL};
 static const spv::Capability pygen_variable_caps_FragmentBarycentricNVFragmentBarycentricKHR[] = {spv::Capability::FragmentBarycentricNV, spv::Capability::FragmentBarycentricKHR};
 static const spv::Capability pygen_variable_caps_FragmentBarycentricNVFragmentBarycentricKHR[] = {spv::Capability::FragmentBarycentricNV, spv::Capability::FragmentBarycentricKHR};
 static const spv::Capability pygen_variable_caps_FragmentDensityEXTShadingRateNV[] = {spv::Capability::FragmentDensityEXT, spv::Capability::ShadingRateNV};
 static const spv::Capability pygen_variable_caps_FragmentDensityEXTShadingRateNV[] = {spv::Capability::FragmentDensityEXT, spv::Capability::ShadingRateNV};
 static const spv::Capability pygen_variable_caps_FragmentFullyCoveredEXT[] = {spv::Capability::FragmentFullyCoveredEXT};
 static const spv::Capability pygen_variable_caps_FragmentFullyCoveredEXT[] = {spv::Capability::FragmentFullyCoveredEXT};
@@ -169,6 +170,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_debug_module[] =
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_device_side_avc_motion_estimation[] = {spvtools::Extension::kSPV_INTEL_device_side_avc_motion_estimation};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_device_side_avc_motion_estimation[] = {spvtools::Extension::kSPV_INTEL_device_side_avc_motion_estimation};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_float_controls2[] = {spvtools::Extension::kSPV_INTEL_float_controls2};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_float_controls2[] = {spvtools::Extension::kSPV_INTEL_float_controls2};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fp_fast_math_mode[] = {spvtools::Extension::kSPV_INTEL_fp_fast_math_mode};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fp_fast_math_mode[] = {spvtools::Extension::kSPV_INTEL_fp_fast_math_mode};
+static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fp_max_error[] = {spvtools::Extension::kSPV_INTEL_fp_max_error};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_argument_interfaces[] = {spvtools::Extension::kSPV_INTEL_fpga_argument_interfaces};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_argument_interfaces[] = {spvtools::Extension::kSPV_INTEL_fpga_argument_interfaces};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_buffer_location[] = {spvtools::Extension::kSPV_INTEL_fpga_buffer_location};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_buffer_location[] = {spvtools::Extension::kSPV_INTEL_fpga_buffer_location};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_cluster_attributes[] = {spvtools::Extension::kSPV_INTEL_fpga_cluster_attributes};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_cluster_attributes[] = {spvtools::Extension::kSPV_INTEL_fpga_cluster_attributes};
@@ -855,6 +857,7 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = {
   {"SingleElementVectorINTEL", 6085, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
   {"SingleElementVectorINTEL", 6085, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
   {"VectorComputeCallableFunctionINTEL", 6087, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
   {"VectorComputeCallableFunctionINTEL", 6087, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
   {"MediaBlockIOINTEL", 6140, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
   {"MediaBlockIOINTEL", 6140, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"FPMaxErrorDecorationINTEL", 6170, 1, pygen_variable_caps_FPMaxErrorINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_FLOAT}, 0xffffffffu, 0xffffffffu},
   {"LatencyControlLabelINTEL", 6172, 1, pygen_variable_caps_FPGALatencyControlINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
   {"LatencyControlLabelINTEL", 6172, 1, pygen_variable_caps_FPGALatencyControlINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
   {"LatencyControlConstraintINTEL", 6173, 1, pygen_variable_caps_FPGALatencyControlINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
   {"LatencyControlConstraintINTEL", 6173, 1, pygen_variable_caps_FPGALatencyControlINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
   {"ConduitKernelArgumentINTEL", 6175, 1, pygen_variable_caps_FPGAArgumentInterfacesINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
   {"ConduitKernelArgumentINTEL", 6175, 1, pygen_variable_caps_FPGAArgumentInterfacesINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
@@ -1272,6 +1275,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
   {"BFloat16ConversionINTEL", 6115, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_bfloat16_conversion, {}, 0xffffffffu, 0xffffffffu},
   {"BFloat16ConversionINTEL", 6115, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_bfloat16_conversion, {}, 0xffffffffu, 0xffffffffu},
   {"SplitBarrierINTEL", 6141, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_split_barrier, {}, 0xffffffffu, 0xffffffffu},
   {"SplitBarrierINTEL", 6141, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_split_barrier, {}, 0xffffffffu, 0xffffffffu},
   {"FPGAKernelAttributesv2INTEL", 6161, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 1, pygen_variable_exts_SPV_INTEL_kernel_attributes, {}, 0xffffffffu, 0xffffffffu},
   {"FPGAKernelAttributesv2INTEL", 6161, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 1, pygen_variable_exts_SPV_INTEL_kernel_attributes, {}, 0xffffffffu, 0xffffffffu},
+  {"FPMaxErrorINTEL", 6169, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fp_max_error, {}, 0xffffffffu, 0xffffffffu},
   {"FPGALatencyControlINTEL", 6171, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_latency_control, {}, 0xffffffffu, 0xffffffffu},
   {"FPGALatencyControlINTEL", 6171, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_latency_control, {}, 0xffffffffu, 0xffffffffu},
   {"FPGAArgumentInterfacesINTEL", 6174, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_argument_interfaces, {}, 0xffffffffu, 0xffffffffu},
   {"FPGAArgumentInterfacesINTEL", 6174, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_argument_interfaces, {}, 0xffffffffu, 0xffffffffu},
   {"GroupUniformArithmeticKHR", 6400, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_uniform_group_instructions, {}, 0xffffffffu, 0xffffffffu}
   {"GroupUniformArithmeticKHR", 6400, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_uniform_group_instructions, {}, 0xffffffffu, 0xffffffffu}
@@ -1299,12 +1303,12 @@ static const spv_operand_desc_t pygen_variable_PackedVectorFormatEntries[] = {
 };
 };
 
 
 static const spv_operand_desc_t pygen_variable_CooperativeMatrixOperandsEntries[] = {
 static const spv_operand_desc_t pygen_variable_CooperativeMatrixOperandsEntries[] = {
-  {"None", 0x0000, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
-  {"MatrixASignedComponents", 0x0001, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
-  {"MatrixBSignedComponents", 0x0002, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
-  {"MatrixCSignedComponents", 0x0004, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
-  {"MatrixResultSignedComponents", 0x0008, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
-  {"SaturatingAccumulation", 0x0010, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
+  {"NoneKHR", 0x0000, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"MatrixASignedComponentsKHR", 0x0001, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"MatrixBSignedComponentsKHR", 0x0002, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"MatrixCSignedComponentsKHR", 0x0004, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"MatrixResultSignedComponentsKHR", 0x0008, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"SaturatingAccumulationKHR", 0x0010, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
 };
 };
 
 
 static const spv_operand_desc_t pygen_variable_CooperativeMatrixLayoutEntries[] = {
 static const spv_operand_desc_t pygen_variable_CooperativeMatrixLayoutEntries[] = {

+ 1 - 0
3rdparty/spirv-tools/include/spirv-tools/libspirv.h

@@ -143,6 +143,7 @@ typedef enum spv_operand_type_t {
   // may be larger than 32, which would require such a typed literal value to
   // may be larger than 32, which would require such a typed literal value to
   // occupy multiple SPIR-V words.
   // occupy multiple SPIR-V words.
   SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
   SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
+  SPV_OPERAND_TYPE_LITERAL_FLOAT,  // Always 32-bit float.
 
 
   // Set 3:  The literal string operand type.
   // Set 3:  The literal string operand type.
   SPV_OPERAND_TYPE_LITERAL_STRING,
   SPV_OPERAND_TYPE_LITERAL_STRING,

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

@@ -981,6 +981,17 @@ Optimizer::PassToken CreateRemoveDontInlinePass();
 // object, currently the pass would remove accesschain pointer argument passed
 // object, currently the pass would remove accesschain pointer argument passed
 // to the function
 // to the function
 Optimizer::PassToken CreateFixFuncCallArgumentsPass();
 Optimizer::PassToken CreateFixFuncCallArgumentsPass();
+
+// Creates a trim-capabilities pass.
+// This pass removes unused capabilities for a given module, and if possible,
+// associated extensions.
+// See `trim_capabilities.h` for the list of supported capabilities.
+//
+// If the module contains unsupported capabilities, this pass will ignore them.
+// This should be fine in most cases, but could yield to incorrect results if
+// the unknown capability interacts with one of the trimmed capabilities.
+Optimizer::PassToken CreateTrimCapabilitiesPass();
+
 }  // namespace spvtools
 }  // namespace spvtools
 
 
 #endif  // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_
 #endif  // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_

+ 7 - 0
3rdparty/spirv-tools/source/binary.cpp

@@ -546,6 +546,13 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
       parsed_operand.number_bit_width = 32;
       parsed_operand.number_bit_width = 32;
       break;
       break;
 
 
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT:
+      // These are regular single-word literal float operands.
+      parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_FLOAT;
+      parsed_operand.number_kind = SPV_NUMBER_FLOATING;
+      parsed_operand.number_bit_width = 32;
+      break;
+
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
       parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
       parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;

+ 4 - 0
3rdparty/spirv-tools/source/diff/diff.cpp

@@ -2038,6 +2038,10 @@ spv_number_kind_t Differ::GetNumberKind(const IdInstructions& id_to,
       // Always unsigned integers.
       // Always unsigned integers.
       *number_bit_width = 32;
       *number_bit_width = 32;
       return SPV_NUMBER_UNSIGNED_INT;
       return SPV_NUMBER_UNSIGNED_INT;
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT:
+      // Always float.
+      *number_bit_width = 32;
+      return SPV_NUMBER_FLOATING;
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
       switch (inst.opcode()) {
       switch (inst.opcode()) {

+ 2 - 1
3rdparty/spirv-tools/source/disassemble.cpp

@@ -357,7 +357,8 @@ void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst,
       stream_ << opcode_desc->name;
       stream_ << opcode_desc->name;
     } break;
     } break;
     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
-    case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: {
+    case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT: {
       SetRed();
       SetRed();
       EmitNumericLiteral(&stream_, inst, operand);
       EmitNumericLiteral(&stream_, inst, operand);
       ResetColor();
       ResetColor();

+ 18 - 0
3rdparty/spirv-tools/source/enum_set.h

@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // limitations under the License.
 
 
+#include <algorithm>
 #include <cassert>
 #include <cassert>
 #include <cstdint>
 #include <cstdint>
 #include <functional>
 #include <functional>
@@ -203,6 +204,14 @@ class EnumSet {
     }
     }
   }
   }
 
 
+  // Creates a set initialized with the content of the range [begin; end[.
+  template <class InputIt>
+  EnumSet(InputIt begin, InputIt end) : EnumSet() {
+    for (; begin != end; ++begin) {
+      insert(*begin);
+    }
+  }
+
   // Copies the EnumSet `other` into a new EnumSet.
   // Copies the EnumSet `other` into a new EnumSet.
   EnumSet(const EnumSet& other)
   EnumSet(const EnumSet& other)
       : buckets_(other.buckets_), size_(other.size_) {}
       : buckets_(other.buckets_), size_(other.size_) {}
@@ -255,6 +264,15 @@ class EnumSet {
   // insertion.
   // insertion.
   iterator insert(const_iterator, T&& value) { return insert(value).first; }
   iterator insert(const_iterator, T&& value) { return insert(value).first; }
 
 
+  // Inserts all the values in the range [`first`; `last[.
+  // Similar to `std::unordered_set::insert`.
+  template <class InputIt>
+  void insert(InputIt first, InputIt last) {
+    for (auto it = first; it != last; ++it) {
+      insert(*it);
+    }
+  }
+
   // Removes the value `value` into the set.
   // Removes the value `value` into the set.
   // Similar to `std::unordered_set::erase`.
   // Similar to `std::unordered_set::erase`.
   // Returns the number of erased elements.
   // Returns the number of erased elements.

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

@@ -155,6 +155,7 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT:
       return "literal number";
       return "literal number";
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
       return "possibly multi-word literal integer";
       return "possibly multi-word literal integer";
@@ -332,6 +333,7 @@ bool spvOperandIsConcrete(spv_operand_type_t type) {
   }
   }
   switch (type) {
   switch (type) {
     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT:
     case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER:
     case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER:
     case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER:
     case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER:
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:

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

@@ -438,6 +438,9 @@ std::vector<uint32_t> AggressiveDCEPass::GetLoadedVariablesFromFunctionCall(
     const Instruction* inst) {
     const Instruction* inst) {
   assert(inst->opcode() == spv::Op::OpFunctionCall);
   assert(inst->opcode() == spv::Op::OpFunctionCall);
   std::vector<uint32_t> live_variables;
   std::vector<uint32_t> live_variables;
+  // NOTE: we should only be checking function call parameters here, not the
+  // function itself, however, `IsPtr` will trivially return false for
+  // OpFunction
   inst->ForEachInId([this, &live_variables](const uint32_t* operand_id) {
   inst->ForEachInId([this, &live_variables](const uint32_t* operand_id) {
     if (!IsPtr(*operand_id)) return;
     if (!IsPtr(*operand_id)) return;
     uint32_t var_id = GetVariableId(*operand_id);
     uint32_t var_id = GetVariableId(*operand_id);
@@ -995,6 +998,7 @@ void AggressiveDCEPass::InitExtensions() {
       "SPV_KHR_uniform_group_instructions",
       "SPV_KHR_uniform_group_instructions",
       "SPV_KHR_fragment_shader_barycentric",
       "SPV_KHR_fragment_shader_barycentric",
       "SPV_NV_bindless_texture",
       "SPV_NV_bindless_texture",
+      "SPV_EXT_shader_atomic_float_add",
   });
   });
 }
 }
 
 

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

@@ -967,6 +967,11 @@ const analysis::Constant* FoldScalarFPDivide(
     return FoldFPScalarDivideByZero(result_type, numerator, const_mgr);
     return FoldFPScalarDivideByZero(result_type, numerator, const_mgr);
   }
   }
 
 
+  uint32_t width = denominator->type()->AsFloat()->width();
+  if (width != 32 && width != 64) {
+    return nullptr;
+  }
+
   const analysis::FloatConstant* denominator_float =
   const analysis::FloatConstant* denominator_float =
       denominator->AsFloatConstant();
       denominator->AsFloatConstant();
   if (denominator_float && denominator->GetValueAsDouble() == -0.0) {
   if (denominator_float && denominator->GetValueAsDouble() == -0.0) {

+ 6 - 1
3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp

@@ -63,6 +63,10 @@ bool ConvertToHalfPass::IsRelaxed(uint32_t id) {
 
 
 void ConvertToHalfPass::AddRelaxed(uint32_t id) { relaxed_ids_set_.insert(id); }
 void ConvertToHalfPass::AddRelaxed(uint32_t id) { relaxed_ids_set_.insert(id); }
 
 
+bool ConvertToHalfPass::CanRelaxOpOperands(Instruction* inst) {
+  return image_ops_.count(inst->opcode()) == 0;
+}
+
 analysis::Type* ConvertToHalfPass::FloatScalarType(uint32_t width) {
 analysis::Type* ConvertToHalfPass::FloatScalarType(uint32_t width) {
   analysis::Float float_ty(width);
   analysis::Float float_ty(width);
   return context()->get_type_mgr()->GetRegisteredType(&float_ty);
   return context()->get_type_mgr()->GetRegisteredType(&float_ty);
@@ -313,7 +317,8 @@ bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) {
   relax = true;
   relax = true;
   get_def_use_mgr()->ForEachUser(inst, [&relax, this](Instruction* uinst) {
   get_def_use_mgr()->ForEachUser(inst, [&relax, this](Instruction* uinst) {
     if (uinst->result_id() == 0 || !IsFloat(uinst, 32) ||
     if (uinst->result_id() == 0 || !IsFloat(uinst, 32) ||
-        (!IsDecoratedRelaxed(uinst) && !IsRelaxed(uinst->result_id()))) {
+        (!IsDecoratedRelaxed(uinst) && !IsRelaxed(uinst->result_id())) ||
+        !CanRelaxOpOperands(uinst)) {
       relax = false;
       relax = false;
       return;
       return;
     }
     }

+ 6 - 3
3rdparty/spirv-tools/source/opt/convert_to_half_pass.h

@@ -56,6 +56,9 @@ class ConvertToHalfPass : public Pass {
   // Add |id| to the relaxed id set
   // Add |id| to the relaxed id set
   void AddRelaxed(uint32_t id);
   void AddRelaxed(uint32_t id);
 
 
+  // Return true if the instruction's operands can be relaxed
+  bool CanRelaxOpOperands(Instruction* inst);
+
   // Return type id for float with |width|
   // Return type id for float with |width|
   analysis::Type* FloatScalarType(uint32_t width);
   analysis::Type* FloatScalarType(uint32_t width);
 
 
@@ -133,13 +136,13 @@ class ConvertToHalfPass : public Pass {
   // Set of 450 extension operations to be processed
   // Set of 450 extension operations to be processed
   std::unordered_set<uint32_t> target_ops_450_;
   std::unordered_set<uint32_t> target_ops_450_;
 
 
-  // Set of sample operations
+  // Set of all sample operations, including dref and non-dref operations
   std::unordered_set<spv::Op, hasher> image_ops_;
   std::unordered_set<spv::Op, hasher> image_ops_;
 
 
-  // Set of dref sample operations
+  // Set of only dref sample operations
   std::unordered_set<spv::Op, hasher> dref_image_ops_;
   std::unordered_set<spv::Op, hasher> dref_image_ops_;
 
 
-  // Set of dref sample operations
+  // Set of operations that can be marked as relaxed
   std::unordered_set<spv::Op, hasher> closure_ops_;
   std::unordered_set<spv::Op, hasher> closure_ops_;
 
 
   // Set of ids of all relaxed instructions
   // Set of ids of all relaxed instructions

+ 24 - 19
3rdparty/spirv-tools/source/opt/feature_manager.h

@@ -25,27 +25,19 @@ namespace opt {
 // Tracks features enabled by a module. The IRContext has a FeatureManager.
 // Tracks features enabled by a module. The IRContext has a FeatureManager.
 class FeatureManager {
 class FeatureManager {
  public:
  public:
-  explicit FeatureManager(const AssemblyGrammar& grammar) : grammar_(grammar) {}
-
   // Returns true if |ext| is an enabled extension in the module.
   // Returns true if |ext| is an enabled extension in the module.
   bool HasExtension(Extension ext) const { return extensions_.contains(ext); }
   bool HasExtension(Extension ext) const { return extensions_.contains(ext); }
 
 
-  // Removes the given |extension| from the current FeatureManager.
-  void RemoveExtension(Extension extension);
-
   // Returns true if |cap| is an enabled capability in the module.
   // Returns true if |cap| is an enabled capability in the module.
   bool HasCapability(spv::Capability cap) const {
   bool HasCapability(spv::Capability cap) const {
     return capabilities_.contains(cap);
     return capabilities_.contains(cap);
   }
   }
 
 
-  // Removes the given |capability| from the current FeatureManager.
-  void RemoveCapability(spv::Capability capability);
-
-  // Analyzes |module| and records enabled extensions and capabilities.
-  void Analyze(Module* module);
+  // Returns the capabilities the module declares.
+  inline const CapabilitySet& GetCapabilities() const { return capabilities_; }
 
 
-  CapabilitySet* GetCapabilities() { return &capabilities_; }
-  const CapabilitySet* GetCapabilities() const { return &capabilities_; }
+  // Returns the extensions the module imports.
+  inline const ExtensionSet& GetExtensions() const { return extensions_; }
 
 
   uint32_t GetExtInstImportId_GLSLstd450() const {
   uint32_t GetExtInstImportId_GLSLstd450() const {
     return extinst_importid_GLSLstd450_;
     return extinst_importid_GLSLstd450_;
@@ -64,23 +56,34 @@ class FeatureManager {
     return !(a == b);
     return !(a == b);
   }
   }
 
 
-  // Adds the given |capability| and all implied capabilities into the current
-  // FeatureManager.
-  void AddCapability(spv::Capability capability);
+ private:
+  explicit FeatureManager(const AssemblyGrammar& grammar) : grammar_(grammar) {}
+
+  // Analyzes |module| and records enabled extensions and capabilities.
+  void Analyze(Module* module);
 
 
   // Add the extension |ext| to the feature manager.
   // Add the extension |ext| to the feature manager.
   void AddExtension(Instruction* ext);
   void AddExtension(Instruction* ext);
 
 
-  // Analyzes |module| and records imported external instruction sets.
-  void AddExtInstImportIds(Module* module);
-
- private:
   // Analyzes |module| and records enabled extensions.
   // Analyzes |module| and records enabled extensions.
   void AddExtensions(Module* module);
   void AddExtensions(Module* module);
 
 
+  // Removes the given |extension| from the current FeatureManager.
+  void RemoveExtension(Extension extension);
+
+  // Adds the given |capability| and all implied capabilities into the current
+  // FeatureManager.
+  void AddCapability(spv::Capability capability);
+
   // Analyzes |module| and records enabled capabilities.
   // Analyzes |module| and records enabled capabilities.
   void AddCapabilities(Module* module);
   void AddCapabilities(Module* module);
 
 
+  // Removes the given |capability| from the current FeatureManager.
+  void RemoveCapability(spv::Capability capability);
+
+  // Analyzes |module| and records imported external instruction sets.
+  void AddExtInstImportIds(Module* module);
+
   // Auxiliary object for querying SPIR-V grammar facts.
   // Auxiliary object for querying SPIR-V grammar facts.
   const AssemblyGrammar& grammar_;
   const AssemblyGrammar& grammar_;
 
 
@@ -100,6 +103,8 @@ class FeatureManager {
   // Common NonSemanticShader100DebugInfo external instruction import ids,
   // Common NonSemanticShader100DebugInfo external instruction import ids,
   // cached for performance.
   // cached for performance.
   uint32_t extinst_importid_Shader100DebugInfo_ = 0;
   uint32_t extinst_importid_Shader100DebugInfo_ = 0;
+
+  friend class IRContext;
 };
 };
 
 
 }  // namespace opt
 }  // namespace opt

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

@@ -573,9 +573,9 @@ uint32_t GraphicsRobustAccessPass::GetGlslInsts() {
       context()->module()->AddExtInstImport(std::move(import_inst));
       context()->module()->AddExtInstImport(std::move(import_inst));
       module_status_.modified = true;
       module_status_.modified = true;
       context()->AnalyzeDefUse(inst);
       context()->AnalyzeDefUse(inst);
-      // Reanalyze the feature list, since we added an extended instruction
-      // set improt.
-      context()->get_feature_mgr()->Analyze(context()->module());
+      // Invalidates the feature manager, since we added an extended instruction
+      // set import.
+      context()->ResetFeatureManager();
     }
     }
   }
   }
   return module_status_.glsl_insts_id;
   return module_status_.glsl_insts_id;

+ 1 - 9
3rdparty/spirv-tools/source/opt/inst_debug_printf_pass.cpp

@@ -241,15 +241,7 @@ Pass::Status InstDebugPrintfPass::ProcessImpl() {
     }
     }
   }
   }
   if (!non_sem_set_seen) {
   if (!non_sem_set_seen) {
-    for (auto c_itr = context()->module()->extension_begin();
-         c_itr != context()->module()->extension_end(); ++c_itr) {
-      const std::string ext_name = c_itr->GetInOperand(0).AsString();
-      if (ext_name == "SPV_KHR_non_semantic_info") {
-        context()->KillInst(&*c_itr);
-        break;
-      }
-    }
-    context()->get_feature_mgr()->RemoveExtension(kSPV_KHR_non_semantic_info);
+    context()->RemoveExtension(kSPV_KHR_non_semantic_info);
   }
   }
   return Status::SuccessWithChange;
   return Status::SuccessWithChange;
 }
 }

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

@@ -220,6 +220,28 @@ Instruction* IRContext::KillInst(Instruction* inst) {
   return next_instruction;
   return next_instruction;
 }
 }
 
 
+bool IRContext::KillInstructionIf(Module::inst_iterator begin,
+                                  Module::inst_iterator end,
+                                  std::function<bool(Instruction*)> condition) {
+  bool removed = false;
+  for (auto it = begin; it != end;) {
+    if (!condition(&*it)) {
+      ++it;
+      continue;
+    }
+
+    removed = true;
+    // `it` is an iterator on an intrusive list. Next is invalidated on the
+    // current node when an instruction is killed. The iterator must be moved
+    // forward before deleting the node.
+    auto instruction = &*it;
+    ++it;
+    KillInst(instruction);
+  }
+
+  return removed;
+}
+
 void IRContext::CollectNonSemanticTree(
 void IRContext::CollectNonSemanticTree(
     Instruction* inst, std::unordered_set<Instruction*>* to_kill) {
     Instruction* inst, std::unordered_set<Instruction*>* to_kill) {
   if (!inst->HasResultId()) return;
   if (!inst->HasResultId()) return;
@@ -251,6 +273,36 @@ bool IRContext::KillDef(uint32_t id) {
   return false;
   return false;
 }
 }
 
 
+bool IRContext::RemoveCapability(spv::Capability capability) {
+  const bool removed = KillInstructionIf(
+      module()->capability_begin(), module()->capability_end(),
+      [capability](Instruction* inst) {
+        return static_cast<spv::Capability>(inst->GetSingleWordOperand(0)) ==
+               capability;
+      });
+
+  if (removed && feature_mgr_ != nullptr) {
+    feature_mgr_->RemoveCapability(capability);
+  }
+
+  return removed;
+}
+
+bool IRContext::RemoveExtension(Extension extension) {
+  const std::string_view extensionName = ExtensionToString(extension);
+  const bool removed = KillInstructionIf(
+      module()->extension_begin(), module()->extension_end(),
+      [&extensionName](Instruction* inst) {
+        return inst->GetOperand(0).AsString() == extensionName;
+      });
+
+  if (removed && feature_mgr_ != nullptr) {
+    feature_mgr_->RemoveExtension(extension);
+  }
+
+  return removed;
+}
+
 bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
 bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
   return ReplaceAllUsesWithPredicate(before, after,
   return ReplaceAllUsesWithPredicate(before, after,
                                      [](Instruction*) { return true; });
                                      [](Instruction*) { return true; });
@@ -718,7 +770,7 @@ void IRContext::AddCombinatorsForExtension(Instruction* extension) {
 }
 }
 
 
 void IRContext::InitializeCombinators() {
 void IRContext::InitializeCombinators() {
-  for (auto capability : *get_feature_mgr()->GetCapabilities()) {
+  for (auto capability : get_feature_mgr()->GetCapabilities()) {
     AddCombinatorsForCapability(uint32_t(capability));
     AddCombinatorsForCapability(uint32_t(capability));
   }
   }
 
 

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

@@ -27,6 +27,7 @@
 #include <vector>
 #include <vector>
 
 
 #include "source/assembly_grammar.h"
 #include "source/assembly_grammar.h"
+#include "source/enum_string_mapping.h"
 #include "source/opt/cfg.h"
 #include "source/opt/cfg.h"
 #include "source/opt/constants.h"
 #include "source/opt/constants.h"
 #include "source/opt/debug_info_manager.h"
 #include "source/opt/debug_info_manager.h"
@@ -153,13 +154,19 @@ class IRContext {
   inline IteratorRange<Module::inst_iterator> capabilities();
   inline IteratorRange<Module::inst_iterator> capabilities();
   inline IteratorRange<Module::const_inst_iterator> capabilities() const;
   inline IteratorRange<Module::const_inst_iterator> capabilities() const;
 
 
+  // Iterators for extensions instructions contained in this module.
+  inline Module::inst_iterator extension_begin();
+  inline Module::inst_iterator extension_end();
+  inline IteratorRange<Module::inst_iterator> extensions();
+  inline IteratorRange<Module::const_inst_iterator> extensions() const;
+
   // Iterators for types, constants and global variables instructions.
   // Iterators for types, constants and global variables instructions.
   inline Module::inst_iterator types_values_begin();
   inline Module::inst_iterator types_values_begin();
   inline Module::inst_iterator types_values_end();
   inline Module::inst_iterator types_values_end();
   inline IteratorRange<Module::inst_iterator> types_values();
   inline IteratorRange<Module::inst_iterator> types_values();
   inline IteratorRange<Module::const_inst_iterator> types_values() const;
   inline IteratorRange<Module::const_inst_iterator> types_values() const;
 
 
-  // Iterators for extension instructions contained in this module.
+  // Iterators for ext_inst import instructions contained in this module.
   inline Module::inst_iterator ext_inst_import_begin();
   inline Module::inst_iterator ext_inst_import_begin();
   inline Module::inst_iterator ext_inst_import_end();
   inline Module::inst_iterator ext_inst_import_end();
   inline IteratorRange<Module::inst_iterator> ext_inst_imports();
   inline IteratorRange<Module::inst_iterator> ext_inst_imports();
@@ -204,12 +211,19 @@ class IRContext {
 
 
   // Add |capability| to the module, if it is not already enabled.
   // Add |capability| to the module, if it is not already enabled.
   inline void AddCapability(spv::Capability capability);
   inline void AddCapability(spv::Capability capability);
-
   // Appends a capability instruction to this module.
   // Appends a capability instruction to this module.
   inline void AddCapability(std::unique_ptr<Instruction>&& c);
   inline void AddCapability(std::unique_ptr<Instruction>&& c);
+  // Removes instruction declaring `capability` from this module.
+  // Returns true if the capability was removed, false otherwise.
+  bool RemoveCapability(spv::Capability capability);
+
   // Appends an extension instruction to this module.
   // Appends an extension instruction to this module.
   inline void AddExtension(const std::string& ext_name);
   inline void AddExtension(const std::string& ext_name);
   inline void AddExtension(std::unique_ptr<Instruction>&& e);
   inline void AddExtension(std::unique_ptr<Instruction>&& e);
+  // Removes instruction declaring `extension` from this module.
+  // Returns true if the extension was removed, false otherwise.
+  bool RemoveExtension(Extension extension);
+
   // Appends an extended instruction set instruction to this module.
   // Appends an extended instruction set instruction to this module.
   inline void AddExtInstImport(const std::string& name);
   inline void AddExtInstImport(const std::string& name);
   inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
   inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
@@ -422,6 +436,15 @@ class IRContext {
   // instruction exists.
   // instruction exists.
   Instruction* KillInst(Instruction* inst);
   Instruction* KillInst(Instruction* inst);
 
 
+  // Deletes all the instruction in the range [`begin`; `end`[, for which the
+  // unary predicate `condition` returned true.
+  // Returns true if at least one instruction was removed, false otherwise.
+  //
+  // Pointer and iterator pointing to the deleted instructions become invalid.
+  // However other pointers and iterators are still valid.
+  bool KillInstructionIf(Module::inst_iterator begin, Module::inst_iterator end,
+                         std::function<bool(Instruction*)> condition);
+
   // Collects the non-semantic instruction tree that uses |inst|'s result id
   // Collects the non-semantic instruction tree that uses |inst|'s result id
   // to be killed later.
   // to be killed later.
   void CollectNonSemanticTree(Instruction* inst,
   void CollectNonSemanticTree(Instruction* inst,
@@ -772,7 +795,8 @@ class IRContext {
 
 
   // Analyzes the features in the owned module. Builds the manager if required.
   // Analyzes the features in the owned module. Builds the manager if required.
   void AnalyzeFeatures() {
   void AnalyzeFeatures() {
-    feature_mgr_ = MakeUnique<FeatureManager>(grammar_);
+    feature_mgr_ =
+        std::unique_ptr<FeatureManager>(new FeatureManager(grammar_));
     feature_mgr_->Analyze(module());
     feature_mgr_->Analyze(module());
   }
   }
 
 
@@ -964,6 +988,22 @@ IteratorRange<Module::const_inst_iterator> IRContext::capabilities() const {
   return ((const Module*)module())->capabilities();
   return ((const Module*)module())->capabilities();
 }
 }
 
 
+Module::inst_iterator IRContext::extension_begin() {
+  return module()->extension_begin();
+}
+
+Module::inst_iterator IRContext::extension_end() {
+  return module()->extension_end();
+}
+
+IteratorRange<Module::inst_iterator> IRContext::extensions() {
+  return module()->extensions();
+}
+
+IteratorRange<Module::const_inst_iterator> IRContext::extensions() const {
+  return ((const Module*)module())->extensions();
+}
+
 Module::inst_iterator IRContext::types_values_begin() {
 Module::inst_iterator IRContext::types_values_begin() {
   return module()->types_values_begin();
   return module()->types_values_begin();
 }
 }

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

@@ -427,7 +427,7 @@ void LocalAccessChainConvertPass::InitExtensions() {
        "SPV_EXT_shader_image_int64", "SPV_KHR_non_semantic_info",
        "SPV_EXT_shader_image_int64", "SPV_KHR_non_semantic_info",
        "SPV_KHR_uniform_group_instructions",
        "SPV_KHR_uniform_group_instructions",
        "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model",
        "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model",
-       "SPV_NV_bindless_texture"});
+       "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add"});
 }
 }
 
 
 bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds(
 bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds(

+ 55 - 56
3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp

@@ -233,62 +233,61 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::Process() {
 
 
 void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
 void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
   extensions_allowlist_.clear();
   extensions_allowlist_.clear();
-  extensions_allowlist_.insert({
-      "SPV_AMD_shader_explicit_vertex_parameter",
-      "SPV_AMD_shader_trinary_minmax",
-      "SPV_AMD_gcn_shader",
-      "SPV_KHR_shader_ballot",
-      "SPV_AMD_shader_ballot",
-      "SPV_AMD_gpu_shader_half_float",
-      "SPV_KHR_shader_draw_parameters",
-      "SPV_KHR_subgroup_vote",
-      "SPV_KHR_8bit_storage",
-      "SPV_KHR_16bit_storage",
-      "SPV_KHR_device_group",
-      "SPV_KHR_multiview",
-      "SPV_NVX_multiview_per_view_attributes",
-      "SPV_NV_viewport_array2",
-      "SPV_NV_stereo_view_rendering",
-      "SPV_NV_sample_mask_override_coverage",
-      "SPV_NV_geometry_shader_passthrough",
-      "SPV_AMD_texture_gather_bias_lod",
-      "SPV_KHR_storage_buffer_storage_class",
-      "SPV_KHR_variable_pointers",
-      "SPV_AMD_gpu_shader_int16",
-      "SPV_KHR_post_depth_coverage",
-      "SPV_KHR_shader_atomic_counter_ops",
-      "SPV_EXT_shader_stencil_export",
-      "SPV_EXT_shader_viewport_index_layer",
-      "SPV_AMD_shader_image_load_store_lod",
-      "SPV_AMD_shader_fragment_mask",
-      "SPV_EXT_fragment_fully_covered",
-      "SPV_AMD_gpu_shader_half_float_fetch",
-      "SPV_GOOGLE_decorate_string",
-      "SPV_GOOGLE_hlsl_functionality1",
-      "SPV_GOOGLE_user_type",
-      "SPV_NV_shader_subgroup_partitioned",
-      "SPV_EXT_demote_to_helper_invocation",
-      "SPV_EXT_descriptor_indexing",
-      "SPV_NV_fragment_shader_barycentric",
-      "SPV_NV_compute_shader_derivatives",
-      "SPV_NV_shader_image_footprint",
-      "SPV_NV_shading_rate",
-      "SPV_NV_mesh_shader",
-      "SPV_NV_ray_tracing",
-      "SPV_KHR_ray_tracing",
-      "SPV_KHR_ray_query",
-      "SPV_EXT_fragment_invocation_density",
-      "SPV_EXT_physical_storage_buffer",
-      "SPV_KHR_terminate_invocation",
-      "SPV_KHR_subgroup_uniform_control_flow",
-      "SPV_KHR_integer_dot_product",
-      "SPV_EXT_shader_image_int64",
-      "SPV_KHR_non_semantic_info",
-      "SPV_KHR_uniform_group_instructions",
-      "SPV_KHR_fragment_shader_barycentric",
-      "SPV_KHR_vulkan_memory_model",
-      "SPV_NV_bindless_texture",
-  });
+  extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter",
+                                "SPV_AMD_shader_trinary_minmax",
+                                "SPV_AMD_gcn_shader",
+                                "SPV_KHR_shader_ballot",
+                                "SPV_AMD_shader_ballot",
+                                "SPV_AMD_gpu_shader_half_float",
+                                "SPV_KHR_shader_draw_parameters",
+                                "SPV_KHR_subgroup_vote",
+                                "SPV_KHR_8bit_storage",
+                                "SPV_KHR_16bit_storage",
+                                "SPV_KHR_device_group",
+                                "SPV_KHR_multiview",
+                                "SPV_NVX_multiview_per_view_attributes",
+                                "SPV_NV_viewport_array2",
+                                "SPV_NV_stereo_view_rendering",
+                                "SPV_NV_sample_mask_override_coverage",
+                                "SPV_NV_geometry_shader_passthrough",
+                                "SPV_AMD_texture_gather_bias_lod",
+                                "SPV_KHR_storage_buffer_storage_class",
+                                "SPV_KHR_variable_pointers",
+                                "SPV_AMD_gpu_shader_int16",
+                                "SPV_KHR_post_depth_coverage",
+                                "SPV_KHR_shader_atomic_counter_ops",
+                                "SPV_EXT_shader_stencil_export",
+                                "SPV_EXT_shader_viewport_index_layer",
+                                "SPV_AMD_shader_image_load_store_lod",
+                                "SPV_AMD_shader_fragment_mask",
+                                "SPV_EXT_fragment_fully_covered",
+                                "SPV_AMD_gpu_shader_half_float_fetch",
+                                "SPV_GOOGLE_decorate_string",
+                                "SPV_GOOGLE_hlsl_functionality1",
+                                "SPV_GOOGLE_user_type",
+                                "SPV_NV_shader_subgroup_partitioned",
+                                "SPV_EXT_demote_to_helper_invocation",
+                                "SPV_EXT_descriptor_indexing",
+                                "SPV_NV_fragment_shader_barycentric",
+                                "SPV_NV_compute_shader_derivatives",
+                                "SPV_NV_shader_image_footprint",
+                                "SPV_NV_shading_rate",
+                                "SPV_NV_mesh_shader",
+                                "SPV_NV_ray_tracing",
+                                "SPV_KHR_ray_tracing",
+                                "SPV_KHR_ray_query",
+                                "SPV_EXT_fragment_invocation_density",
+                                "SPV_EXT_physical_storage_buffer",
+                                "SPV_KHR_terminate_invocation",
+                                "SPV_KHR_subgroup_uniform_control_flow",
+                                "SPV_KHR_integer_dot_product",
+                                "SPV_EXT_shader_image_int64",
+                                "SPV_KHR_non_semantic_info",
+                                "SPV_KHR_uniform_group_instructions",
+                                "SPV_KHR_fragment_shader_barycentric",
+                                "SPV_KHR_vulkan_memory_model",
+                                "SPV_NV_bindless_texture",
+                                "SPV_EXT_shader_atomic_float_add"});
 }
 }
 
 
 }  // namespace opt
 }  // namespace opt

+ 52 - 53
3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp

@@ -86,59 +86,58 @@ Pass::Status LocalSingleStoreElimPass::Process() {
 }
 }
 
 
 void LocalSingleStoreElimPass::InitExtensionAllowList() {
 void LocalSingleStoreElimPass::InitExtensionAllowList() {
-  extensions_allowlist_.insert({
-      "SPV_AMD_shader_explicit_vertex_parameter",
-      "SPV_AMD_shader_trinary_minmax",
-      "SPV_AMD_gcn_shader",
-      "SPV_KHR_shader_ballot",
-      "SPV_AMD_shader_ballot",
-      "SPV_AMD_gpu_shader_half_float",
-      "SPV_KHR_shader_draw_parameters",
-      "SPV_KHR_subgroup_vote",
-      "SPV_KHR_8bit_storage",
-      "SPV_KHR_16bit_storage",
-      "SPV_KHR_device_group",
-      "SPV_KHR_multiview",
-      "SPV_NVX_multiview_per_view_attributes",
-      "SPV_NV_viewport_array2",
-      "SPV_NV_stereo_view_rendering",
-      "SPV_NV_sample_mask_override_coverage",
-      "SPV_NV_geometry_shader_passthrough",
-      "SPV_AMD_texture_gather_bias_lod",
-      "SPV_KHR_storage_buffer_storage_class",
-      "SPV_KHR_variable_pointers",
-      "SPV_AMD_gpu_shader_int16",
-      "SPV_KHR_post_depth_coverage",
-      "SPV_KHR_shader_atomic_counter_ops",
-      "SPV_EXT_shader_stencil_export",
-      "SPV_EXT_shader_viewport_index_layer",
-      "SPV_AMD_shader_image_load_store_lod",
-      "SPV_AMD_shader_fragment_mask",
-      "SPV_EXT_fragment_fully_covered",
-      "SPV_AMD_gpu_shader_half_float_fetch",
-      "SPV_GOOGLE_decorate_string",
-      "SPV_GOOGLE_hlsl_functionality1",
-      "SPV_NV_shader_subgroup_partitioned",
-      "SPV_EXT_descriptor_indexing",
-      "SPV_NV_fragment_shader_barycentric",
-      "SPV_NV_compute_shader_derivatives",
-      "SPV_NV_shader_image_footprint",
-      "SPV_NV_shading_rate",
-      "SPV_NV_mesh_shader",
-      "SPV_NV_ray_tracing",
-      "SPV_KHR_ray_query",
-      "SPV_EXT_fragment_invocation_density",
-      "SPV_EXT_physical_storage_buffer",
-      "SPV_KHR_terminate_invocation",
-      "SPV_KHR_subgroup_uniform_control_flow",
-      "SPV_KHR_integer_dot_product",
-      "SPV_EXT_shader_image_int64",
-      "SPV_KHR_non_semantic_info",
-      "SPV_KHR_uniform_group_instructions",
-      "SPV_KHR_fragment_shader_barycentric",
-      "SPV_KHR_vulkan_memory_model",
-      "SPV_NV_bindless_texture",
-  });
+  extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter",
+                                "SPV_AMD_shader_trinary_minmax",
+                                "SPV_AMD_gcn_shader",
+                                "SPV_KHR_shader_ballot",
+                                "SPV_AMD_shader_ballot",
+                                "SPV_AMD_gpu_shader_half_float",
+                                "SPV_KHR_shader_draw_parameters",
+                                "SPV_KHR_subgroup_vote",
+                                "SPV_KHR_8bit_storage",
+                                "SPV_KHR_16bit_storage",
+                                "SPV_KHR_device_group",
+                                "SPV_KHR_multiview",
+                                "SPV_NVX_multiview_per_view_attributes",
+                                "SPV_NV_viewport_array2",
+                                "SPV_NV_stereo_view_rendering",
+                                "SPV_NV_sample_mask_override_coverage",
+                                "SPV_NV_geometry_shader_passthrough",
+                                "SPV_AMD_texture_gather_bias_lod",
+                                "SPV_KHR_storage_buffer_storage_class",
+                                "SPV_KHR_variable_pointers",
+                                "SPV_AMD_gpu_shader_int16",
+                                "SPV_KHR_post_depth_coverage",
+                                "SPV_KHR_shader_atomic_counter_ops",
+                                "SPV_EXT_shader_stencil_export",
+                                "SPV_EXT_shader_viewport_index_layer",
+                                "SPV_AMD_shader_image_load_store_lod",
+                                "SPV_AMD_shader_fragment_mask",
+                                "SPV_EXT_fragment_fully_covered",
+                                "SPV_AMD_gpu_shader_half_float_fetch",
+                                "SPV_GOOGLE_decorate_string",
+                                "SPV_GOOGLE_hlsl_functionality1",
+                                "SPV_NV_shader_subgroup_partitioned",
+                                "SPV_EXT_descriptor_indexing",
+                                "SPV_NV_fragment_shader_barycentric",
+                                "SPV_NV_compute_shader_derivatives",
+                                "SPV_NV_shader_image_footprint",
+                                "SPV_NV_shading_rate",
+                                "SPV_NV_mesh_shader",
+                                "SPV_NV_ray_tracing",
+                                "SPV_KHR_ray_query",
+                                "SPV_EXT_fragment_invocation_density",
+                                "SPV_EXT_physical_storage_buffer",
+                                "SPV_KHR_terminate_invocation",
+                                "SPV_KHR_subgroup_uniform_control_flow",
+                                "SPV_KHR_integer_dot_product",
+                                "SPV_EXT_shader_image_int64",
+                                "SPV_KHR_non_semantic_info",
+                                "SPV_KHR_uniform_group_instructions",
+                                "SPV_KHR_fragment_shader_barycentric",
+                                "SPV_KHR_vulkan_memory_model",
+                                "SPV_NV_bindless_texture",
+                                "SPV_EXT_shader_atomic_float_add"});
 }
 }
 bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
 bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
   std::vector<Instruction*> users;
   std::vector<Instruction*> users;

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

@@ -76,6 +76,11 @@ bool MemPass::IsNonPtrAccessChain(const spv::Op opcode) const {
 bool MemPass::IsPtr(uint32_t ptrId) {
 bool MemPass::IsPtr(uint32_t ptrId) {
   uint32_t varId = ptrId;
   uint32_t varId = ptrId;
   Instruction* ptrInst = get_def_use_mgr()->GetDef(varId);
   Instruction* ptrInst = get_def_use_mgr()->GetDef(varId);
+  if (ptrInst->opcode() == spv::Op::OpFunction) {
+    // A function is not a pointer, but it's return type could be, which will
+    // erroneously lead to this function returning true later on
+    return false;
+  }
   while (ptrInst->opcode() == spv::Op::OpCopyObject) {
   while (ptrInst->opcode() == spv::Op::OpCopyObject) {
     varId = ptrInst->GetSingleWordInOperand(kCopyObjectOperandInIdx);
     varId = ptrInst->GetSingleWordInOperand(kCopyObjectOperandInIdx);
     ptrInst = get_def_use_mgr()->GetDef(varId);
     ptrInst = get_def_use_mgr()->GetDef(varId);

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

@@ -17,6 +17,7 @@
 
 
 #include <functional>
 #include <functional>
 #include <memory>
 #include <memory>
+#include <string_view>
 #include <unordered_map>
 #include <unordered_map>
 #include <utility>
 #include <utility>
 #include <vector>
 #include <vector>

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

@@ -82,6 +82,7 @@
 #include "source/opt/strength_reduction_pass.h"
 #include "source/opt/strength_reduction_pass.h"
 #include "source/opt/strip_debug_info_pass.h"
 #include "source/opt/strip_debug_info_pass.h"
 #include "source/opt/strip_nonsemantic_info_pass.h"
 #include "source/opt/strip_nonsemantic_info_pass.h"
+#include "source/opt/trim_capabilities_pass.h"
 #include "source/opt/unify_const_pass.h"
 #include "source/opt/unify_const_pass.h"
 #include "source/opt/upgrade_memory_model.h"
 #include "source/opt/upgrade_memory_model.h"
 #include "source/opt/vector_dce.h"
 #include "source/opt/vector_dce.h"

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

@@ -0,0 +1,320 @@
+// Copyright (c) 2023 Google Inc.
+//
+// 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/trim_capabilities_pass.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <functional>
+#include <optional>
+#include <queue>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "source/enum_set.h"
+#include "source/enum_string_mapping.h"
+#include "source/opt/ir_context.h"
+#include "source/spirv_target_env.h"
+#include "source/util/string_utils.h"
+
+namespace spvtools {
+namespace opt {
+
+namespace {
+constexpr uint32_t kVariableStorageClassIndex = 0;
+constexpr uint32_t kTypeArrayTypeIndex = 0;
+constexpr uint32_t kOpTypeScalarBitWidthIndex = 0;
+constexpr uint32_t kTypePointerTypeIdInIdx = 1;
+}  // namespace
+
+// ============== Begin opcode handler implementations. =======================
+//
+// Adding support for a new capability should only require adding a new handler,
+// and updating the
+// kSupportedCapabilities/kUntouchableCapabilities/kFordiddenCapabilities lists.
+//
+// Handler names follow the following convention:
+//  Handler_<Opcode>_<Capability>()
+
+static std::optional<spv::Capability> Handler_OpVariable_StorageInputOutput16(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpVariable &&
+         "This handler only support OpVariable opcodes.");
+
+  // This capability is only required if the variable as an Input/Output storage
+  // class.
+  spv::StorageClass storage_class = spv::StorageClass(
+      instruction->GetSingleWordInOperand(kVariableStorageClassIndex));
+  if (storage_class != spv::StorageClass::Input &&
+      storage_class != spv::StorageClass::Output) {
+    return std::nullopt;
+  }
+
+  // This capability is only required if the type involves a 16-bit component.
+  // Quick check: are 16-bit types allowed?
+  const CapabilitySet& capabilities =
+      instruction->context()->get_feature_mgr()->GetCapabilities();
+  if (!capabilities.contains(spv::Capability::Float16) &&
+      !capabilities.contains(spv::Capability::Int16)) {
+    return std::nullopt;
+  }
+
+  // We need to walk the type definition.
+  std::queue<uint32_t> instructions_to_visit;
+  instructions_to_visit.push(instruction->type_id());
+  const auto* def_use_mgr = instruction->context()->get_def_use_mgr();
+  while (!instructions_to_visit.empty()) {
+    const Instruction* item =
+        def_use_mgr->GetDef(instructions_to_visit.front());
+    instructions_to_visit.pop();
+
+    if (item->opcode() == spv::Op::OpTypePointer) {
+      instructions_to_visit.push(
+          item->GetSingleWordInOperand(kTypePointerTypeIdInIdx));
+      continue;
+    }
+
+    if (item->opcode() == spv::Op::OpTypeMatrix ||
+        item->opcode() == spv::Op::OpTypeVector ||
+        item->opcode() == spv::Op::OpTypeArray ||
+        item->opcode() == spv::Op::OpTypeRuntimeArray) {
+      instructions_to_visit.push(
+          item->GetSingleWordInOperand(kTypeArrayTypeIndex));
+      continue;
+    }
+
+    if (item->opcode() == spv::Op::OpTypeStruct) {
+      item->ForEachInOperand([&instructions_to_visit](const uint32_t* op_id) {
+        instructions_to_visit.push(*op_id);
+      });
+      continue;
+    }
+
+    if (item->opcode() != spv::Op::OpTypeInt &&
+        item->opcode() != spv::Op::OpTypeFloat) {
+      continue;
+    }
+
+    if (item->GetSingleWordInOperand(kOpTypeScalarBitWidthIndex) == 16) {
+      return spv::Capability::StorageInputOutput16;
+    }
+  }
+
+  return std::nullopt;
+}
+
+// Opcode of interest to determine capabilities requirements.
+constexpr std::array<std::pair<spv::Op, OpcodeHandler>, 1> kOpcodeHandlers{{
+    {spv::Op::OpVariable, Handler_OpVariable_StorageInputOutput16},
+}};
+
+// ==============  End opcode handler implementations.  =======================
+
+namespace {
+ExtensionSet getExtensionsRelatedTo(const CapabilitySet& capabilities,
+                                    const AssemblyGrammar& grammar) {
+  ExtensionSet output;
+  const spv_operand_desc_t* desc = nullptr;
+  for (auto capability : capabilities) {
+    if (SPV_SUCCESS != grammar.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
+                                             static_cast<uint32_t>(capability),
+                                             &desc)) {
+      continue;
+    }
+
+    for (uint32_t i = 0; i < desc->numExtensions; ++i) {
+      output.insert(desc->extensions[i]);
+    }
+  }
+
+  return output;
+}
+}  // namespace
+
+TrimCapabilitiesPass::TrimCapabilitiesPass()
+    : supportedCapabilities_(
+          TrimCapabilitiesPass::kSupportedCapabilities.cbegin(),
+          TrimCapabilitiesPass::kSupportedCapabilities.cend()),
+      forbiddenCapabilities_(
+          TrimCapabilitiesPass::kForbiddenCapabilities.cbegin(),
+          TrimCapabilitiesPass::kForbiddenCapabilities.cend()),
+      untouchableCapabilities_(
+          TrimCapabilitiesPass::kUntouchableCapabilities.cbegin(),
+          TrimCapabilitiesPass::kUntouchableCapabilities.cend()),
+      opcodeHandlers_(kOpcodeHandlers.cbegin(), kOpcodeHandlers.cend()) {}
+
+void TrimCapabilitiesPass::addInstructionRequirements(
+    Instruction* instruction, CapabilitySet* capabilities,
+    ExtensionSet* extensions) const {
+  // Ignoring OpCapability instructions.
+  if (instruction->opcode() == spv::Op::OpCapability) {
+    return;
+  }
+
+  // First case: the opcode is itself gated by a capability.
+  {
+    const spv_opcode_desc_t* desc = {};
+    auto result =
+        context()->grammar().lookupOpcode(instruction->opcode(), &desc);
+    if (result == SPV_SUCCESS) {
+      addSupportedCapabilitiesToSet(desc->numCapabilities, desc->capabilities,
+                                    capabilities);
+      if (desc->minVersion <=
+          spvVersionForTargetEnv(context()->GetTargetEnv())) {
+        extensions->insert(desc->extensions,
+                           desc->extensions + desc->numExtensions);
+      }
+    }
+  }
+
+  // Second case: one of the opcode operand is gated by a capability.
+  const uint32_t operandCount = instruction->NumOperands();
+  for (uint32_t i = 0; i < operandCount; i++) {
+    const auto& operand = instruction->GetOperand(i);
+    // No supported capability relies on a 2+-word operand.
+    if (operand.words.size() != 1) {
+      continue;
+    }
+
+    // No supported capability relies on a literal string operand.
+    if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING) {
+      continue;
+    }
+
+    const spv_operand_desc_t* desc = {};
+    auto result = context()->grammar().lookupOperand(operand.type,
+                                                     operand.words[0], &desc);
+    if (result != SPV_SUCCESS) {
+      continue;
+    }
+
+    addSupportedCapabilitiesToSet(desc->numCapabilities, desc->capabilities,
+                                  capabilities);
+    if (desc->minVersion <= spvVersionForTargetEnv(context()->GetTargetEnv())) {
+      extensions->insert(desc->extensions,
+                         desc->extensions + desc->numExtensions);
+    }
+  }
+
+  // Last case: some complex logic needs to be run to determine capabilities.
+  auto[begin, end] = opcodeHandlers_.equal_range(instruction->opcode());
+  for (auto it = begin; it != end; it++) {
+    const OpcodeHandler handler = it->second;
+    auto result = handler(instruction);
+    if (result.has_value()) {
+      capabilities->insert(*result);
+    }
+  }
+}
+
+std::pair<CapabilitySet, ExtensionSet>
+TrimCapabilitiesPass::DetermineRequiredCapabilitiesAndExtensions() const {
+  CapabilitySet required_capabilities;
+  ExtensionSet required_extensions;
+
+  get_module()->ForEachInst([&](Instruction* instruction) {
+    addInstructionRequirements(instruction, &required_capabilities,
+                               &required_extensions);
+  });
+
+#if !defined(NDEBUG)
+  // Debug only. We check the outputted required capabilities against the
+  // supported capabilities list. The supported capabilities list is useful for
+  // API users to quickly determine if they can use the pass or not. But this
+  // list has to remain up-to-date with the pass code. If we can detect a
+  // capability as required, but it's not listed, it means the list is
+  // out-of-sync. This method is not ideal, but should cover most cases.
+  {
+    for (auto capability : required_capabilities) {
+      assert(supportedCapabilities_.contains(capability) &&
+             "Module is using a capability that is not listed as supported.");
+    }
+  }
+#endif
+
+  return std::make_pair(std::move(required_capabilities),
+                        std::move(required_extensions));
+}
+
+Pass::Status TrimCapabilitiesPass::TrimUnrequiredCapabilities(
+    const CapabilitySet& required_capabilities) const {
+  const FeatureManager* feature_manager = context()->get_feature_mgr();
+  CapabilitySet capabilities_to_trim;
+  for (auto capability : feature_manager->GetCapabilities()) {
+    // Forbidden capability completely prevents trimming. Early exit.
+    if (forbiddenCapabilities_.contains(capability)) {
+      return Pass::Status::SuccessWithoutChange;
+    }
+
+    // Some capabilities cannot be safely removed. Leaving them untouched.
+    if (untouchableCapabilities_.contains(capability)) {
+      continue;
+    }
+
+    // If the capability is unsupported, don't trim it.
+    if (!supportedCapabilities_.contains(capability)) {
+      continue;
+    }
+
+    if (required_capabilities.contains(capability)) {
+      continue;
+    }
+
+    capabilities_to_trim.insert(capability);
+  }
+
+  for (auto capability : capabilities_to_trim) {
+    context()->RemoveCapability(capability);
+  }
+
+  return capabilities_to_trim.size() == 0 ? Pass::Status::SuccessWithoutChange
+                                          : Pass::Status::SuccessWithChange;
+}
+
+Pass::Status TrimCapabilitiesPass::TrimUnrequiredExtensions(
+    const ExtensionSet& required_extensions) const {
+  const auto supported_extensions =
+      getExtensionsRelatedTo(supportedCapabilities_, context()->grammar());
+
+  bool modified_module = false;
+  for (auto extension : supported_extensions) {
+    if (!required_extensions.contains(extension)) {
+      modified_module = true;
+      context()->RemoveExtension(extension);
+    }
+  }
+
+  return modified_module ? Pass::Status::SuccessWithChange
+                         : Pass::Status::SuccessWithoutChange;
+}
+
+Pass::Status TrimCapabilitiesPass::Process() {
+  auto[required_capabilities, required_extensions] =
+      DetermineRequiredCapabilitiesAndExtensions();
+
+  Pass::Status status = TrimUnrequiredCapabilities(required_capabilities);
+  // If no capabilities were removed, we have no extension to trim.
+  // Note: this is true because this pass only removes unused extensions caused
+  // by unused capabilities.
+  //       This is not an extension trimming pass.
+  if (status == Pass::Status::SuccessWithoutChange) {
+    return status;
+  }
+  return TrimUnrequiredExtensions(required_extensions);
+}
+
+}  // namespace opt
+}  // namespace spvtools

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

@@ -0,0 +1,151 @@
+// Copyright (c) 2023 Google Inc.
+//
+// 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_TRIM_CAPABILITIES_PASS_H_
+#define SOURCE_OPT_TRIM_CAPABILITIES_PASS_H_
+
+#include <algorithm>
+#include <array>
+#include <functional>
+#include <optional>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "source/enum_set.h"
+#include "source/extensions.h"
+#include "source/opt/ir_context.h"
+#include "source/opt/module.h"
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// This is required for NDK build. The unordered_set/unordered_map
+// implementation don't work with class enums.
+struct ClassEnumHash {
+  std::size_t operator()(spv::Capability value) const {
+    using StoringType = typename std::underlying_type_t<spv::Capability>;
+    return std::hash<StoringType>{}(static_cast<StoringType>(value));
+  }
+
+  std::size_t operator()(spv::Op value) const {
+    using StoringType = typename std::underlying_type_t<spv::Op>;
+    return std::hash<StoringType>{}(static_cast<StoringType>(value));
+  }
+};
+
+// An opcode handler is a function which, given an instruction, returns either
+// the required capability, or nothing.
+// Each handler checks one case for a capability requirement.
+//
+// Example:
+//  - `OpTypeImage` can have operand `A` operand which requires capability 1
+//  - `OpTypeImage` can also have operand `B` which requires capability 2.
+//    -> We have 2 handlers: `Handler_OpTypeImage_1` and
+//    `Handler_OpTypeImage_2`.
+using OpcodeHandler =
+    std::optional<spv::Capability> (*)(const Instruction* instruction);
+
+// This pass tried to remove superfluous capabilities declared in the module.
+// - If all the capabilities listed by an extension are removed, the extension
+//   is also trimmed.
+// - If the module countains any capability listed in `kForbiddenCapabilities`,
+//   the module is left untouched.
+// - No capabilities listed in `kUntouchableCapabilities` are trimmed, even when
+//   not used.
+// - Only capabilitied listed in `kSupportedCapabilities` are supported.
+// - If the module contains unsupported capabilities, results might be
+//   incorrect.
+class TrimCapabilitiesPass : public Pass {
+ private:
+  // All the capabilities supported by this optimization pass. If your module
+  // contains unsupported instruction, the pass could yield bad results.
+  static constexpr std::array kSupportedCapabilities{
+      // clang-format off
+      spv::Capability::Groups,
+      spv::Capability::Linkage,
+      spv::Capability::MinLod,
+      spv::Capability::Shader,
+      spv::Capability::ShaderClockKHR,
+      spv::Capability::StorageInputOutput16
+      // clang-format on
+  };
+
+  // Those capabilities disable all transformation of the module.
+  static constexpr std::array kForbiddenCapabilities{
+      spv::Capability::Linkage,
+  };
+
+  // Those capabilities are never removed from a module because we cannot
+  // guess from the SPIR-V only if they are required or not.
+  static constexpr std::array kUntouchableCapabilities{
+      spv::Capability::Shader,
+  };
+
+ public:
+  TrimCapabilitiesPass();
+  TrimCapabilitiesPass(const TrimCapabilitiesPass&) = delete;
+  TrimCapabilitiesPass(TrimCapabilitiesPass&&) = delete;
+
+ private:
+  // Inserts every capability in `capabilities[capabilityCount]` supported by
+  // this pass into `output`.
+  inline void addSupportedCapabilitiesToSet(
+      uint32_t capabilityCount, const spv::Capability* const capabilities,
+      CapabilitySet* output) const {
+    for (uint32_t i = 0; i < capabilityCount; ++i) {
+      if (supportedCapabilities_.contains(capabilities[i])) {
+        output->insert(capabilities[i]);
+      }
+    }
+  }
+
+  // Given an `instruction`, determines the capabilities and extension it
+  // requires, and output them in `capabilities` and `extensions`. The returned
+  // capabilities form a subset of kSupportedCapabilities.
+  void addInstructionRequirements(Instruction* instruction,
+                                  CapabilitySet* capabilities,
+                                  ExtensionSet* extensions) const;
+
+  // Returns the list of required capabilities and extensions for the module.
+  // The returned capabilities form a subset of kSupportedCapabilities.
+  std::pair<CapabilitySet, ExtensionSet>
+  DetermineRequiredCapabilitiesAndExtensions() const;
+
+  // Trims capabilities not listed in `required_capabilities` if possible.
+  // Returns whether or not the module was modified.
+  Pass::Status TrimUnrequiredCapabilities(
+      const CapabilitySet& required_capabilities) const;
+
+  // Trims extensions not listed in `required_extensions` if supported by this
+  // pass. An extensions is considered supported as soon as one capability this
+  // pass support requires it.
+  Pass::Status TrimUnrequiredExtensions(
+      const ExtensionSet& required_extensions) const;
+
+ public:
+  const char* name() const override { return "trim-capabilities"; }
+  Status Process() override;
+
+ private:
+  const CapabilitySet supportedCapabilities_;
+  const CapabilitySet forbiddenCapabilities_;
+  const CapabilitySet untouchableCapabilities_;
+  const std::unordered_multimap<spv::Op, OpcodeHandler, ClassEnumHash>
+      opcodeHandlers_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+#endif  // SOURCE_OPT_TRIM_CAPABILITIES_H_

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

@@ -24,6 +24,7 @@ namespace spvtools {
 void EmitNumericLiteral(std::ostream* out, const spv_parsed_instruction_t& inst,
 void EmitNumericLiteral(std::ostream* out, const spv_parsed_instruction_t& inst,
                         const spv_parsed_operand_t& operand) {
                         const spv_parsed_operand_t& operand) {
   if (operand.type != SPV_OPERAND_TYPE_LITERAL_INTEGER &&
   if (operand.type != SPV_OPERAND_TYPE_LITERAL_INTEGER &&
+      operand.type != SPV_OPERAND_TYPE_LITERAL_FLOAT &&
       operand.type != SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER &&
       operand.type != SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER &&
       operand.type != SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER &&
       operand.type != SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER &&
       operand.type != SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER)
       operand.type != SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER)

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

@@ -312,6 +312,17 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar,
       }
       }
     } break;
     } break;
 
 
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT: {
+      // The current operand is a 32-bit float.
+      // That's just how the grammar works.
+      spvtools::IdType expected_type = {
+          32, false, spvtools::IdTypeClass::kScalarFloatType};
+      if (auto error = context->binaryEncodeNumericLiteral(
+              textValue, error_code_for_literals, expected_type, pInst)) {
+        return error;
+      }
+    } break;
+
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
       // This is a context-independent literal number which can be a 32-bit
       // This is a context-independent literal number which can be a 32-bit
       // number of floating point value.
       // number of floating point value.

Some files were not shown because too many files changed in this diff