瀏覽代碼

Updated spirv-tools.

Бранимир Караџић 3 年之前
父節點
當前提交
e8abac2374
共有 85 個文件被更改,包括 735 次插入216 次删除
  1. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  2. 7 4
      3rdparty/spirv-tools/include/spirv-tools/libspirv.h
  3. 2 2
      3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp
  4. 25 12
      3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp
  5. 1 1
      3rdparty/spirv-tools/source/binary.cpp
  6. 1 0
      3rdparty/spirv-tools/source/ext_inst.cpp
  7. 2 2
      3rdparty/spirv-tools/source/ext_inst.h
  8. 123 68
      3rdparty/spirv-tools/source/link/linker.cpp
  9. 2 2
      3rdparty/spirv-tools/source/opcode.cpp
  10. 1 1
      3rdparty/spirv-tools/source/opt/amd_ext_to_khr.h
  11. 1 1
      3rdparty/spirv-tools/source/opt/basic_block.h
  12. 1 1
      3rdparty/spirv-tools/source/opt/cfg.h
  13. 2 2
      3rdparty/spirv-tools/source/opt/const_folding_rules.cpp
  14. 1 1
      3rdparty/spirv-tools/source/opt/constants.h
  15. 1 1
      3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp
  16. 1 1
      3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.h
  17. 1 1
      3rdparty/spirv-tools/source/opt/debug_info_manager.cpp
  18. 2 2
      3rdparty/spirv-tools/source/opt/def_use_manager.h
  19. 3 3
      3rdparty/spirv-tools/source/opt/desc_sroa.cpp
  20. 2 2
      3rdparty/spirv-tools/source/opt/dominator_tree.cpp
  21. 2 2
      3rdparty/spirv-tools/source/opt/eliminate_dead_members_pass.cpp
  22. 1 1
      3rdparty/spirv-tools/source/opt/fold.cpp
  23. 1 1
      3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp
  24. 3 3
      3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp
  25. 1 1
      3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.h
  26. 2 2
      3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h
  27. 1 1
      3rdparty/spirv-tools/source/opt/instruction.h
  28. 3 3
      3rdparty/spirv-tools/source/opt/instrument_pass.h
  29. 1 1
      3rdparty/spirv-tools/source/opt/ir_context.cpp
  30. 3 3
      3rdparty/spirv-tools/source/opt/ir_context.h
  31. 1 1
      3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h
  32. 3 3
      3rdparty/spirv-tools/source/opt/loop_descriptor.cpp
  33. 1 1
      3rdparty/spirv-tools/source/opt/loop_descriptor.h
  34. 1 1
      3rdparty/spirv-tools/source/opt/loop_fission.cpp
  35. 1 1
      3rdparty/spirv-tools/source/opt/loop_fission.h
  36. 2 2
      3rdparty/spirv-tools/source/opt/loop_fusion.cpp
  37. 1 1
      3rdparty/spirv-tools/source/opt/loop_fusion.h
  38. 1 1
      3rdparty/spirv-tools/source/opt/loop_fusion_pass.h
  39. 1 1
      3rdparty/spirv-tools/source/opt/loop_peeling.h
  40. 5 5
      3rdparty/spirv-tools/source/opt/loop_unroller.cpp
  41. 1 1
      3rdparty/spirv-tools/source/opt/loop_unswitch_pass.cpp
  42. 1 1
      3rdparty/spirv-tools/source/opt/loop_unswitch_pass.h
  43. 2 2
      3rdparty/spirv-tools/source/opt/loop_utils.h
  44. 2 2
      3rdparty/spirv-tools/source/opt/merge_return_pass.h
  45. 7 0
      3rdparty/spirv-tools/source/opt/optimizer.cpp
  46. 1 1
      3rdparty/spirv-tools/source/opt/pass.h
  47. 2 2
      3rdparty/spirv-tools/source/opt/pass_manager.h
  48. 1 0
      3rdparty/spirv-tools/source/opt/passes.h
  49. 1 1
      3rdparty/spirv-tools/source/opt/private_to_local_pass.h
  50. 1 1
      3rdparty/spirv-tools/source/opt/redundancy_elimination.h
  51. 2 2
      3rdparty/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h
  52. 1 1
      3rdparty/spirv-tools/source/opt/scalar_analysis.cpp
  53. 1 1
      3rdparty/spirv-tools/source/opt/scalar_analysis_nodes.h
  54. 1 1
      3rdparty/spirv-tools/source/opt/scalar_analysis_simplification.cpp
  55. 314 0
      3rdparty/spirv-tools/source/opt/spread_volatile_semantics.cpp
  56. 110 0
      3rdparty/spirv-tools/source/opt/spread_volatile_semantics.h
  57. 1 1
      3rdparty/spirv-tools/source/opt/unify_const_pass.cpp
  58. 1 1
      3rdparty/spirv-tools/source/opt/vector_dce.h
  59. 1 1
      3rdparty/spirv-tools/source/reduce/remove_struct_member_reduction_opportunity.cpp
  60. 2 2
      3rdparty/spirv-tools/source/reduce/remove_unused_struct_member_reduction_opportunity_finder.cpp
  61. 2 2
      3rdparty/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp
  62. 1 1
      3rdparty/spirv-tools/source/spirv_definition.h
  63. 1 1
      3rdparty/spirv-tools/source/spirv_endian.h
  64. 12 2
      3rdparty/spirv-tools/source/spirv_target_env.cpp
  65. 1 1
      3rdparty/spirv-tools/source/spirv_target_env.h
  66. 1 0
      3rdparty/spirv-tools/source/table.cpp
  67. 1 1
      3rdparty/spirv-tools/source/util/bit_vector.h
  68. 1 1
      3rdparty/spirv-tools/source/util/ilist.h
  69. 1 1
      3rdparty/spirv-tools/source/util/parse_number.h
  70. 5 2
      3rdparty/spirv-tools/source/util/small_vector.h
  71. 3 3
      3rdparty/spirv-tools/source/util/timer.h
  72. 6 6
      3rdparty/spirv-tools/source/val/basic_block.h
  73. 2 2
      3rdparty/spirv-tools/source/val/function.cpp
  74. 5 5
      3rdparty/spirv-tools/source/val/function.h
  75. 1 1
      3rdparty/spirv-tools/source/val/validate.cpp
  76. 1 1
      3rdparty/spirv-tools/source/val/validate.h
  77. 1 1
      3rdparty/spirv-tools/source/val/validate_arithmetics.cpp
  78. 2 2
      3rdparty/spirv-tools/source/val/validate_cfg.cpp
  79. 2 2
      3rdparty/spirv-tools/source/val/validate_decorations.cpp
  80. 1 1
      3rdparty/spirv-tools/source/val/validate_extensions.cpp
  81. 5 4
      3rdparty/spirv-tools/source/val/validate_image.cpp
  82. 2 2
      3rdparty/spirv-tools/source/val/validate_instruction.cpp
  83. 2 2
      3rdparty/spirv-tools/source/val/validate_scopes.cpp
  84. 5 5
      3rdparty/spirv-tools/source/val/validation_state.cpp
  85. 3 3
      3rdparty/spirv-tools/source/val/validation_state.h

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

@@ -1 +1 @@
-"v2021.5-dev", "SPIRV-Tools v2021.5-dev 4581f14cd481bad1e0d6292f0dd0a6e298c2ee18"
+"v2022.2-dev", "SPIRV-Tools v2022.2-dev 2e9ea79f27f42b1ea49e66ce7ba0a5c1ab75ea81"

+ 7 - 4
3rdparty/spirv-tools/include/spirv-tools/libspirv.h

@@ -483,6 +483,7 @@ SPIRV_TOOLS_EXPORT const char* spvSoftwareVersionDetailsString(void);
 //    SPV_ENV_VULKAN_1_1           ->  SPIR-V 1.3
 //    SPV_ENV_VULKAN_1_1_SPIRV_1_4 ->  SPIR-V 1.4
 //    SPV_ENV_VULKAN_1_2           ->  SPIR-V 1.5
+//    SPV_ENV_VULKAN_1_3           ->  SPIR-V 1.6
 // Consult the description of API entry points for specific rules.
 typedef enum {
   SPV_ENV_UNIVERSAL_1_0,  // SPIR-V 1.0 latest revision, no other restrictions.
@@ -519,7 +520,9 @@ typedef enum {
   SPV_ENV_VULKAN_1_2,     // Vulkan 1.2 latest revision.
 
   SPV_ENV_UNIVERSAL_1_6,  // SPIR-V 1.6 latest revision, no other restrictions.
-  SPV_ENV_MAX             // Keep this as the last enum value.
+  SPV_ENV_VULKAN_1_3,     // Vulkan 1.3 latest revision.
+
+  SPV_ENV_MAX  // Keep this as the last enum value.
 } spv_target_env;
 
 // SPIR-V Validator can be parameterized with the following Universal Limits.
@@ -558,7 +561,7 @@ SPIRV_TOOLS_EXPORT bool spvParseVulkanEnv(uint32_t vulkan_ver,
 // Creates a context object for most of the SPIRV-Tools API.
 // Returns null if env is invalid.
 //
-// See specific API calls for how the target environment is interpeted
+// See specific API calls for how the target environment is interpreted
 // (particularly assembly and validation).
 SPIRV_TOOLS_EXPORT spv_context spvContextCreate(spv_target_env env);
 
@@ -610,7 +613,7 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetRelaxLogicalPointer(
 //    set that option.
 // 2) Pointers that are pass as parameters to function calls do not have to
 //    match the storage class of the formal parameter.
-// 3) Pointers that are actaul parameters on function calls do not have to point
+// 3) Pointers that are actual parameters on function calls do not have to point
 //    to the same type pointed as the formal parameter.  The types just need to
 //    logically match.
 // 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant
@@ -636,7 +639,7 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetUniformBufferStandardLayout(
 // Records whether the validator should use "scalar" block layout rules.
 // Scalar layout rules are more permissive than relaxed block layout.
 //
-// See Vulkan extnesion VK_EXT_scalar_block_layout.  The scalar alignment is
+// See Vulkan extension VK_EXT_scalar_block_layout.  The scalar alignment is
 // defined as follows:
 // - scalar alignment of a scalar is the scalar size
 // - scalar alignment of a vector is the scalar alignment of its component

+ 2 - 2
3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp

@@ -36,7 +36,7 @@ class Context {
  public:
   // Constructs a context targeting the given environment |env|.
   //
-  // See specific API calls for how the target environment is interpeted
+  // See specific API calls for how the target environment is interpreted
   // (particularly assembly and validation).
   //
   // The constructed instance will have an empty message consumer, which just
@@ -139,7 +139,7 @@ class ValidatorOptions {
   //    set that option.
   // 2) Pointers that are pass as parameters to function calls do not have to
   //    match the storage class of the formal parameter.
-  // 3) Pointers that are actaul parameters on function calls do not have to
+  // 3) Pointers that are actual parameters on function calls do not have to
   //    point to the same type pointed as the formal parameter.  The types just
   //    need to logically match.
   // 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant

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

@@ -43,7 +43,7 @@ class Optimizer {
   // consumed by the RegisterPass() method. Tokens are one-time objects that
   // only support move; copying is not allowed.
   struct PassToken {
-    struct Impl;  // Opaque struct for holding inernal data.
+    struct Impl;  // Opaque struct for holding internal data.
 
     PassToken(std::unique_ptr<Impl>);
 
@@ -227,7 +227,7 @@ Optimizer::PassToken CreateNullPass();
 
 // Creates a strip-debug-info pass.
 // A strip-debug-info pass removes all debug instructions (as documented in
-// Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized.
+// Section 3.42.2 of the SPIR-V spec) of the SPIR-V module to be optimized.
 Optimizer::PassToken CreateStripDebugInfoPass();
 
 // [Deprecated] This will create a strip-nonsemantic-info pass.  See below.
@@ -296,11 +296,11 @@ Optimizer::PassToken CreateFreezeSpecConstantValuePass();
 // and can be changed in future. A spec constant is foldable if all of its
 // value(s) can be determined from the module. E.g., an integer spec constant
 // defined with OpSpecConstantOp instruction can be folded if its value won't
-// change later. This pass will replace the original OpSpecContantOp instruction
-// with an OpConstant instruction. When folding composite spec constants,
-// new instructions may be inserted to define the components of the composite
-// constant first, then the original spec constants will be replaced by
-// OpConstantComposite instructions.
+// change later. This pass will replace the original OpSpecConstantOp
+// instruction with an OpConstant instruction. When folding composite spec
+// constants, new instructions may be inserted to define the components of the
+// composite constant first, then the original spec constants will be replaced
+// by OpConstantComposite instructions.
 //
 // There are some operations not supported yet:
 //   OpSConvert, OpFConvert, OpQuantizeToF16 and
@@ -326,7 +326,7 @@ Optimizer::PassToken CreateUnifyConstantPass();
 
 // Creates a eliminate-dead-constant pass.
 // A eliminate-dead-constant pass removes dead constants, including normal
-// contants defined by OpConstant, OpConstantComposite, OpConstantTrue, or
+// constants defined by OpConstant, OpConstantComposite, OpConstantTrue, or
 // OpConstantFalse and spec constants defined by OpSpecConstant,
 // OpSpecConstantComposite, OpSpecConstantTrue, OpSpecConstantFalse or
 // OpSpecConstantOp.
@@ -390,7 +390,7 @@ Optimizer::PassToken CreateInlineOpaquePass();
 // Only modules with relaxed logical addressing (see opt/instruction.h) are
 // currently processed.
 //
-// This pass is most effective if preceeded by Inlining and
+// This pass is most effective if preceded by Inlining and
 // LocalAccessChainConvert. This pass will reduce the work needed to be done
 // by LocalSingleStoreElim and LocalMultiStoreElim.
 //
@@ -408,7 +408,7 @@ Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass();
 // Note that some branches and blocks may be left to avoid creating invalid
 // control flow. Improving this is left to future work.
 //
-// This pass is most effective when preceeded by passes which eliminate
+// This pass is most effective when preceded by passes which eliminate
 // local loads and stores, effectively propagating constant values where
 // possible.
 Optimizer::PassToken CreateDeadBranchElimPass();
@@ -425,7 +425,7 @@ Optimizer::PassToken CreateDeadBranchElimPass();
 // are currently processed. Currently modules with any extensions enabled are
 // not processed. This is left for future work.
 //
-// This pass is most effective if preceeded by Inlining and
+// This pass is most effective if preceded by Inlining and
 // LocalAccessChainConvert. LocalSingleStoreElim and LocalSingleBlockElim
 // will reduce the work that this pass has to do.
 Optimizer::PassToken CreateLocalMultiStoreElimPass();
@@ -630,7 +630,7 @@ Optimizer::PassToken CreateRedundancyEliminationPass();
 Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit = 100);
 
 // Create a private to local pass.
-// This pass looks for variables delcared in the private storage class that are
+// This pass looks for variables declared in the private storage class that are
 // used in only one function.  Those variables are moved to the function storage
 // class in the function that they are used.
 Optimizer::PassToken CreatePrivateToLocalPass();
@@ -835,6 +835,19 @@ Optimizer::PassToken CreateFixStorageClassPass();
 //   inclusive.
 Optimizer::PassToken CreateGraphicsRobustAccessPass();
 
+// Create a pass to spread Volatile semantics to variables with SMIDNV,
+// WarpIDNV, SubgroupSize, SubgroupLocalInvocationId, SubgroupEqMask,
+// SubgroupGeMask, SubgroupGtMask, SubgroupLeMask, or SubgroupLtMask BuiltIn
+// decorations or OpLoad for them when the shader model is the ray generation,
+// closest hit, miss, intersection, or callable. This pass can be used for
+// VUID-StandaloneSpirv-VulkanMemoryModel-04678 and
+// VUID-StandaloneSpirv-VulkanMemoryModel-04679 (See "Standalone SPIR-V
+// Validation" section of Vulkan spec "Appendix A: Vulkan Environment for
+// SPIR-V"). When the SPIR-V version is 1.6 or above, the pass also spreads
+// the Volatile semantics to a variable with HelperInvocation BuiltIn decoration
+// in the fragement shader.
+Optimizer::PassToken CreateSpreadVolatileSemanticsPass();
+
 // Create a pass to replace a descriptor access using variable index.
 // This pass replaces every access using a variable index to array variable
 // |desc| that has a DescriptorSet and Binding decorations with a constant

+ 1 - 1
3rdparty/spirv-tools/source/binary.cpp

@@ -215,7 +215,7 @@ class Parser {
     size_t word_index;           // The current position in words.
     size_t instruction_count;    // The count of processed instructions
     spv_endianness_t endian;     // The endianness of the binary.
-    // Is the SPIR-V binary in a different endiannes from the host native
+    // Is the SPIR-V binary in a different endianness from the host native
     // endianness?
     bool requires_endian_conversion;
 

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

@@ -97,6 +97,7 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable,
     case SPV_ENV_UNIVERSAL_1_5:
     case SPV_ENV_VULKAN_1_2:
     case SPV_ENV_UNIVERSAL_1_6:
+    case SPV_ENV_VULKAN_1_3:
       *pExtInstTable = &kTable_1_0;
       return SPV_SUCCESS;
     default:

+ 2 - 2
3rdparty/spirv-tools/source/ext_inst.h

@@ -27,7 +27,7 @@ bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type);
 // Returns true if the extended instruction set is debug info
 bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type);
 
-// Finds the named extented instruction of the given type in the given extended
+// Finds the named extended instruction of the given type in the given extended
 // instruction table. On success, returns SPV_SUCCESS and writes a handle of
 // the instruction entry into *entry.
 spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
@@ -35,7 +35,7 @@ spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
                                        const char* name,
                                        spv_ext_inst_desc* entry);
 
-// Finds the extented instruction of the given type in the given extended
+// Finds the extended instruction of the given type in the given extended
 // instruction table by value. On success, returns SPV_SUCCESS and writes a
 // handle of the instruction entry into *entry.
 spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table,

+ 123 - 68
3rdparty/spirv-tools/source/link/linker.cpp

@@ -19,6 +19,7 @@
 #include <cstring>
 #include <iostream>
 #include <memory>
+#include <numeric>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
@@ -87,10 +88,6 @@ spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
 //
 // |header| should not be null, |modules| should not be empty and pointers
 // should be non-null. |max_id_bound| should be strictly greater than 0.
-//
-// TODO(pierremoreau): What to do when binaries use different versions of
-//                     SPIR-V? For now, use the max of all versions found in
-//                     the input modules.
 spv_result_t GenerateHeader(const MessageConsumer& consumer,
                             const std::vector<opt::Module*>& modules,
                             uint32_t max_id_bound, opt::ModuleHeader* header);
@@ -131,7 +128,7 @@ spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer,
 
 // Remove linkage specific instructions, such as prototypes of imported
 // functions, declarations of imported variables, import (and export if
-// necessary) linkage attribtes.
+// necessary) linkage attributes.
 //
 // |linked_context| and |decoration_manager| should not be null, and the
 // 'RemoveDuplicatePass' should be run first.
@@ -149,6 +146,15 @@ spv_result_t RemoveLinkageSpecificInstructions(
 spv_result_t VerifyIds(const MessageConsumer& consumer,
                        opt::IRContext* linked_context);
 
+// Verify that the universal limits are not crossed, and warn the user
+// otherwise.
+//
+// TODO(pierremoreau):
+// - Verify against the limits of the environment (e.g. Vulkan limits if
+//   consuming vulkan1.x)
+spv_result_t VerifyLimits(const MessageConsumer& consumer,
+                          const opt::IRContext& linked_context);
+
 spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
                                std::vector<opt::Module*>* modules,
                                uint32_t* max_id_bound) {
@@ -164,29 +170,31 @@ spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
     return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
            << "|max_id_bound| of ShiftIdsInModules should not be null.";
 
-  uint32_t id_bound = modules->front()->IdBound() - 1u;
+  const size_t id_bound =
+      std::accumulate(modules->begin(), modules->end(), static_cast<size_t>(1),
+                      [](const size_t& accumulation, opt::Module* module) {
+                        return accumulation + module->IdBound() - 1u;
+                      });
+  if (id_bound > std::numeric_limits<uint32_t>::max())
+    return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
+           << "Too many IDs (" << id_bound
+           << "): combining all modules would overflow the 32-bit word of the "
+              "SPIR-V header.";
+
+  *max_id_bound = static_cast<uint32_t>(id_bound);
+
+  uint32_t id_offset = modules->front()->IdBound() - 1u;
   for (auto module_iter = modules->begin() + 1; module_iter != modules->end();
        ++module_iter) {
     Module* module = *module_iter;
-    module->ForEachInst([&id_bound](Instruction* insn) {
-      insn->ForEachId([&id_bound](uint32_t* id) { *id += id_bound; });
+    module->ForEachInst([&id_offset](Instruction* insn) {
+      insn->ForEachId([&id_offset](uint32_t* id) { *id += id_offset; });
     });
-    id_bound += module->IdBound() - 1u;
-    if (id_bound > 0x3FFFFF)
-      return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_ID)
-             << "The limit of IDs, 4194303, was exceeded:"
-             << " " << id_bound << " is the current ID bound.";
+    id_offset += module->IdBound() - 1u;
 
     // Invalidate the DefUseManager
     module->context()->InvalidateAnalyses(opt::IRContext::kAnalysisDefUse);
   }
-  ++id_bound;
-  if (id_bound > 0x3FFFFF)
-    return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_ID)
-           << "The limit of IDs, 4194303, was exceeded:"
-           << " " << id_bound << " is the current ID bound.";
-
-  *max_id_bound = id_bound;
 
   return SPV_SUCCESS;
 }
@@ -203,12 +211,22 @@ spv_result_t GenerateHeader(const MessageConsumer& consumer,
     return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
            << "|max_id_bound| of GenerateHeader should not be null.";
 
-  uint32_t version = 0u;
-  for (const auto& module : modules)
-    version = std::max(version, module->version());
+  const uint32_t linked_version = modules.front()->version();
+  for (std::size_t i = 1; i < modules.size(); ++i) {
+    const uint32_t module_version = modules[i]->version();
+    if (module_version != linked_version)
+      return DiagnosticStream({0, 0, 1}, consumer, "", SPV_ERROR_INTERNAL)
+             << "Conflicting SPIR-V versions: "
+             << SPV_SPIRV_VERSION_MAJOR_PART(linked_version) << "."
+             << SPV_SPIRV_VERSION_MINOR_PART(linked_version)
+             << " (input modules 1 through " << i << ") vs "
+             << SPV_SPIRV_VERSION_MAJOR_PART(module_version) << "."
+             << SPV_SPIRV_VERSION_MINOR_PART(module_version)
+             << " (input module " << (i + 1) << ").";
+  }
 
   header->magic_number = SpvMagicNumber;
-  header->version = version;
+  header->version = linked_version;
   header->generator = SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_LINKER, 0);
   header->bound = max_id_bound;
   header->schema = 0u;
@@ -244,44 +262,55 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
       linked_module->AddExtInstImport(
           std::unique_ptr<Instruction>(inst.Clone(linked_context)));
 
-  do {
-    const Instruction* memory_model_inst = input_modules[0]->GetMemoryModel();
-    if (memory_model_inst == nullptr) break;
-
-    uint32_t addressing_model = memory_model_inst->GetSingleWordOperand(0u);
-    uint32_t memory_model = memory_model_inst->GetSingleWordOperand(1u);
-    for (const auto& module : input_modules) {
-      memory_model_inst = module->GetMemoryModel();
-      if (memory_model_inst == nullptr) continue;
-
-      if (addressing_model != memory_model_inst->GetSingleWordOperand(0u)) {
-        spv_operand_desc initial_desc = nullptr, current_desc = nullptr;
-        grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
-                              addressing_model, &initial_desc);
-        grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
-                              memory_model_inst->GetSingleWordOperand(0u),
-                              &current_desc);
-        return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
-               << "Conflicting addressing models: " << initial_desc->name
-               << " vs " << current_desc->name << ".";
-      }
-      if (memory_model != memory_model_inst->GetSingleWordOperand(1u)) {
-        spv_operand_desc initial_desc = nullptr, current_desc = nullptr;
-        grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, memory_model,
-                              &initial_desc);
-        grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL,
-                              memory_model_inst->GetSingleWordOperand(1u),
-                              &current_desc);
-        return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
-               << "Conflicting memory models: " << initial_desc->name << " vs "
-               << current_desc->name << ".";
-      }
+  const Instruction* linked_memory_model_inst =
+      input_modules.front()->GetMemoryModel();
+  if (linked_memory_model_inst == nullptr) {
+    return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
+           << "Input module 1 is lacking an OpMemoryModel instruction.";
+  }
+  const uint32_t linked_addressing_model =
+      linked_memory_model_inst->GetSingleWordOperand(0u);
+  const uint32_t linked_memory_model =
+      linked_memory_model_inst->GetSingleWordOperand(1u);
+
+  for (std::size_t i = 1; i < input_modules.size(); ++i) {
+    const Module* module = input_modules[i];
+    const Instruction* memory_model_inst = module->GetMemoryModel();
+    if (memory_model_inst == nullptr)
+      return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
+             << "Input module " << (i + 1)
+             << " is lacking an OpMemoryModel instruction.";
+
+    const uint32_t module_addressing_model =
+        memory_model_inst->GetSingleWordOperand(0u);
+    if (module_addressing_model != linked_addressing_model) {
+      spv_operand_desc linked_desc = nullptr, module_desc = nullptr;
+      grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
+                            linked_addressing_model, &linked_desc);
+      grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
+                            module_addressing_model, &module_desc);
+      return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
+             << "Conflicting addressing models: " << linked_desc->name
+             << " (input modules 1 through " << i << ") vs "
+             << module_desc->name << " (input module " << (i + 1) << ").";
     }
 
-    if (memory_model_inst != nullptr)
-      linked_module->SetMemoryModel(std::unique_ptr<Instruction>(
-          memory_model_inst->Clone(linked_context)));
-  } while (false);
+    const uint32_t module_memory_model =
+        memory_model_inst->GetSingleWordOperand(1u);
+    if (module_memory_model != linked_memory_model) {
+      spv_operand_desc linked_desc = nullptr, module_desc = nullptr;
+      grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, linked_memory_model,
+                            &linked_desc);
+      grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, module_memory_model,
+                            &module_desc);
+      return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
+             << "Conflicting memory models: " << linked_desc->name
+             << " (input modules 1 through " << i << ") vs "
+             << module_desc->name << " (input module " << (i + 1) << ").";
+    }
+  }
+  linked_module->SetMemoryModel(std::unique_ptr<Instruction>(
+      linked_memory_model_inst->Clone(linked_context)));
 
   std::vector<std::pair<uint32_t, std::string>> entry_points;
   for (const auto& module : input_modules)
@@ -332,7 +361,7 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
 
   // If the generated module uses SPIR-V 1.1 or higher, add an
   // OpModuleProcessed instruction about the linking step.
-  if (linked_module->version() >= 0x10100) {
+  if (linked_module->version() >= SPV_SPIRV_VERSION_WORD(1, 1)) {
     const std::string processed_string("Linked by SPIR-V Tools Linker");
     std::vector<uint32_t> processed_words =
         spvtools::utils::MakeVector(processed_string);
@@ -349,18 +378,12 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
   // TODO(pierremoreau): Since the modules have not been validate, should we
   //                     expect SpvStorageClassFunction variables outside
   //                     functions?
-  uint32_t num_global_values = 0u;
   for (const auto& module : input_modules) {
     for (const auto& inst : module->types_values()) {
       linked_module->AddType(
           std::unique_ptr<Instruction>(inst.Clone(linked_context)));
-      num_global_values += inst.opcode() == SpvOpVariable;
     }
   }
-  if (num_global_values > 0xFFFF)
-    return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
-           << "The limit of global values, 65535, was exceeded;"
-           << " " << num_global_values << " global values were found.";
 
   // Process functions and their basic blocks
   for (const auto& module : input_modules) {
@@ -632,6 +655,34 @@ spv_result_t VerifyIds(const MessageConsumer& consumer,
   return SPV_SUCCESS;
 }
 
+spv_result_t VerifyLimits(const MessageConsumer& consumer,
+                          const opt::IRContext& linked_context) {
+  spv_position_t position = {};
+
+  const uint32_t max_id_bound = linked_context.module()->id_bound();
+  if (max_id_bound >= SPV_LIMIT_RESULT_ID_BOUND)
+    DiagnosticStream({0u, 0u, 4u}, consumer, "", SPV_WARNING)
+        << "The minimum limit of IDs, " << (SPV_LIMIT_RESULT_ID_BOUND - 1)
+        << ", was exceeded:"
+        << " " << max_id_bound << " is the current ID bound.\n"
+        << "The resulting module might not be supported by all "
+           "implementations.";
+
+  size_t num_global_values = 0u;
+  for (const auto& inst : linked_context.module()->types_values()) {
+    num_global_values += inst.opcode() == SpvOpVariable;
+  }
+  if (num_global_values >= SPV_LIMIT_GLOBAL_VARIABLES_MAX)
+    DiagnosticStream(position, consumer, "", SPV_WARNING)
+        << "The minimum limit of global values, "
+        << (SPV_LIMIT_GLOBAL_VARIABLES_MAX - 1) << ", was exceeded;"
+        << " " << num_global_values << " global values were found.\n"
+        << "The resulting module might not be supported by all "
+           "implementations.";
+
+  return SPV_SUCCESS;
+}
+
 }  // namespace
 
 spv_result_t Link(const Context& context,
@@ -756,7 +807,11 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries,
   pass_res = manager.Run(&linked_context);
   if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA;
 
-  // Phase 11: Output the module
+  // Phase 11: Warn if SPIR-V limits were exceeded
+  res = VerifyLimits(consumer, linked_context);
+  if (res != SPV_SUCCESS) return res;
+
+  // Phase 12: Output the module
   linked_context.module()->ToBinary(linked_binary, true);
 
   return SPV_SUCCESS;

+ 2 - 2
3rdparty/spirv-tools/source/opcode.cpp

@@ -40,12 +40,12 @@ struct OpcodeDescPtrLen {
 static const spv_opcode_table_t kOpcodeTable = {ARRAY_SIZE(kOpcodeTableEntries),
                                                 kOpcodeTableEntries};
 
-// Represents a vendor tool entry in the SPIR-V XML Regsitry.
+// Represents a vendor tool entry in the SPIR-V XML Registry.
 struct VendorTool {
   uint32_t value;
   const char* vendor;
   const char* tool;         // Might be empty string.
-  const char* vendor_tool;  // Combiantion of vendor and tool.
+  const char* vendor_tool;  // Combination of vendor and tool.
 };
 
 const VendorTool vendor_tools[] = {

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

@@ -23,7 +23,7 @@ namespace spvtools {
 namespace opt {
 
 // Replaces the extensions VK_AMD_shader_ballot, VK_AMD_gcn_shader, and
-// VK_AMD_shader_trinary_minmax with equivalant code using core instructions and
+// VK_AMD_shader_trinary_minmax with equivalent code using core instructions and
 // capabilities.
 class AmdExtensionToKhrPass : public Pass {
  public:

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

@@ -83,7 +83,7 @@ class BasicBlock {
   const Instruction* GetMergeInst() const;
   Instruction* GetMergeInst();
 
-  // Returns the OpLoopMerge instruciton in this basic block, if it exists.
+  // Returns the OpLoopMerge instruction in this basic block, if it exists.
   // Otherwise return null.  May be used whenever tail() can be used.
   const Instruction* GetLoopMergeInst() const;
   Instruction* GetLoopMergeInst();

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

@@ -30,7 +30,7 @@ class CFG {
  public:
   explicit CFG(Module* module);
 
-  // Return the list of predecesors for basic block with label |blkid|.
+  // Return the list of predecessors for basic block with label |blkid|.
   // TODO(dnovillo): Move this to BasicBlock.
   const std::vector<uint32_t>& preds(uint32_t blk_id) const {
     assert(label2preds_.count(blk_id));

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

@@ -550,7 +550,7 @@ ConstantFoldingRule FoldFAdd() { return FoldFPBinaryOp(FOLD_FPARITH_OP(+)); }
 ConstantFoldingRule FoldFMul() { return FoldFPBinaryOp(FOLD_FPARITH_OP(*)); }
 
 // Returns the constant that results from evaluating |numerator| / 0.0.  Returns
-// |nullptr| if the result could not be evalutated.
+// |nullptr| if the result could not be evaluated.
 const analysis::Constant* FoldFPScalarDivideByZero(
     const analysis::Type* result_type, const analysis::Constant* numerator,
     analysis::ConstantManager* const_mgr) {
@@ -1346,7 +1346,7 @@ void ConstantFoldingRules::AddFoldingRules() {
         FoldFPUnaryOp(FoldFTranscendentalUnary(std::log)));
 
 #ifdef __ANDROID__
-    // Android NDK r15c tageting ABI 15 doesn't have full support for C++11
+    // Android NDK r15c targeting ABI 15 doesn't have full support for C++11
     // (no std::exp2/log2). ::exp2 is available from C99 but ::log2 isn't
     // available up until ABI 18 so we use a shim
     auto log2_shim = [](double v) -> double { return log(v) / log(2.0); };

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

@@ -541,7 +541,7 @@ class ConstantManager {
   // instruction at the end of the current module's types section.
   //
   // |type_id| is an optional argument for disambiguating equivalent types. If
-  // |type_id| is specified, the contant returned will have that type id.
+  // |type_id| is specified, the constant returned will have that type id.
   Instruction* GetDefiningInstruction(const Constant* c, uint32_t type_id = 0,
                                       Module::inst_iterator* pos = nullptr);
 

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

@@ -181,7 +181,7 @@ bool ConvertToHalfPass::ProcessPhi(Instruction* inst, uint32_t from_width,
                                    uint32_t to_width) {
   // Add converts of any float operands to to_width if they are of from_width.
   // If converting to 16, change type of phi to float16 equivalent and remember
-  // result id. Converts need to be added to preceeding blocks.
+  // result id. Converts need to be added to preceding blocks.
   uint32_t ocnt = 0;
   uint32_t* prev_idp;
   bool modified = false;

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

@@ -158,7 +158,7 @@ class DeadBranchElimPass : public MemPass {
       uint32_t cont_id, uint32_t header_id, uint32_t merge_id,
       std::unordered_set<BasicBlock*>* blocks_with_back_edges);
 
-  // Returns true if there is a brach to the merge node of the selection
+  // Returns true if there is a branch to the merge node of the selection
   // construct |switch_header_id| that is inside a nested selection construct or
   // in the header of the nested selection construct.
   bool SwitchHasNestedBreak(uint32_t switch_header_id);

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

@@ -149,7 +149,7 @@ void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
 // Create new constant directly into global value area, bypassing the
 // Constant manager. This is used when the DefUse or Constant managers
 // are invalid and cannot be regenerated due to the module being in an
-// inconsistant state e.g. in the middle of significant modification
+// inconsistent state e.g. in the middle of significant modification
 // such as inlining. Invalidate Constant and DefUse managers if used.
 uint32_t AddNewConstInGlobals(IRContext* context, uint32_t const_value) {
   uint32_t id = context->TakeNextId();

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

@@ -190,7 +190,7 @@ class DefUseManager {
   // Returns the annotation instrunctions which are a direct use of the given
   // |id|. This means when the decorations are applied through decoration
   // group(s), this function will just return the OpGroupDecorate
-  // instrcution(s) which refer to the given id as an operand. The OpDecorate
+  // instruction(s) which refer to the given id as an operand. The OpDecorate
   // instructions which decorate the decoration group will not be returned.
   std::vector<Instruction*> GetAnnotations(uint32_t id) const;
 
@@ -210,7 +210,7 @@ class DefUseManager {
   friend bool CompareAndPrintDifferences(const DefUseManager&,
                                          const DefUseManager&);
 
-  // If |inst| has not already been analysed, then analyses its defintion and
+  // If |inst| has not already been analysed, then analyses its definition and
   // uses.
   void UpdateDefUse(Instruction* inst);
 

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

@@ -118,7 +118,7 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var,
 
   if (use->NumInOperands() == 2) {
     // We are not indexing into the replacement variable.  We can replaces the
-    // access chain with the replacement varibale itself.
+    // access chain with the replacement variable itself.
     context()->ReplaceAllUsesWith(use->result_id(), replacement_var);
     context()->KillInst(use);
     return true;
@@ -135,8 +135,8 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var,
   // Use the replacement variable as the base address.
   new_operands.push_back({SPV_OPERAND_TYPE_ID, {replacement_var}});
 
-  // Drop the first index because it is consumed by the replacment, and copy the
-  // rest.
+  // Drop the first index because it is consumed by the replacement, and copy
+  // the rest.
   for (uint32_t i = 4; i < use->NumOperands(); i++) {
     new_operands.emplace_back(use->GetOperand(i));
   }

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

@@ -48,7 +48,7 @@ namespace {
 // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
 // SuccessorLambda - Lamdba matching the signature of 'const
 // std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
-// succeding BasicBlock A.
+// succeeding BasicBlock A.
 // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
 // called on each node traversed AFTER their children.
 // PreLambda - Lamdba matching the signature of 'void (const BBType*)' will be
@@ -69,7 +69,7 @@ static void DepthFirstSearch(const BBType* bb, SuccessorLambda successors,
 // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
 // SuccessorLambda - Lamdba matching the signature of 'const
 // std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
-// succeding BasicBlock A.
+// succeeding BasicBlock A.
 // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
 // called on each node traversed after their children.
 template <typename BBType, typename SuccessorLambda, typename PostLambda>

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

@@ -38,7 +38,7 @@ Pass::Status EliminateDeadMembersPass::Process() {
 }
 
 void EliminateDeadMembersPass::FindLiveMembers() {
-  // Until we have implemented the rewritting of OpSpecConsantOp instructions,
+  // Until we have implemented the rewriting of OpSpecConsantOp instructions,
   // we have to mark them as fully used just to be safe.
   for (auto& inst : get_module()->types_values()) {
     if (inst.opcode() == SpvOpSpecConstantOp) {
@@ -570,7 +570,7 @@ bool EliminateDeadMembersPass::UpdateCompsiteExtract(Instruction* inst) {
     Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
     switch (type_inst->opcode()) {
       case SpvOpTypeStruct:
-        // The type will have already been rewriten, so use the new member
+        // The type will have already been rewritten, so use the new member
         // index.
         type_id = type_inst->GetSingleWordInOperand(new_member_idx);
         break;

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

@@ -540,7 +540,7 @@ std::vector<uint32_t> InstructionFolder::FoldVectors(
         // in 32-bit words here. The reason of not using FoldScalars() here
         // is that we do not create temporary null constants as components
         // when the vector operand is a NullConstant because Constant creation
-        // may need extra checks for the validity and that is not manageed in
+        // may need extra checks for the validity and that is not managed in
         // here.
         if (const analysis::ScalarConstant* scalar_component =
                 vector_operand->GetComponents().at(d)->AsScalarConstant()) {

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

@@ -115,7 +115,7 @@ bool FoldSpecConstantOpAndCompositePass::ProcessOpSpecConstantOp(
   Instruction* folded_inst = nullptr;
   assert(inst->GetInOperand(0).type ==
              SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER &&
-         "The first in-operand of OpSpecContantOp instruction must be of "
+         "The first in-operand of OpSpecConstantOp instruction must be of "
          "SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER type");
 
   switch (static_cast<SpvOp>(inst->GetSingleWordInOperand(0))) {

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

@@ -13,7 +13,7 @@
 // limitations under the License.
 
 // This pass injects code in a graphics shader to implement guarantees
-// satisfying Vulkan's robustBufferAcces rules.  Robust access rules permit
+// satisfying Vulkan's robustBufferAccess rules.  Robust access rules permit
 // an out-of-bounds access to be redirected to an access of the same type
 // (load, store, etc.) but within the same root object.
 //
@@ -74,7 +74,7 @@
 //    Pointers are always (correctly) typed and so the address and number of
 //    consecutive locations are fully determined by the pointer.
 //
-//  - A pointer value orginates as one of few cases:
+//  - A pointer value originates as one of few cases:
 //
 //    - OpVariable for an interface object or an array of them: image,
 //      buffer (UBO or SSBO), sampler, sampled-image, push-constant, input
@@ -958,7 +958,7 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
       constant_mgr->GetDefiningInstruction(component_0)->result_id();
 
   // If the image is a cube array, then the last component of the queried
-  // size is the layer count.  In the query, we have to accomodate folding
+  // size is the layer count.  In the query, we have to accommodate folding
   // in the face index ranging from 0 through 5. The inclusive upper bound
   // on the third coordinate therefore is multiplied by 6.
   auto* query_size_including_faces = query_size;

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

@@ -111,7 +111,7 @@ class GraphicsRobustAccessPass : public Pass {
                                    Instruction* max, Instruction* where);
 
   // Returns a new instruction which evaluates to the length the runtime array
-  // referenced by the access chain at the specfied index.  The instruction is
+  // referenced by the access chain at the specified index.  The instruction is
   // inserted before the access chain instruction.  Returns a null pointer in
   // some cases if assumptions are violated (rather than asserting out).
   opt::Instruction* MakeRuntimeArrayLengthInst(Instruction* access_chain,

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

@@ -147,11 +147,11 @@ class InstBindlessCheckPass : public InstrumentPass {
   uint32_t GenLastByteIdx(RefAnalysis* ref, InstructionBuilder* builder);
 
   // Clone original image computation starting at |image_id| into |builder|.
-  // This may generate more than one instruction if neccessary.
+  // This may generate more than one instruction if necessary.
   uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder);
 
   // Clone original original reference encapsulated by |ref| into |builder|.
-  // This may generate more than one instruction if neccessary.
+  // This may generate more than one instruction if necessary.
   uint32_t CloneOriginalReference(RefAnalysis* ref,
                                   InstructionBuilder* builder);
 

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

@@ -122,7 +122,7 @@ inline bool operator!=(const Operand& o1, const Operand& o2) {
 }
 
 // This structure is used to represent a DebugScope instruction from
-// the OpenCL.100.DebugInfo extened instruction set. Note that we can
+// the OpenCL.100.DebugInfo extended instruction set. Note that we can
 // ignore the result id of DebugScope instruction because it is not
 // used for anything. We do not keep it to reduce the size of
 // structure.

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

@@ -50,7 +50,7 @@
 // A validation pass may read or write multiple buffers. All such buffers
 // are located in a single debug descriptor set whose index is passed at the
 // creation of the instrumentation pass. The bindings of the buffers used by
-// a validation pass are permanantly assigned and fixed and documented by
+// a validation pass are permanently assigned and fixed and documented by
 // the kDebugOutput* static consts.
 
 namespace spvtools {
@@ -179,8 +179,8 @@ class InstrumentPass : public Pass {
   // the error. Every stage will write a fixed number of words. Vertex shaders
   // will write the Vertex and Instance ID. Fragment shaders will write
   // FragCoord.xy. Compute shaders will write the GlobalInvocation ID.
-  // The tesselation eval shader will write the Primitive ID and TessCoords.uv.
-  // The tesselation control shader and geometry shader will write the
+  // The tessellation eval shader will write the Primitive ID and TessCoords.uv.
+  // The tessellation control shader and geometry shader will write the
   // Primitive ID and Invocation ID.
   //
   // The Validation Error Code specifies the exact error which has occurred.

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

@@ -106,7 +106,7 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
     analyses_to_invalidate |= kAnalysisDebugInfo;
   }
 
-  // The dominator analysis hold the psuedo entry and exit nodes from the CFG.
+  // The dominator analysis hold the pseudo entry and exit nodes from the CFG.
   // Also if the CFG change the dominators many changed as well, so the
   // dominator analysis should be invalidated as well.
   if (analyses_to_invalidate & kAnalysisCFG) {

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

@@ -302,7 +302,7 @@ class IRContext {
     }
   }
 
-  // Returns a pointer the decoration manager.  If the decoration manger is
+  // Returns a pointer the decoration manager.  If the decoration manager is
   // invalid, it is rebuilt first.
   analysis::DecorationManager* get_decoration_mgr() {
     if (!AreAnalysesValid(kAnalysisDecorations)) {
@@ -385,7 +385,7 @@ class IRContext {
 
   // Deletes the instruction defining the given |id|. Returns true on
   // success, false if the given |id| is not defined at all. This method also
-  // erases the name, decorations, and defintion of |id|.
+  // erases the name, decorations, and definition of |id|.
   //
   // Pointers and iterators pointing to the deleted instructions become invalid.
   // However other pointers and iterators are still valid.
@@ -802,7 +802,7 @@ class IRContext {
   // iterators to traverse instructions.
   std::unordered_map<uint32_t, Function*> id_to_func_;
 
-  // A bitset indicating which analyes are currently valid.
+  // A bitset indicating which analyzes are currently valid.
   Analysis valid_analyses_;
 
   // Opcodes of shader capability core executable instructions

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

@@ -81,7 +81,7 @@ class LocalAccessChainConvertPass : public MemPass {
                               std::vector<Operand>* in_opnds);
 
   // Create a load/insert/store equivalent to a store of
-  // |valId| through (constant index) access chaing |ptrInst|.
+  // |valId| through (constant index) access chain |ptrInst|.
   // Append to |newInsts|.  Returns true if successful.
   bool GenAccessChainStoreReplacement(
       const Instruction* ptrInst, uint32_t valId,

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

@@ -719,7 +719,7 @@ bool Loop::FindNumberOfIterations(const Instruction* induction,
     step_value = -step_value;
   }
 
-  // Find the inital value of the loop and make sure it is a constant integer.
+  // Find the initial value of the loop and make sure it is a constant integer.
   int64_t init_value = 0;
   if (!GetInductionInitValue(induction, &init_value)) return false;
 
@@ -751,7 +751,7 @@ bool Loop::FindNumberOfIterations(const Instruction* induction,
 // We retrieve the number of iterations using the following formula, diff /
 // |step_value| where diff is calculated differently according to the
 // |condition| and uses the |condition_value| and |init_value|. If diff /
-// |step_value| is NOT cleanly divisable then we add one to the sum.
+// |step_value| is NOT cleanly divisible then we add one to the sum.
 int64_t Loop::GetIterations(SpvOp condition, int64_t condition_value,
                             int64_t init_value, int64_t step_value) const {
   int64_t diff = 0;
@@ -795,7 +795,7 @@ int64_t Loop::GetIterations(SpvOp condition, int64_t condition_value,
       // If the condition is not met to begin with the loop will never iterate.
       if (!(init_value >= condition_value)) return 0;
 
-      // We subract one to make it the same as SpvOpGreaterThan as it is
+      // We subtract one to make it the same as SpvOpGreaterThan as it is
       // functionally equivalent.
       diff = init_value - (condition_value - 1);
 

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

@@ -395,7 +395,7 @@ class Loop {
   // Sets |merge| as the loop merge block. No checks are performed here.
   inline void SetMergeBlockImpl(BasicBlock* merge) { loop_merge_ = merge; }
 
-  // Each differnt loop |condition| affects how we calculate the number of
+  // Each different loop |condition| affects how we calculate the number of
   // iterations using the |condition_value|, |init_value|, and |step_values| of
   // the induction variable. This method will return the number of iterations in
   // a loop with those values for a given |condition|.

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

@@ -29,7 +29,7 @@
 // 2 - For each loop in the list, group each instruction into a set of related
 // instructions by traversing each instructions users and operands recursively.
 // We stop if we encounter an instruction we have seen before or an instruction
-// which we don't consider relevent (i.e OpLoopMerge). We then group these
+// which we don't consider relevant (i.e OpLoopMerge). We then group these
 // groups into two different sets, one for the first loop and one for the
 // second.
 //

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

@@ -33,7 +33,7 @@ namespace opt {
 
 class LoopFissionPass : public Pass {
  public:
-  // Fuction used to determine if a given loop should be split. Takes register
+  // Function used to determine if a given loop should be split. Takes register
   // pressure region for that loop as a parameter and returns true if the loop
   // should be split.
   using FissionCriteriaFunction =

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

@@ -165,7 +165,7 @@ bool LoopFusion::AreCompatible() {
 
   // Check adjacency, |loop_0_| should come just before |loop_1_|.
   // There is always at least one block between loops, even if it's empty.
-  // We'll check at most 2 preceeding blocks.
+  // We'll check at most 2 preceding blocks.
 
   auto pre_header_1 = loop_1_->GetPreHeaderBlock();
 
@@ -712,7 +712,7 @@ void LoopFusion::Fuse() {
 
   ld->RemoveLoop(loop_1_);
 
-  // Kill unnessecary instructions and remove all empty blocks.
+  // Kill unnecessary instructions and remove all empty blocks.
   for (auto inst : instr_to_delete) {
     context_->KillInst(inst);
   }

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

@@ -40,7 +40,7 @@ class LoopFusion {
   // That means:
   //   * they both have one induction variable
   //   * they have the same upper and lower bounds
-  //     - same inital value
+  //     - same initial value
   //     - same condition
   //   * they have the same update step
   //   * they are adjacent, with |loop_0| appearing before |loop_1|

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

@@ -33,7 +33,7 @@ class LoopFusionPass : public Pass {
 
   // Processes the given |module|. Returns Status::Failure if errors occur when
   // processing. Returns the corresponding Status::Success if processing is
-  // succesful to indicate whether changes have been made to the modue.
+  // successful to indicate whether changes have been made to the module.
   Status Process() override;
 
  private:

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

@@ -261,7 +261,7 @@ class LoopPeelingPass : public Pass {
 
   // Processes the given |module|. Returns Status::Failure if errors occur when
   // processing. Returns the corresponding Status::Success if processing is
-  // succesful to indicate whether changes have been made to the modue.
+  // successful to indicate whether changes have been made to the module.
   Pass::Status Process() override;
 
  private:

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

@@ -163,7 +163,7 @@ struct LoopUnrollState {
 };
 
 // This class implements the actual unrolling. It uses a LoopUnrollState to
-// maintain the state of the unrolling inbetween steps.
+// maintain the state of the unrolling in between steps.
 class LoopUnrollerUtilsImpl {
  public:
   using BasicBlockListTy = std::vector<std::unique_ptr<BasicBlock>>;
@@ -209,7 +209,7 @@ class LoopUnrollerUtilsImpl {
   // Add all blocks_to_add_ to function_ at the |insert_point|.
   void AddBlocksToFunction(const BasicBlock* insert_point);
 
-  // Duplicates the |old_loop|, cloning each body and remaping the ids without
+  // Duplicates the |old_loop|, cloning each body and remapping the ids without
   // removing instructions or changing relative structure. Result will be stored
   // in |new_loop|.
   void DuplicateLoop(Loop* old_loop, Loop* new_loop);
@@ -241,7 +241,7 @@ class LoopUnrollerUtilsImpl {
   // Remap all the in |basic_block| to new IDs and keep the mapping of new ids
   // to old
   // ids. |loop| is used to identify special loop blocks (header, continue,
-  // ect).
+  // etc).
   void AssignNewResultIds(BasicBlock* basic_block);
 
   // Using the map built by AssignNewResultIds, replace the uses in |inst|
@@ -320,7 +320,7 @@ class LoopUnrollerUtilsImpl {
   // and then be remapped at the end.
   std::vector<Instruction*> loop_phi_instructions_;
 
-  // The number of loop iterations that the loop would preform pre-unroll.
+  // The number of loop iterations that the loop would perform pre-unroll.
   size_t number_of_loop_iterations_;
 
   // The amount that the loop steps each iteration.
@@ -839,7 +839,7 @@ void LoopUnrollerUtilsImpl::DuplicateLoop(Loop* old_loop, Loop* new_loop) {
   new_loop->SetMergeBlock(new_merge);
 }
 
-// Whenever the utility copies a block it stores it in a tempory buffer, this
+// Whenever the utility copies a block it stores it in a temporary buffer, this
 // function adds the buffer into the Function. The blocks will be inserted
 // after the block |insert_point|.
 void LoopUnrollerUtilsImpl::AddBlocksToFunction(

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

@@ -118,7 +118,7 @@ class LoopUnswitch {
 
     // Find a value that can be used to select the default path.
     // If none are possible, then it will just use 0.  The value does not matter
-    // because this path will never be taken becaues the new switch outside of
+    // because this path will never be taken because the new switch outside of
     // the loop cannot select this path either.
     std::vector<uint32_t> existing_values;
     for (uint32_t i = 2; i < switch_inst->NumInOperands(); i += 2) {

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

@@ -30,7 +30,7 @@ class LoopUnswitchPass : public Pass {
 
   // Processes the given |module|. Returns Status::Failure if errors occur when
   // processing. Returns the corresponding Status::Success if processing is
-  // succesful to indicate whether changes have been made to the modue.
+  // successful to indicate whether changes have been made to the module.
   Pass::Status Process() override;
 
  private:

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

@@ -123,7 +123,7 @@ class LoopUtils {
   // Clone the |loop_| and make the new loop branch to the second loop on exit.
   Loop* CloneAndAttachLoopToHeader(LoopCloningResult* cloning_result);
 
-  // Perfom a partial unroll of |loop| by given |factor|. This will copy the
+  // Perform a partial unroll of |loop| by given |factor|. This will copy the
   // body of the loop |factor| times. So a |factor| of one would give a new loop
   // with the original body plus one unrolled copy body.
   bool PartiallyUnroll(size_t factor);
@@ -139,7 +139,7 @@ class LoopUtils {
   // 1. That the loop is in structured order.
   // 2. That the continue block is a branch to the header.
   // 3. That the only phi used in the loop is the induction variable.
-  //  TODO([email protected]): This is a temporary mesure, after the loop is
+  //  TODO([email protected]): This is a temporary measure, after the loop is
   //  converted into LCSAA form and has a single entry and exit we can rewrite
   //  the other phis.
   // 4. That this is an inner most loop, or that loops contained within this

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

@@ -247,7 +247,7 @@ class MergeReturnPass : public MemPass {
 
   // Add new phi nodes for any id that no longer dominate all of it uses.  A phi
   // node is added to a block |bb| for an id if the id is defined between the
-  // original immediate dominator of |bb| and its new immidiate dominator.  It
+  // original immediate dominator of |bb| and its new immediate dominator.  It
   // is assumed that at this point there are no unreachable blocks in the
   // control flow graph.
   void AddNewPhiNodes();
@@ -273,7 +273,7 @@ class MergeReturnPass : public MemPass {
   void InsertAfterElement(BasicBlock* element, BasicBlock* new_element,
                           std::list<BasicBlock*>* list);
 
-  // Creates a single case switch around all of the exectuable code of the
+  // Creates a single case switch around all of the executable code of the
   // current function where the switch and case value are both zero and the
   // default is the merge block. Returns after the switch is executed. Sets
   // |final_return_block_|.

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

@@ -324,6 +324,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
     RegisterPass(CreateLocalAccessChainConvertPass());
   } else if (pass_name == "replace-desc-array-access-using-var-index") {
     RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass());
+  } else if (pass_name == "spread-volatile-semantics") {
+    RegisterPass(CreateSpreadVolatileSemanticsPass());
   } else if (pass_name == "descriptor-scalar-replacement") {
     RegisterPass(CreateDescriptorScalarReplacementPass());
   } else if (pass_name == "eliminate-dead-code-aggressive") {
@@ -976,6 +978,11 @@ Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() {
       MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>());
 }
 
+Optimizer::PassToken CreateSpreadVolatileSemanticsPass() {
+  return MakeUnique<Optimizer::PassToken::Impl>(
+      MakeUnique<opt::SpreadVolatileSemantics>());
+}
+
 Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
   return MakeUnique<Optimizer::PassToken::Impl>(
       MakeUnique<opt::DescriptorScalarReplacement>());

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

@@ -129,7 +129,7 @@ class Pass {
 
   // Processes the given |module|. Returns Status::Failure if errors occur when
   // processing. Returns the corresponding Status::Success if processing is
-  // succesful to indicate whether changes are made to the module.
+  // successful to indicate whether changes are made to the module.
   virtual Status Process() = 0;
 
   // Return the next available SSA id and increment it.

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

@@ -54,7 +54,7 @@ class PassManager {
   // Adds an externally constructed pass.
   void AddPass(std::unique_ptr<Pass> pass);
   // Uses the argument |args| to construct a pass instance of type |T|, and adds
-  // the pass instance to this pass manger. The pass added will use this pass
+  // the pass instance to this pass manager. The pass added will use this pass
   // manager's message consumer.
   template <typename T, typename... Args>
   void AddPass(Args&&... args);
@@ -70,7 +70,7 @@ class PassManager {
   // Runs all passes on the given |module|. Returns Status::Failure if errors
   // occur when processing using one of the registered passes. All passes
   // registered after the error-reporting pass will be skipped. Returns the
-  // corresponding Status::Success if processing is succesful to indicate
+  // corresponding Status::Success if processing is successful to indicate
   // whether changes are made to the module.
   //
   // After running all the passes, they are removed from the list.

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

@@ -71,6 +71,7 @@
 #include "source/opt/scalar_replacement_pass.h"
 #include "source/opt/set_spec_constant_default_value_pass.h"
 #include "source/opt/simplification_pass.h"
+#include "source/opt/spread_volatile_semantics.h"
 #include "source/opt/ssa_rewrite_pass.h"
 #include "source/opt/strength_reduction_pass.h"
 #include "source/opt/strip_debug_info_pass.h"

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

@@ -44,7 +44,7 @@ class PrivateToLocalPass : public Pass {
   // class of |function|.  Returns false if the variable could not be moved.
   bool MoveVariable(Instruction* variable, Function* function);
 
-  // |inst| is an instruction declaring a varible.  If that variable is
+  // |inst| is an instruction declaring a variable.  If that variable is
   // referenced in a single function and all of uses are valid as defined by
   // |IsValidUse|, then that function is returned.  Otherwise, the return
   // value is |nullptr|.

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

@@ -41,7 +41,7 @@ class RedundancyEliminationPass : public LocalRedundancyEliminationPass {
   // in the function containing |bb|.
   //
   // |value_to_ids| is a map from value number to ids.  If {vn, id} is in
-  // |value_to_ids| then vn is the value number of id, and the defintion of id
+  // |value_to_ids| then vn is the value number of id, and the definition of id
   // dominates |bb|.
   //
   // Returns true if at least one instruction is deleted.

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

@@ -47,7 +47,7 @@ class ReplaceDescArrayAccessUsingVarIndex : public Pass {
   }
 
  private:
-  // Replaces all acceses to |var| using variable indices with constant
+  // Replaces all accesses to |var| using variable indices with constant
   // elements of the array |var|. Creates switch-case statements to determine
   // the value of the variable index for all the possible cases. Returns
   // whether replacement is done or not.
@@ -170,7 +170,7 @@ class ReplaceDescArrayAccessUsingVarIndex : public Pass {
   // Creates and adds an OpSwitch used for the selection of OpAccessChain whose
   // first Indexes operand is |access_chain_index_var_id|. The OpSwitch will be
   // added at the end of |parent_block|. It will jump to |default_id| for the
-  // default case and jumps to one of case blocks whoes ids are |case_block_ids|
+  // default case and jumps to one of case blocks whose ids are |case_block_ids|
   // if |access_chain_index_var_id| matches the case number. |merge_id| is the
   // merge block id.
   void AddSwitchForAccessChain(

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

@@ -581,7 +581,7 @@ static void PushToString(T id, std::u32string* str) {
 
 // Implements the hashing of SENodes.
 size_t SENodeHash::operator()(const SENode* node) const {
-  // Concatinate the terms into a string which we can hash.
+  // Concatenate the terms into a string which we can hash.
   std::u32string hash_string{};
 
   // Hashing the type as a string is safer than hashing the enum as the enum is

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

@@ -167,7 +167,7 @@ class SENode {
   const ChildContainerType& GetChildren() const { return children_; }
   ChildContainerType& GetChildren() { return children_; }
 
-  // Return true if this node is a cant compute node.
+  // Return true if this node is a can't compute node.
   bool IsCantCompute() const { return GetType() == CanNotCompute; }
 
 // Implements a casting method for each type.

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

@@ -88,7 +88,7 @@ class SENodeSimplifyImpl {
 
  private:
   // Recursively descend through the graph to build up the accumulator objects
-  // which are used to flatten the graph. |child| is the node currenty being
+  // which are used to flatten the graph. |child| is the node currently being
   // traversed and the |negation| flag is used to signify that this operation
   // was preceded by a unary negative operation and as such the result should be
   // negated.

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

@@ -0,0 +1,314 @@
+// Copyright (c) 2022 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/spread_volatile_semantics.h"
+
+#include "source/opt/decoration_manager.h"
+#include "source/opt/ir_builder.h"
+#include "source/spirv_constant.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+const uint32_t kOpDecorateInOperandBuiltinDecoration = 2u;
+const uint32_t kOpLoadInOperandMemoryOperands = 1u;
+const uint32_t kOpEntryPointInOperandEntryPoint = 1u;
+const uint32_t kOpEntryPointInOperandInterface = 3u;
+
+bool HasBuiltinDecoration(analysis::DecorationManager* decoration_manager,
+                          uint32_t var_id, uint32_t built_in) {
+  return decoration_manager->FindDecoration(
+      var_id, SpvDecorationBuiltIn, [built_in](const Instruction& inst) {
+        return built_in == inst.GetSingleWordInOperand(
+                               kOpDecorateInOperandBuiltinDecoration);
+      });
+}
+
+bool IsBuiltInForRayTracingVolatileSemantics(uint32_t built_in) {
+  switch (built_in) {
+    case SpvBuiltInSMIDNV:
+    case SpvBuiltInWarpIDNV:
+    case SpvBuiltInSubgroupSize:
+    case SpvBuiltInSubgroupLocalInvocationId:
+    case SpvBuiltInSubgroupEqMask:
+    case SpvBuiltInSubgroupGeMask:
+    case SpvBuiltInSubgroupGtMask:
+    case SpvBuiltInSubgroupLeMask:
+    case SpvBuiltInSubgroupLtMask:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool HasBuiltinForRayTracingVolatileSemantics(
+    analysis::DecorationManager* decoration_manager, uint32_t var_id) {
+  return decoration_manager->FindDecoration(
+      var_id, SpvDecorationBuiltIn, [](const Instruction& inst) {
+        uint32_t built_in =
+            inst.GetSingleWordInOperand(kOpDecorateInOperandBuiltinDecoration);
+        return IsBuiltInForRayTracingVolatileSemantics(built_in);
+      });
+}
+
+bool HasVolatileDecoration(analysis::DecorationManager* decoration_manager,
+                           uint32_t var_id) {
+  return decoration_manager->HasDecoration(var_id, SpvDecorationVolatile);
+}
+
+bool HasOnlyEntryPointsAsFunctions(IRContext* context, Module* module) {
+  std::unordered_set<uint32_t> entry_function_ids;
+  for (Instruction& entry_point : module->entry_points()) {
+    entry_function_ids.insert(
+        entry_point.GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint));
+  }
+  for (auto& function : *module) {
+    if (entry_function_ids.find(function.result_id()) ==
+        entry_function_ids.end()) {
+      std::string message(
+          "Functions of SPIR-V for spread-volatile-semantics pass input must "
+          "be inlined except entry points");
+      message += "\n  " + function.DefInst().PrettyPrint(
+                              SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
+      context->consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, message.c_str());
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+Pass::Status SpreadVolatileSemantics::Process() {
+  if (!HasOnlyEntryPointsAsFunctions(context(), get_module())) {
+    return Status::Failure;
+  }
+
+  const bool is_vk_memory_model_enabled =
+      context()->get_feature_mgr()->HasCapability(
+          SpvCapabilityVulkanMemoryModel);
+  CollectTargetsForVolatileSemantics(is_vk_memory_model_enabled);
+
+  // If VulkanMemoryModel capability is not enabled, we have to set Volatile
+  // decoration for interface variables instead of setting Volatile for load
+  // instructions. If an interface (or pointers to it) is used by two load
+  // instructions in two entry points and one must be volatile while another
+  // is not, we have to report an error for the conflict.
+  if (!is_vk_memory_model_enabled &&
+      HasInterfaceInConflictOfVolatileSemantics()) {
+    return Status::Failure;
+  }
+
+  return SpreadVolatileSemanticsToVariables(is_vk_memory_model_enabled);
+}
+
+Pass::Status SpreadVolatileSemantics::SpreadVolatileSemanticsToVariables(
+    const bool is_vk_memory_model_enabled) {
+  Status status = Status::SuccessWithoutChange;
+  for (Instruction& var : context()->types_values()) {
+    auto entry_function_ids =
+        EntryFunctionsToSpreadVolatileSemanticsForVar(var.result_id());
+    if (entry_function_ids.empty()) {
+      continue;
+    }
+
+    if (is_vk_memory_model_enabled) {
+      SetVolatileForLoadsInEntries(&var, entry_function_ids);
+    } else {
+      DecorateVarWithVolatile(&var);
+    }
+    status = Status::SuccessWithChange;
+  }
+  return status;
+}
+
+bool SpreadVolatileSemantics::IsTargetUsedByNonVolatileLoadInEntryPoint(
+    uint32_t var_id, Instruction* entry_point) {
+  uint32_t entry_function_id =
+      entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint);
+  return !VisitLoadsOfPointersToVariableInEntries(
+      var_id,
+      [](Instruction* load) {
+        // If it has a load without volatile memory operand, finish traversal
+        // and return false.
+        if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) {
+          return false;
+        }
+        uint32_t memory_operands =
+            load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands);
+        return (memory_operands & SpvMemoryAccessVolatileMask) != 0;
+      },
+      {entry_function_id});
+}
+
+bool SpreadVolatileSemantics::HasInterfaceInConflictOfVolatileSemantics() {
+  for (Instruction& entry_point : get_module()->entry_points()) {
+    SpvExecutionModel execution_model =
+        static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
+    for (uint32_t operand_index = kOpEntryPointInOperandInterface;
+         operand_index < entry_point.NumInOperands(); ++operand_index) {
+      uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index);
+      if (!EntryFunctionsToSpreadVolatileSemanticsForVar(var_id).empty() &&
+          !IsTargetForVolatileSemantics(var_id, execution_model) &&
+          IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) {
+        Instruction* inst = context()->get_def_use_mgr()->GetDef(var_id);
+        context()->EmitErrorMessage(
+            "Variable is a target for Volatile semantics for an entry point, "
+            "but it is not for another entry point",
+            inst);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void SpreadVolatileSemantics::MarkVolatileSemanticsForVariable(
+    uint32_t var_id, Instruction* entry_point) {
+  uint32_t entry_function_id =
+      entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint);
+  auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id);
+  if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) {
+    var_ids_to_entry_fn_for_volatile_semantics_[var_id] = {entry_function_id};
+    return;
+  }
+  itr->second.insert(entry_function_id);
+}
+
+void SpreadVolatileSemantics::CollectTargetsForVolatileSemantics(
+    const bool is_vk_memory_model_enabled) {
+  for (Instruction& entry_point : get_module()->entry_points()) {
+    SpvExecutionModel execution_model =
+        static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
+    for (uint32_t operand_index = kOpEntryPointInOperandInterface;
+         operand_index < entry_point.NumInOperands(); ++operand_index) {
+      uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index);
+      if (!IsTargetForVolatileSemantics(var_id, execution_model)) {
+        continue;
+      }
+      if (is_vk_memory_model_enabled ||
+          IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) {
+        MarkVolatileSemanticsForVariable(var_id, &entry_point);
+      }
+    }
+  }
+}
+
+void SpreadVolatileSemantics::DecorateVarWithVolatile(Instruction* var) {
+  analysis::DecorationManager* decoration_manager =
+      context()->get_decoration_mgr();
+  uint32_t var_id = var->result_id();
+  if (HasVolatileDecoration(decoration_manager, var_id)) {
+    return;
+  }
+  get_decoration_mgr()->AddDecoration(
+      SpvOpDecorate, {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {var_id}},
+                      {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
+                       {SpvDecorationVolatile}}});
+}
+
+bool SpreadVolatileSemantics::VisitLoadsOfPointersToVariableInEntries(
+    uint32_t var_id, const std::function<bool(Instruction*)>& handle_load,
+    const std::unordered_set<uint32_t>& entry_function_ids) {
+  std::vector<uint32_t> worklist({var_id});
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  while (!worklist.empty()) {
+    uint32_t ptr_id = worklist.back();
+    worklist.pop_back();
+    bool finish_traversal = !def_use_mgr->WhileEachUser(
+        ptr_id, [this, &worklist, &ptr_id, handle_load,
+                 &entry_function_ids](Instruction* user) {
+          BasicBlock* block = context()->get_instr_block(user);
+          if (block == nullptr ||
+              entry_function_ids.find(block->GetParent()->result_id()) ==
+                  entry_function_ids.end()) {
+            return true;
+          }
+
+          if (user->opcode() == SpvOpAccessChain ||
+              user->opcode() == SpvOpInBoundsAccessChain ||
+              user->opcode() == SpvOpPtrAccessChain ||
+              user->opcode() == SpvOpInBoundsPtrAccessChain ||
+              user->opcode() == SpvOpCopyObject) {
+            if (ptr_id == user->GetSingleWordInOperand(0))
+              worklist.push_back(user->result_id());
+            return true;
+          }
+
+          if (user->opcode() != SpvOpLoad) {
+            return true;
+          }
+
+          return handle_load(user);
+        });
+    if (finish_traversal) return false;
+  }
+  return true;
+}
+
+void SpreadVolatileSemantics::SetVolatileForLoadsInEntries(
+    Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids) {
+  // Set Volatile memory operand for all load instructions if they do not have
+  // it.
+  VisitLoadsOfPointersToVariableInEntries(
+      var->result_id(),
+      [](Instruction* load) {
+        if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) {
+          load->AddOperand(
+              {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessVolatileMask}});
+          return true;
+        }
+        uint32_t memory_operands =
+            load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands);
+        memory_operands |= SpvMemoryAccessVolatileMask;
+        load->SetInOperand(kOpLoadInOperandMemoryOperands, {memory_operands});
+        return true;
+      },
+      entry_function_ids);
+}
+
+bool SpreadVolatileSemantics::IsTargetForVolatileSemantics(
+    uint32_t var_id, SpvExecutionModel execution_model) {
+  analysis::DecorationManager* decoration_manager =
+      context()->get_decoration_mgr();
+  if (execution_model == SpvExecutionModelFragment) {
+    return get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 6) &&
+           HasBuiltinDecoration(decoration_manager, var_id,
+                                SpvBuiltInHelperInvocation);
+  }
+
+  if (execution_model == SpvExecutionModelIntersectionKHR ||
+      execution_model == SpvExecutionModelIntersectionNV) {
+    if (HasBuiltinDecoration(decoration_manager, var_id,
+                             SpvBuiltInRayTmaxKHR)) {
+      return true;
+    }
+  }
+
+  switch (execution_model) {
+    case SpvExecutionModelRayGenerationKHR:
+    case SpvExecutionModelClosestHitKHR:
+    case SpvExecutionModelMissKHR:
+    case SpvExecutionModelCallableKHR:
+    case SpvExecutionModelIntersectionKHR:
+      return HasBuiltinForRayTracingVolatileSemantics(decoration_manager,
+                                                      var_id);
+    default:
+      return false;
+  }
+}
+
+}  // namespace opt
+}  // namespace spvtools

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

@@ -0,0 +1,110 @@
+// Copyright (c) 2022 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_SPREAD_VOLATILE_SEMANTICS_H_
+#define SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_
+
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class SpreadVolatileSemantics : public Pass {
+ public:
+  SpreadVolatileSemantics() {}
+
+  const char* name() const override { return "spread-volatile-semantics"; }
+
+  Status Process() override;
+
+  IRContext::Analysis GetPreservedAnalyses() override {
+    return IRContext::kAnalysisDefUse | IRContext::kAnalysisDecorations |
+           IRContext::kAnalysisInstrToBlockMapping;
+  }
+
+ private:
+  // Iterates interface variables and spreads the Volatile semantics if it has
+  // load instructions for the Volatile semantics.
+  Pass::Status SpreadVolatileSemanticsToVariables(
+      const bool is_vk_memory_model_enabled);
+
+  // Returns whether |var_id| is the result id of a target builtin variable for
+  // the volatile semantics for |execution_model| based on the Vulkan spec
+  // VUID-StandaloneSpirv-VulkanMemoryModel-04678 or
+  // VUID-StandaloneSpirv-VulkanMemoryModel-04679.
+  bool IsTargetForVolatileSemantics(uint32_t var_id,
+                                    SpvExecutionModel execution_model);
+
+  // Collects interface variables that need the volatile semantics.
+  // |is_vk_memory_model_enabled| is true if VulkanMemoryModel capability is
+  // enabled.
+  void CollectTargetsForVolatileSemantics(
+      const bool is_vk_memory_model_enabled);
+
+  // Reports an error if an interface variable is used by two entry points and
+  // it needs the Volatile decoration for one but not for another. Returns true
+  // if the error must be reported.
+  bool HasInterfaceInConflictOfVolatileSemantics();
+
+  // Returns whether the variable whose result is |var_id| is used by a
+  // non-volatile load or a pointer to it is used by a non-volatile load in
+  // |entry_point| or not.
+  bool IsTargetUsedByNonVolatileLoadInEntryPoint(uint32_t var_id,
+                                                 Instruction* entry_point);
+
+  // Visits load instructions of pointers to variable whose result id is
+  // |var_id| if the load instructions are in entry points whose
+  // function id is one of |entry_function_ids|. |handle_load| is a function to
+  // do some actions for the load instructions. Finishes the traversal and
+  // returns false if |handle_load| returns false for a load instruction.
+  // Otherwise, returns true after running |handle_load| for all the load
+  // instructions.
+  bool VisitLoadsOfPointersToVariableInEntries(
+      uint32_t var_id, const std::function<bool(Instruction*)>& handle_load,
+      const std::unordered_set<uint32_t>& entry_function_ids);
+
+  // Sets Memory Operands of OpLoad instructions that load |var| or pointers
+  // of |var| as Volatile if the function id of the OpLoad instruction is
+  // included in |entry_function_ids|.
+  void SetVolatileForLoadsInEntries(
+      Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids);
+
+  // Adds OpDecorate Volatile for |var| if it does not exist.
+  void DecorateVarWithVolatile(Instruction* var);
+
+  // Returns a set of entry function ids to spread the volatile semantics for
+  // the variable with the result id |var_id|.
+  std::unordered_set<uint32_t> EntryFunctionsToSpreadVolatileSemanticsForVar(
+      uint32_t var_id) {
+    auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id);
+    if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) return {};
+    return itr->second;
+  }
+
+  // Specifies that we have to spread the volatile semantics for the
+  // variable with the result id |var_id| for the entry point |entry_point|.
+  void MarkVolatileSemanticsForVariable(uint32_t var_id,
+                                        Instruction* entry_point);
+
+  // Result ids of variables to entry function ids for the volatile semantics
+  // spread.
+  std::unordered_map<uint32_t, std::unordered_set<uint32_t>>
+      var_ids_to_entry_fn_for_volatile_semantics_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_

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

@@ -151,7 +151,7 @@ Pass::Status UnifyConstantPass::Process() {
       // 'SpecId' decoration and all of them should be treated as unique.
       // 'SpecId' is not applicable to SpecConstants defined with
       // OpSpecConstant{Op|Composite}, their values are not necessary to be
-      // unique. When all the operands/compoents are the same between two
+      // unique. When all the operands/components are the same between two
       // OpSpecConstant{Op|Composite} results, their result values must be the
       // same so are unifiable.
       case SpvOp::SpvOpSpecConstantOp:

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

@@ -73,7 +73,7 @@ class VectorDCE : public MemPass {
   bool RewriteInstructions(Function* function,
                            const LiveComponentMap& live_components);
 
-  // Makrs all DebugValue instructions that use |composite| for their values as
+  // Makes all DebugValue instructions that use |composite| for their values as
   // dead instructions by putting them into |dead_dbg_value|.
   void MarkDebugValueUsesAsDead(Instruction* composite,
                                 std::vector<Instruction*>* dead_dbg_value);

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

@@ -153,7 +153,7 @@ void RemoveStructMemberReductionOpportunity::AdjustAccessedIndices(
         next_type = type_inst->GetSingleWordInOperand(0);
         break;
       case SpvOpTypeStruct: {
-        // Struct types are special becuase (a) we may need to adjust the index
+        // Struct types are special because (a) we may need to adjust the index
         // being used, if the struct type is the one from which we are removing
         // a member, and (b) the type encountered by following the current index
         // is dependent on the value of the index.

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

@@ -136,9 +136,9 @@ RemoveUnusedStructMemberReductionOpportunityFinder::GetAvailableOpportunities(
     }
   }
 
-  // We now know those struct indices that are unsed, and we make a reduction
+  // We now know those struct indices that are unused, and we make a reduction
   // opportunity for each of them. By mapping each relevant member index to the
-  // structs in which it is unsed, we will group all opportunities to remove
+  // structs in which it is unused, we will group all opportunities to remove
   // member k of a struct (for some k) together.  This reduces the likelihood
   // that opportunities to remove members from the same struct will be adjacent,
   // which is good because such opportunities mutually disable one another.

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

@@ -96,7 +96,7 @@ StructuredConstructToBlockReductionOpportunityFinder::GetAvailableOpportunities(
         // This also means that we don't add a region.
         continue;
       }
-      // We have a reachable header block with a rechable merge that
+      // We have a reachable header block with a reachable merge that
       // postdominates the header: this means we have a new region.
       regions.emplace(&block, std::unordered_set<opt::BasicBlock*>());
     }
@@ -128,7 +128,7 @@ bool StructuredConstructToBlockReductionOpportunityFinder::
     if (!block->WhileEachInst(
             [context, &header, &region](opt::Instruction* inst) -> bool {
               if (inst->result_id() == 0) {
-                // The instruction does not genreate a result id, thus it cannot
+                // The instruction does not generate a result id, thus it cannot
                 // be referred to outside the region - this is fine.
                 return true;
               }

+ 1 - 1
3rdparty/spirv-tools/source/spirv_definition.h

@@ -27,7 +27,7 @@ typedef struct spv_header_t {
   uint32_t generator;
   uint32_t bound;
   uint32_t schema;               // NOTE: Reserved
-  const uint32_t* instructions;  // NOTE: Unfixed pointer to instruciton stream
+  const uint32_t* instructions;  // NOTE: Unfixed pointer to instruction stream
 } spv_header_t;
 
 #endif  // SOURCE_SPIRV_DEFINITION_H_

+ 1 - 1
3rdparty/spirv-tools/source/spirv_endian.h

@@ -31,7 +31,7 @@ uint64_t spvFixDoubleWord(const uint32_t low, const uint32_t high,
 spv_result_t spvBinaryEndianness(const spv_const_binary binary,
                                  spv_endianness_t* endian);
 
-// Returns true if the given endianness matches the host's native endiannes.
+// Returns true if the given endianness matches the host's native endianness.
 bool spvIsHostEndian(spv_endianness_t endian);
 
 #endif  // SOURCE_SPIRV_ENDIAN_H_

+ 12 - 2
3rdparty/spirv-tools/source/spirv_target_env.cpp

@@ -74,6 +74,8 @@ const char* spvTargetEnvDescription(spv_target_env env) {
       return "SPIR-V 1.5 (under Vulkan 1.2 semantics)";
     case SPV_ENV_UNIVERSAL_1_6:
       return "SPIR-V 1.6";
+    case SPV_ENV_VULKAN_1_3:
+      return "SPIR-V 1.6 (under Vulkan 1.3 semantics)";
     case SPV_ENV_MAX:
       assert(false && "Invalid target environment value.");
       break;
@@ -116,6 +118,7 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) {
     case SPV_ENV_VULKAN_1_2:
       return SPV_SPIRV_VERSION_WORD(1, 5);
     case SPV_ENV_UNIVERSAL_1_6:
+    case SPV_ENV_VULKAN_1_3:
       return SPV_SPIRV_VERSION_WORD(1, 6);
     case SPV_ENV_MAX:
       assert(false && "Invalid target environment value.");
@@ -129,6 +132,7 @@ static const std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] = {
     {"vulkan1.0", SPV_ENV_VULKAN_1_0},
     {"vulkan1.1", SPV_ENV_VULKAN_1_1},
     {"vulkan1.2", SPV_ENV_VULKAN_1_2},
+    {"vulkan1.3", SPV_ENV_VULKAN_1_3},
     {"spv1.0", SPV_ENV_UNIVERSAL_1_0},
     {"spv1.1", SPV_ENV_UNIVERSAL_1_1},
     {"spv1.2", SPV_ENV_UNIVERSAL_1_2},
@@ -182,7 +186,8 @@ static const VulkanEnv ordered_vulkan_envs[] = {
     {SPV_ENV_VULKAN_1_0, VULKAN_VER(1, 0), SPIRV_VER(1, 0)},
     {SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)},
     {SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)},
-    {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)}};
+    {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)},
+    {SPV_ENV_VULKAN_1_3, VULKAN_VER(1, 3), SPIRV_VER(1, 6)}};
 
 bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver,
                        spv_target_env* env) {
@@ -222,6 +227,7 @@ bool spvIsVulkanEnv(spv_target_env env) {
     case SPV_ENV_VULKAN_1_1:
     case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
     case SPV_ENV_VULKAN_1_2:
+    case SPV_ENV_VULKAN_1_3:
       return true;
     case SPV_ENV_WEBGPU_0:
       assert(false && "Deprecated target environment value.");
@@ -251,6 +257,7 @@ bool spvIsOpenCLEnv(spv_target_env env) {
     case SPV_ENV_UNIVERSAL_1_5:
     case SPV_ENV_VULKAN_1_2:
     case SPV_ENV_UNIVERSAL_1_6:
+    case SPV_ENV_VULKAN_1_3:
       return false;
     case SPV_ENV_OPENCL_1_2:
     case SPV_ENV_OPENCL_EMBEDDED_1_2:
@@ -292,6 +299,7 @@ bool spvIsOpenGLEnv(spv_target_env env) {
     case SPV_ENV_UNIVERSAL_1_5:
     case SPV_ENV_VULKAN_1_2:
     case SPV_ENV_UNIVERSAL_1_6:
+    case SPV_ENV_VULKAN_1_3:
       return false;
     case SPV_ENV_OPENGL_4_0:
     case SPV_ENV_OPENGL_4_1:
@@ -330,6 +338,7 @@ bool spvIsValidEnv(spv_target_env env) {
     case SPV_ENV_UNIVERSAL_1_5:
     case SPV_ENV_VULKAN_1_2:
     case SPV_ENV_UNIVERSAL_1_6:
+    case SPV_ENV_VULKAN_1_3:
     case SPV_ENV_OPENGL_4_0:
     case SPV_ENV_OPENGL_4_1:
     case SPV_ENV_OPENGL_4_2:
@@ -365,7 +374,8 @@ std::string spvLogStringForEnv(spv_target_env env) {
     case SPV_ENV_VULKAN_1_0:
     case SPV_ENV_VULKAN_1_1:
     case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
-    case SPV_ENV_VULKAN_1_2: {
+    case SPV_ENV_VULKAN_1_2:
+    case SPV_ENV_VULKAN_1_3: {
       return "Vulkan";
     }
     case SPV_ENV_UNIVERSAL_1_0:

+ 1 - 1
3rdparty/spirv-tools/source/spirv_target_env.h

@@ -40,7 +40,7 @@ std::string spvLogStringForEnv(spv_target_env env);
 
 // Returns a formatted list of all SPIR-V target environment names that
 // can be parsed by spvParseTargetEnv.
-// |pad| is the number of space characters that the begining of each line
+// |pad| is the number of space characters that the beginning of each line
 //       except the first one will be padded with.
 // |wrap| is the max length of lines the user desires. Word-wrapping will
 //        occur to satisfy this limit.

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

@@ -42,6 +42,7 @@ spv_context spvContextCreate(spv_target_env env) {
     case SPV_ENV_UNIVERSAL_1_5:
     case SPV_ENV_VULKAN_1_2:
     case SPV_ENV_UNIVERSAL_1_6:
+    case SPV_ENV_VULKAN_1_3:
       break;
     default:
       return nullptr;

+ 1 - 1
3rdparty/spirv-tools/source/util/bit_vector.h

@@ -32,7 +32,7 @@ class BitVector {
   enum { kInitialNumBits = 1024 };
 
  public:
-  // Creates a bit vector contianing 0s.
+  // Creates a bit vector containing 0s.
   BitVector(uint32_t reserved_size = kInitialNumBits)
       : bits_((reserved_size - 1) / kBitContainerSize + 1, 0) {}
 

+ 1 - 1
3rdparty/spirv-tools/source/util/ilist.h

@@ -59,7 +59,7 @@ class IntrusiveList {
   // Moves the contents of the given list to the list being constructed.
   IntrusiveList(IntrusiveList&&);
 
-  // Destorys the list.  Note that the elements of the list will not be deleted,
+  // Destroys the list.  Note that the elements of the list will not be deleted,
   // but they will be removed from the list.
   virtual ~IntrusiveList();
 

+ 1 - 1
3rdparty/spirv-tools/source/util/parse_number.h

@@ -220,7 +220,7 @@ EncodeNumberStatus ParseAndEncodeIntegerNumber(
     std::function<void(uint32_t)> emit, std::string* error_msg);
 
 // Parses a floating point value of a given |type| from the given |text| and
-// encodes the number by the given |emit| funciton. On success, returns
+// encodes the number by the given |emit| function. On success, returns
 // EncodeNumberStatus::kSuccess and the parsed number will be consumed by the
 // given |emit| function word by word (least significant word first). On
 // failure, this function returns the error code of the encoding status and

+ 5 - 2
3rdparty/spirv-tools/source/util/small_vector.h

@@ -175,9 +175,12 @@ class SmallVector {
     return true;
   }
 
+// Avoid infinite recursion from rewritten operators in C++20
+#if __cplusplus <= 201703L
   friend bool operator==(const std::vector<T>& lhs, const SmallVector& rhs) {
     return rhs == lhs;
   }
+#endif
 
   friend bool operator!=(const SmallVector& lhs, const std::vector<T>& rhs) {
     return !(lhs == rhs);
@@ -363,7 +366,7 @@ class SmallVector {
       }
     }
 
-    // Upate the size.
+    // Update the size.
     size_ += num_of_new_elements;
     return pos;
   }
@@ -449,7 +452,7 @@ class SmallVector {
   T* small_data_;
 
   // The actual data used to store the array elements.  It must never be used
-  // directly, but must only be accesed through |small_data_|.
+  // directly, but must only be accessed through |small_data_|.
   typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type
       buffer[small_size];
 

+ 3 - 3
3rdparty/spirv-tools/source/util/timer.h

@@ -206,16 +206,16 @@ class Timer {
 
   // Variable to save the result of clock_gettime(CLOCK_PROCESS_CPUTIME_ID) when
   // Timer::Stop() is called. It is used as the last status of CPU time. The
-  // resouce usage is measured by subtracting |cpu_before_| from it.
+  // resource usage is measured by subtracting |cpu_before_| from it.
   timespec cpu_after_;
 
   // Variable to save the result of clock_gettime(CLOCK_MONOTONIC) when
   // Timer::Stop() is called. It is used as the last status of WALL time. The
-  // resouce usage is measured by subtracting |wall_before_| from it.
+  // resource usage is measured by subtracting |wall_before_| from it.
   timespec wall_after_;
 
   // Variable to save the result of getrusage() when Timer::Stop() is called. It
-  // is used as the last status of USR time, SYS time, and RSS. Those resouce
+  // is used as the last status of USR time, SYS time, and RSS. Those resource
   // usages are measured by subtracting |usage_before_| from it.
   rusage usage_after_;
 

+ 6 - 6
3rdparty/spirv-tools/source/val/basic_block.h

@@ -84,26 +84,26 @@ class BasicBlock {
       type_.set(type);
   }
 
-  /// Sets the immedate dominator of this basic block
+  /// Sets the immediate dominator of this basic block
   ///
   /// @param[in] dom_block The dominator block
   void SetImmediateDominator(BasicBlock* dom_block);
 
-  /// Sets the immedate post dominator of this basic block
+  /// Sets the immediate post dominator of this basic block
   ///
   /// @param[in] pdom_block The post dominator block
   void SetImmediatePostDominator(BasicBlock* pdom_block);
 
-  /// Returns the immedate dominator of this basic block
+  /// Returns the immediate dominator of this basic block
   BasicBlock* immediate_dominator();
 
-  /// Returns the immedate dominator of this basic block
+  /// Returns the immediate dominator of this basic block
   const BasicBlock* immediate_dominator() const;
 
-  /// Returns the immedate post dominator of this basic block
+  /// Returns the immediate post dominator of this basic block
   BasicBlock* immediate_post_dominator();
 
-  /// Returns the immedate post dominator of this basic block
+  /// Returns the immediate post dominator of this basic block
   const BasicBlock* immediate_post_dominator() const;
 
   /// Returns the label instruction for the block, or nullptr if not set.

+ 2 - 2
3rdparty/spirv-tools/source/val/function.cpp

@@ -57,7 +57,7 @@ spv_result_t Function::RegisterFunctionParameter(uint32_t parameter_id,
                                                  uint32_t type_id) {
   assert(current_block_ == nullptr &&
          "RegisterFunctionParameter can only be called when parsing the binary "
-         "ouside of a block");
+         "outside of a block");
   // TODO(umar): Validate function parameter type order and count
   // TODO(umar): Use these variables to validate parameter type
   (void)parameter_id;
@@ -130,7 +130,7 @@ spv_result_t Function::RegisterBlock(uint32_t block_id, bool is_definition) {
     undefined_blocks_.erase(block_id);
     current_block_ = &inserted_block->second;
     ordered_blocks_.push_back(current_block_);
-  } else if (success) {  // Block doesn't exsist but this is not a definition
+  } else if (success) {  // Block doesn't exist but this is not a definition
     undefined_blocks_.insert(block_id);
   }
 

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

@@ -73,8 +73,8 @@ class Function {
 
   /// Registers a variable in the current block
   ///
-  /// @param[in] type_id The type ID of the varaible
-  /// @param[in] id      The ID of the varaible
+  /// @param[in] type_id The type ID of the variable
+  /// @param[in] id      The ID of the variable
   /// @param[in] storage The storage of the variable
   /// @param[in] init_id The initializer ID of the variable
   ///
@@ -197,10 +197,10 @@ class Function {
   /// been identified and dominators have been computed.
   int GetBlockDepth(BasicBlock* bb);
 
-  /// Prints a GraphViz digraph of the CFG of the current funciton
+  /// Prints a GraphViz digraph of the CFG of the current function
   void PrintDotGraph() const;
 
-  /// Prints a directed graph of the CFG of the current funciton
+  /// Prints a directed graph of the CFG of the current function
   void PrintBlocks() const;
 
   /// Registers execution model limitation such as "Feature X is only available
@@ -285,7 +285,7 @@ class Function {
   /// The type of the return value
   uint32_t result_type_id_;
 
-  /// The control fo the funciton
+  /// The control fo the function
   SpvFunctionControlMask function_control_;
 
   /// The type of declaration of each function

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

@@ -348,7 +348,7 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
   }
 
   // Validate the preconditions involving adjacent instructions. e.g. SpvOpPhi
-  // must only be preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
+  // must only be preceded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
   if (auto error = ValidateAdjacency(*vstate)) return error;
 
   if (auto error = ValidateEntryPoints(*vstate)) return error;

+ 1 - 1
3rdparty/spirv-tools/source/val/validate.h

@@ -70,7 +70,7 @@ spv_result_t CheckIdDefinitionDominateUse(ValidationState_t& _);
 ///
 /// This function will iterate over all instructions and check for any required
 /// predecessor and/or successor instructions. e.g. SpvOpPhi must only be
-/// preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
+/// preceded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
 ///
 /// @param[in] _ the validation state of the module
 ///

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

@@ -155,7 +155,7 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) {
           first_vector_num_components = num_components;
         } else if (num_components != first_vector_num_components) {
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
-                 << "Expected operands to have the same number of componenets: "
+                 << "Expected operands to have the same number of components: "
                  << spvOpcodeString(opcode);
         }
       }

+ 2 - 2
3rdparty/spirv-tools/source/val/validate_cfg.cpp

@@ -675,7 +675,7 @@ spv_result_t ValidateStructuredSelections(
     } else if (terminator->opcode() == SpvOpSwitch) {
       if (!merge) {
         return _.diag(SPV_ERROR_INVALID_CFG, terminator)
-               << "OpSwitch must be preceeded by an OpSelectionMerge "
+               << "OpSwitch must be preceded by an OpSelectionMerge "
                   "instruction";
       }
       // Mark the targets as seen.
@@ -917,7 +917,7 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) {
           }
         }
       }
-      // If we have structed control flow, check that no block has a control
+      // If we have structured control flow, check that no block has a control
       // flow nesting depth larger than the limit.
       if (_.HasCapability(SpvCapabilityShader)) {
         const int control_flow_nesting_depth_limit =

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

@@ -465,7 +465,7 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
         return lhs.offset < rhs.offset;
       });
 
-  // Now scan from lowest offest to highest offset.
+  // Now scan from lowest offset to highest offset.
   uint32_t nextValidOffset = 0;
   for (size_t ordered_member_idx = 0;
        ordered_member_idx < member_offsets.size(); ordered_member_idx++) {
@@ -720,7 +720,7 @@ spv_result_t CheckBuiltInVariable(uint32_t var_id, ValidationState_t& vstate) {
   return SPV_SUCCESS;
 }
 
-// Checks whether proper decorations have been appied to the entry points.
+// Checks whether proper decorations have been applied to the entry points.
 spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
   for (uint32_t entry_point : vstate.entry_points()) {
     const auto& descs = vstate.entry_point_descriptions(entry_point);

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

@@ -129,7 +129,7 @@ spv_result_t ValidateUint32ConstantOperandForDebugInfo(
   }
 
 // True if the operand of a debug info instruction |inst| at |word_index|
-// satisifies |expectation| that is given as a function. Otherwise,
+// satisfies |expectation| that is given as a function. Otherwise,
 // returns false.
 bool DoesDebugInfoOperandMatchExpectation(
     const ValidationState_t& _,

+ 5 - 4
3rdparty/spirv-tools/source/val/validate_image.cpp

@@ -260,7 +260,8 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
         mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask |
                          SpvImageOperandsVolatileTexelKHRMask |
                          SpvImageOperandsSignExtendMask |
-                         SpvImageOperandsZeroExtendMask);
+                         SpvImageOperandsZeroExtendMask |
+                         SpvImageOperandsNontemporalMask);
     size_t expected_num_image_operand_words =
         spvtools::utils::CountSetBits(mask_bits_having_operands);
     if (mask & SpvImageOperandsGradMask) {
@@ -502,7 +503,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
     if (!_.IsIntVectorType(component_type) ||
         _.GetDimension(component_type) != 2) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
-             << "Expected Image Operand ConstOffsets array componenets to be "
+             << "Expected Image Operand ConstOffsets array components to be "
                 "int vectors of size 2";
     }
 
@@ -1043,7 +1044,7 @@ spv_result_t ValidateSampledImage(ValidationState_t& _,
                << "Result <id> from OpSampledImage instruction must not appear "
                   "as operand for Op"
                << spvOpcodeString(static_cast<SpvOp>(consumer_opcode))
-               << ", since it is not specificed as taking an "
+               << ", since it is not specified as taking an "
                << "OpTypeSampledImage."
                << " Found result <id> '" << _.getIdName(inst->id())
                << "' as an operand of <id> '"
@@ -1672,7 +1673,7 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) {
            << " components, but given only " << actual_coord_size;
   }
 
-  // TODO([email protected]) The spec doesn't explicitely say what the type
+  // TODO([email protected]) The spec doesn't explicitly say what the type
   // of texel should be.
   const uint32_t texel_type = _.GetOperandTypeId(inst, 2);
   if (!_.IsIntScalarOrVectorType(texel_type) &&

+ 2 - 2
3rdparty/spirv-tools/source/val/validate_instruction.cpp

@@ -297,7 +297,7 @@ spv_result_t VersionCheck(ValidationState_t& _, const Instruction* inst) {
   }
 
   // OpTerminateInvocation is special because it is enabled by Shader
-  // capability, but also requries a extension and/or version check.
+  // capability, but also requires an extension and/or version check.
   const bool capability_check_is_sufficient =
       inst->opcode() != SpvOpTerminateInvocation;
 
@@ -406,7 +406,7 @@ spv_result_t LimitCheckSwitch(ValidationState_t& _, const Instruction* inst) {
     // The instruction syntax is as follows:
     // OpSwitch <selector ID> <Default ID> literal label literal label ...
     // literal,label pairs come after the first 2 operands.
-    // It is guaranteed at this point that num_operands is an even numner.
+    // It is guaranteed at this point that num_operands is an even number.
     size_t num_pairs = (inst->operands().size() - 2) / 2;
     const unsigned int num_pairs_limit =
         _.options()->universal_limits_.max_switch_branches;

+ 2 - 2
3rdparty/spirv-tools/source/val/validate_scopes.cpp

@@ -225,7 +225,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst,
              << _.VkErrorID(4638) << spvOpcodeString(opcode)
              << ": in Vulkan environment, Memory Scope cannot be CrossDevice";
     }
-    // Vulkan 1.0 specifc rules
+    // Vulkan 1.0 specific rules
     if (_.context()->target_env == SPV_ENV_VULKAN_1_0 &&
         value != SpvScopeDevice && value != SpvScopeWorkgroup &&
         value != SpvScopeInvocation) {
@@ -234,7 +234,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst,
              << ": in Vulkan 1.0 environment Memory Scope is limited to "
              << "Device, Workgroup and Invocation";
     }
-    // Vulkan 1.1 specifc rules
+    // Vulkan 1.1 specific rules
     if ((_.context()->target_env == SPV_ENV_VULKAN_1_1 ||
          _.context()->target_env == SPV_ENV_VULKAN_1_2) &&
         value != SpvScopeDevice && value != SpvScopeWorkgroup &&

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

@@ -175,7 +175,7 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx,
     }
   }
 
-  // LocalSizeId is only disallowed without maintainence4.
+  // LocalSizeId is only disallowed prior to Vulkan 1.3 without maintenance4.
   switch (env) {
     case SPV_ENV_VULKAN_1_0:
     case SPV_ENV_VULKAN_1_1:
@@ -498,7 +498,7 @@ spv_result_t ValidationState_t::RegisterFunctionEnd() {
          "inside of another function");
   assert(in_block() == false &&
          "RegisterFunctionParameter can only be called when parsing the binary "
-         "ouside of a block");
+         "outside of a block");
   current_function().RegisterFunctionEnd();
   in_function_ = false;
   return SPV_SUCCESS;
@@ -610,7 +610,7 @@ void ValidationState_t::RegisterStorageClassConsumer(
               if (message) {
                 *message =
                     errorVUID +
-                    "in Vulkan evironment, Output Storage Class must not be "
+                    "in Vulkan environment, Output Storage Class must not be "
                     "used in GLCompute, RayGenerationKHR, IntersectionKHR, "
                     "AnyHitKHR, ClosestHitKHR, MissKHR, or CallableKHR "
                     "execution models";
@@ -632,7 +632,7 @@ void ValidationState_t::RegisterStorageClassConsumer(
               if (message) {
                 *message =
                     errorVUID +
-                    "in Vulkan evironment, Workgroup Storage Class is limited "
+                    "in Vulkan environment, Workgroup Storage Class is limited "
                     "to MeshNV, TaskNV, and GLCompute execution model";
               }
               return false;
@@ -1407,7 +1407,7 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
     return "";
   }
 
-  // This large switch case is only searched when an error has occured.
+  // This large switch case is only searched when an error has occurred.
   // If an id is changed, the old case must be modified or removed. Each string
   // here is interpreted as being "implemented"
 

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

@@ -67,7 +67,7 @@ class ValidationState_t {
     bool declare_int16_type = false;     // Allow OpTypeInt with 16 bit width?
     bool declare_float16_type = false;   // Allow OpTypeFloat with 16 bit width?
     bool free_fp_rounding_mode = false;  // Allow the FPRoundingMode decoration
-                                         // and its vaules to be used without
+                                         // and its values to be used without
                                          // requiring any capability
 
     // Allow functionalities enabled by VariablePointers capability.
@@ -797,7 +797,7 @@ class ValidationState_t {
   /// IDs that are entry points, ie, arguments to OpEntryPoint.
   std::vector<uint32_t> entry_points_;
 
-  /// Maps an entry point id to its desciptions.
+  /// Maps an entry point id to its descriptions.
   std::unordered_map<uint32_t, std::vector<EntryPointDescription>>
       entry_point_descriptions_;
 
@@ -844,7 +844,7 @@ class ValidationState_t {
   // have the same pointer size (for physical pointer types).
   uint32_t pointer_size_and_alignment_;
 
-  /// NOTE: See correspoding getter functions
+  /// NOTE: See corresponding getter functions
   bool in_function_;
 
   /// The state of optional features.  These are determined by capabilities