Explorar el Código

Updated spirv-tools.

Бранимир Караџић hace 4 años
padre
commit
b9d37691cf

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

@@ -1 +1 @@
-"v2020.7-dev", "SPIRV-Tools v2020.7-dev 93efa0c36bc823ed865bd45418c57390547cef74"
+"v2020.7-dev", "SPIRV-Tools v2020.7-dev 45234794d9cc274023fbed948636fd006b589aef"

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

@@ -626,6 +626,12 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetUniformBufferStandardLayout(
 SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetScalarBlockLayout(
 SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetScalarBlockLayout(
     spv_validator_options options, bool val);
     spv_validator_options options, bool val);
 
 
+// Records whether the validator should use "scalar" block layout
+// rules (as defined above) for Workgroup blocks.  See Vulkan
+// extension VK_KHR_workgroup_memory_explicit_layout.
+SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetWorkgroupScalarBlockLayout(
+    spv_validator_options options, bool val);
+
 // Records whether or not the validator should skip validating standard
 // Records whether or not the validator should skip validating standard
 // uniform/storage block layout.
 // uniform/storage block layout.
 SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetSkipBlockLayout(
 SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetSkipBlockLayout(

+ 6 - 0
3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp

@@ -104,6 +104,12 @@ class ValidatorOptions {
     spvValidatorOptionsSetScalarBlockLayout(options_, val);
     spvValidatorOptionsSetScalarBlockLayout(options_, val);
   }
   }
 
 
+  // Enables scalar layout when validating Workgroup blocks.  See
+  // VK_KHR_workgroup_memory_explicit_layout.
+  void SetWorkgroupScalarBlockLayout(bool val) {
+    spvValidatorOptionsSetWorkgroupScalarBlockLayout(options_, val);
+  }
+
   // Skips validating standard uniform/storage buffer/push-constant layout.
   // Skips validating standard uniform/storage buffer/push-constant layout.
   void SetSkipBlockLayout(bool val) {
   void SetSkipBlockLayout(bool val) {
     spvValidatorOptionsSetSkipBlockLayout(options_, val);
     spvValidatorOptionsSetSkipBlockLayout(options_, val);

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

@@ -147,8 +147,8 @@ bool ConvertToHalfPass::MatConvertCleanup(Instruction* inst) {
   return true;
   return true;
 }
 }
 
 
-void ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) {
-  context()->get_decoration_mgr()->RemoveDecorationsFrom(
+bool ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) {
+  return context()->get_decoration_mgr()->RemoveDecorationsFrom(
       id, [](const Instruction& dec) {
       id, [](const Instruction& dec) {
         if (dec.opcode() == SpvOpDecorate &&
         if (dec.opcode() == SpvOpDecorate &&
             dec.GetSingleWordInOperand(1u) == SpvDecorationRelaxedPrecision)
             dec.GetSingleWordInOperand(1u) == SpvDecorationRelaxedPrecision)
@@ -344,10 +344,14 @@ Pass::Status ConvertToHalfPass::ProcessImpl() {
   // If modified, make sure module has Float16 capability
   // If modified, make sure module has Float16 capability
   if (modified) context()->AddCapability(SpvCapabilityFloat16);
   if (modified) context()->AddCapability(SpvCapabilityFloat16);
   // Remove all RelaxedPrecision decorations from instructions and globals
   // Remove all RelaxedPrecision decorations from instructions and globals
-  for (auto c_id : relaxed_ids_set_) RemoveRelaxedDecoration(c_id);
+  for (auto c_id : relaxed_ids_set_) {
+    modified |= RemoveRelaxedDecoration(c_id);
+  }
   for (auto& val : get_module()->types_values()) {
   for (auto& val : get_module()->types_values()) {
     uint32_t v_id = val.result_id();
     uint32_t v_id = val.result_id();
-    if (v_id != 0) RemoveRelaxedDecoration(v_id);
+    if (v_id != 0) {
+      modified |= RemoveRelaxedDecoration(v_id);
+    }
   }
   }
   return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
   return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
 }
 }

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

@@ -74,7 +74,7 @@ class ConvertToHalfPass : public Pass {
   void GenConvert(uint32_t* val_idp, uint32_t width, Instruction* inst);
   void GenConvert(uint32_t* val_idp, uint32_t width, Instruction* inst);
 
 
   // Remove RelaxedPrecision decoration of |id|.
   // Remove RelaxedPrecision decoration of |id|.
-  void RemoveRelaxedDecoration(uint32_t id);
+  bool RemoveRelaxedDecoration(uint32_t id);
 
 
   // Add |inst| to relaxed instruction set if warranted. Specifically, if
   // Add |inst| to relaxed instruction set if warranted. Specifically, if
   // it is float32 and either decorated relaxed or a composite or phi
   // it is float32 and either decorated relaxed or a composite or phi

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

@@ -500,14 +500,15 @@ bool DebugInfoManager::AddDebugValueIfVarDeclIsVisible(
            insert_before->opcode() == SpvOpVariable) {
            insert_before->opcode() == SpvOpVariable) {
       insert_before = insert_before->NextNode();
       insert_before = insert_before->NextNode();
     }
     }
-    modified |= AddDebugValueForDecl(dbg_decl_or_val, value_id,
-                                     insert_before) != nullptr;
+    modified |= AddDebugValueForDecl(dbg_decl_or_val, value_id, insert_before,
+                                     scope_and_line) != nullptr;
   }
   }
   return modified;
   return modified;
 }
 }
 
 
 Instruction* DebugInfoManager::AddDebugValueForDecl(
 Instruction* DebugInfoManager::AddDebugValueForDecl(
-    Instruction* dbg_decl, uint32_t value_id, Instruction* insert_before) {
+    Instruction* dbg_decl, uint32_t value_id, Instruction* insert_before,
+    Instruction* scope_and_line) {
   if (dbg_decl == nullptr || !IsDebugDeclare(dbg_decl)) return nullptr;
   if (dbg_decl == nullptr || !IsDebugDeclare(dbg_decl)) return nullptr;
 
 
   std::unique_ptr<Instruction> dbg_val(dbg_decl->Clone(context()));
   std::unique_ptr<Instruction> dbg_val(dbg_decl->Clone(context()));
@@ -517,6 +518,7 @@ Instruction* DebugInfoManager::AddDebugValueForDecl(
   dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id});
   dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id});
   dbg_val->SetOperand(kDebugValueOperandExpressionIndex,
   dbg_val->SetOperand(kDebugValueOperandExpressionIndex,
                       {GetEmptyDebugExpression()->result_id()});
                       {GetEmptyDebugExpression()->result_id()});
+  dbg_val->UpdateDebugInfoFrom(scope_and_line);
 
 
   auto* added_dbg_val = insert_before->InsertBefore(std::move(dbg_val));
   auto* added_dbg_val = insert_before->InsertBefore(std::move(dbg_val));
   AnalyzeDebugInst(added_dbg_val);
   AnalyzeDebugInst(added_dbg_val);

+ 7 - 4
3rdparty/spirv-tools/source/opt/debug_info_manager.h

@@ -152,11 +152,14 @@ class DebugInfoManager {
       std::unordered_set<Instruction*>* invisible_decls);
       std::unordered_set<Instruction*>* invisible_decls);
 
 
   // Creates a DebugValue for DebugDeclare |dbg_decl| and inserts it before
   // Creates a DebugValue for DebugDeclare |dbg_decl| and inserts it before
-  // |insert_before|. The new DebugValue has the same line, scope, and
-  // operands with DebugDeclare but it uses |value_id| for value. Returns
-  // the added DebugValue, or nullptr if it does not add a DebugValue.
+  // |insert_before|. The new DebugValue has the same line and scope as
+  // |scope_and_line|, or no scope and line information if |scope_and_line|
+  // is nullptr. The new DebugValue has the same operands as DebugDeclare
+  // but it uses |value_id| for the value. Returns the created DebugValue,
+  // or nullptr if fails to create one.
   Instruction* AddDebugValueForDecl(Instruction* dbg_decl, uint32_t value_id,
   Instruction* AddDebugValueForDecl(Instruction* dbg_decl, uint32_t value_id,
-                                    Instruction* insert_before);
+                                    Instruction* insert_before,
+                                    Instruction* scope_and_line);
 
 
   // Erases |instr| from data structures of this class.
   // Erases |instr| from data structures of this class.
   void ClearDebugInfo(Instruction* instr);
   void ClearDebugInfo(Instruction* instr);

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

@@ -53,11 +53,12 @@ namespace spvtools {
 namespace opt {
 namespace opt {
 namespace analysis {
 namespace analysis {
 
 
-void DecorationManager::RemoveDecorationsFrom(
+bool DecorationManager::RemoveDecorationsFrom(
     uint32_t id, std::function<bool(const Instruction&)> pred) {
     uint32_t id, std::function<bool(const Instruction&)> pred) {
+  bool was_modified = false;
   const auto ids_iter = id_to_decoration_insts_.find(id);
   const auto ids_iter = id_to_decoration_insts_.find(id);
   if (ids_iter == id_to_decoration_insts_.end()) {
   if (ids_iter == id_to_decoration_insts_.end()) {
-    return;
+    return was_modified;
   }
   }
 
 
   TargetData& decorations_info = ids_iter->second;
   TargetData& decorations_info = ids_iter->second;
@@ -99,7 +100,6 @@ void DecorationManager::RemoveDecorationsFrom(
 
 
     // Otherwise, remove |id| from the targets of |group_id|
     // Otherwise, remove |id| from the targets of |group_id|
     const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
     const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
-    bool was_modified = false;
     for (uint32_t i = 1u; i < inst->NumInOperands();) {
     for (uint32_t i = 1u; i < inst->NumInOperands();) {
       if (inst->GetSingleWordInOperand(i) != id) {
       if (inst->GetSingleWordInOperand(i) != id) {
         i += stride;
         i += stride;
@@ -155,6 +155,7 @@ void DecorationManager::RemoveDecorationsFrom(
           }),
           }),
       indirect_decorations.end());
       indirect_decorations.end());
 
 
+  was_modified |= !insts_to_kill.empty();
   for (Instruction* inst : insts_to_kill) context->KillInst(inst);
   for (Instruction* inst : insts_to_kill) context->KillInst(inst);
   insts_to_kill.clear();
   insts_to_kill.clear();
 
 
@@ -165,6 +166,7 @@ void DecorationManager::RemoveDecorationsFrom(
     for (Instruction* inst : decorations_info.decorate_insts)
     for (Instruction* inst : decorations_info.decorate_insts)
       insts_to_kill.push_back(inst);
       insts_to_kill.push_back(inst);
   }
   }
+  was_modified |= !insts_to_kill.empty();
   for (Instruction* inst : insts_to_kill) context->KillInst(inst);
   for (Instruction* inst : insts_to_kill) context->KillInst(inst);
 
 
   if (decorations_info.direct_decorations.empty() &&
   if (decorations_info.direct_decorations.empty() &&
@@ -172,6 +174,7 @@ void DecorationManager::RemoveDecorationsFrom(
       decorations_info.decorate_insts.empty()) {
       decorations_info.decorate_insts.empty()) {
     id_to_decoration_insts_.erase(ids_iter);
     id_to_decoration_insts_.erase(ids_iter);
   }
   }
+  return was_modified;
 }
 }
 
 
 std::vector<Instruction*> DecorationManager::GetDecorationsFor(
 std::vector<Instruction*> DecorationManager::GetDecorationsFor(

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

@@ -36,8 +36,9 @@ class DecorationManager {
   }
   }
   DecorationManager() = delete;
   DecorationManager() = delete;
 
 
-  // Changes all of the decorations (direct and through groups) where |pred| is
-  // true and that apply to |id| so that they no longer apply to |id|.
+  // Removes all decorations (direct and through groups) where |pred| is
+  // true and that apply to |id| so that they no longer apply to |id|.  Returns
+  // true if something changed.
   //
   //
   // If |id| is part of a group, it will be removed from the group if it
   // If |id| is part of a group, it will be removed from the group if it
   // does not use all of the group's decorations, or, if there are no
   // does not use all of the group's decorations, or, if there are no
@@ -52,9 +53,9 @@ class DecorationManager {
   // removed, then the |OpGroupDecorate| and
   // removed, then the |OpGroupDecorate| and
   // |OpGroupMemberDecorate| for the group will be killed, but not the defining
   // |OpGroupMemberDecorate| for the group will be killed, but not the defining
   // |OpDecorationGroup| instruction.
   // |OpDecorationGroup| instruction.
-  void RemoveDecorationsFrom(uint32_t id,
-                             std::function<bool(const Instruction&)> pred =
-                                 [](const Instruction&) { return true; });
+  bool RemoveDecorationsFrom(
+      uint32_t id, std::function<bool(const Instruction&)> pred =
+                       [](const Instruction&) { return true; });
 
 
   // Removes all decorations from the result id of |inst|.
   // Removes all decorations from the result id of |inst|.
   //
   //

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

@@ -175,7 +175,7 @@ bool LocalSingleStoreElimPass::RewriteDebugDeclares(Instruction* store_inst,
     for (auto* decl : invisible_decls) {
     for (auto* decl : invisible_decls) {
       if (dominator_analysis->Dominates(store_inst, decl)) {
       if (dominator_analysis->Dominates(store_inst, decl)) {
         context()->get_debug_info_mgr()->AddDebugValueForDecl(decl, value_id,
         context()->get_debug_info_mgr()->AddDebugValueForDecl(decl, value_id,
-                                                              decl);
+                                                              decl, store_inst);
         modified = true;
         modified = true;
       }
       }
     }
     }

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

@@ -175,7 +175,8 @@ bool ScalarReplacementPass::ReplaceWholeDebugDeclare(
     Instruction* added_dbg_value =
     Instruction* added_dbg_value =
         context()->get_debug_info_mgr()->AddDebugValueForDecl(
         context()->get_debug_info_mgr()->AddDebugValueForDecl(
             dbg_decl, /*value_id=*/var->result_id(),
             dbg_decl, /*value_id=*/var->result_id(),
-            /*insert_before=*/var->NextNode());
+            /*insert_before=*/var->NextNode(), /*scope_and_line=*/dbg_decl);
+
     if (added_dbg_value == nullptr) return false;
     if (added_dbg_value == nullptr) return false;
     added_dbg_value->AddOperand(
     added_dbg_value->AddOperand(
         {SPV_OPERAND_TYPE_ID,
         {SPV_OPERAND_TYPE_ID,

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

@@ -658,8 +658,8 @@ Pass::Status SSARewriter::AddDebugValuesForInvisibleDebugDecls(Function* fp) {
   //   a = 3;
   //   a = 3;
   //   foo(3);
   //   foo(3);
   // After inlining:
   // After inlining:
-  //   a = 3; // we want to specify "DebugValue: %x = %int_3"
-  //   foo and x disappeared!
+  //   a = 3;
+  //   foo and x disappeared but we want to specify "DebugValue: %x = %int_3".
   //
   //
   // We want to specify the value for the variable using |defs_at_block_[bb]|,
   // We want to specify the value for the variable using |defs_at_block_[bb]|,
   // where |bb| is the basic block contains the decl.
   // where |bb| is the basic block contains the decl.
@@ -681,16 +681,17 @@ Pass::Status SSARewriter::AddDebugValuesForInvisibleDebugDecls(Function* fp) {
     if (value && (pass_->context()->get_instr_block(value) == nullptr ||
     if (value && (pass_->context()->get_instr_block(value) == nullptr ||
                   dom_tree->Dominates(value, decl))) {
                   dom_tree->Dominates(value, decl))) {
       if (pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl(
       if (pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl(
-              decl, value->result_id(), decl) == nullptr) {
+              decl, value->result_id(), decl, value) == nullptr) {
         return Pass::Status::Failure;
         return Pass::Status::Failure;
       }
       }
     } else {
     } else {
       // If |value| in the same basic block does not dominate |decl|, we can
       // If |value| in the same basic block does not dominate |decl|, we can
       // assign the value in the immediate dominator.
       // assign the value in the immediate dominator.
       value_id = GetValueAtBlock(var_id, dom_tree->ImmediateDominator(bb));
       value_id = GetValueAtBlock(var_id, dom_tree->ImmediateDominator(bb));
+      if (value_id) value = pass_->get_def_use_mgr()->GetDef(value_id);
       if (value_id &&
       if (value_id &&
           pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl(
           pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl(
-              decl, value_id, decl) == nullptr) {
+              decl, value_id, decl, value) == nullptr) {
         return Pass::Status::Failure;
         return Pass::Status::Failure;
       }
       }
     }
     }

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

@@ -111,6 +111,11 @@ void spvValidatorOptionsSetScalarBlockLayout(spv_validator_options options,
   options->scalar_block_layout = val;
   options->scalar_block_layout = val;
 }
 }
 
 
+void spvValidatorOptionsSetWorkgroupScalarBlockLayout(spv_validator_options options,
+                                                      bool val) {
+  options->workgroup_scalar_block_layout = val;
+}
+
 void spvValidatorOptionsSetSkipBlockLayout(spv_validator_options options,
 void spvValidatorOptionsSetSkipBlockLayout(spv_validator_options options,
                                            bool val) {
                                            bool val) {
   options->skip_block_layout = val;
   options->skip_block_layout = val;

+ 2 - 0
3rdparty/spirv-tools/source/spirv_validator_options.h

@@ -45,6 +45,7 @@ struct spv_validator_options_t {
         relax_block_layout(false),
         relax_block_layout(false),
         uniform_buffer_standard_layout(false),
         uniform_buffer_standard_layout(false),
         scalar_block_layout(false),
         scalar_block_layout(false),
+        workgroup_scalar_block_layout(false),
         skip_block_layout(false),
         skip_block_layout(false),
         before_hlsl_legalization(false) {}
         before_hlsl_legalization(false) {}
 
 
@@ -54,6 +55,7 @@ struct spv_validator_options_t {
   bool relax_block_layout;
   bool relax_block_layout;
   bool uniform_buffer_standard_layout;
   bool uniform_buffer_standard_layout;
   bool scalar_block_layout;
   bool scalar_block_layout;
+  bool workgroup_scalar_block_layout;
   bool skip_block_layout;
   bool skip_block_layout;
   bool before_hlsl_legalization;
   bool before_hlsl_legalization;
 };
 };

+ 28 - 10
3rdparty/spirv-tools/source/val/validate_conversion.cpp

@@ -14,12 +14,12 @@
 
 
 // Validates correctness of conversion instructions.
 // Validates correctness of conversion instructions.
 
 
-#include "source/val/validate.h"
-
 #include "source/diagnostic.h"
 #include "source/diagnostic.h"
 #include "source/opcode.h"
 #include "source/opcode.h"
 #include "source/spirv_constant.h"
 #include "source/spirv_constant.h"
+#include "source/spirv_target_env.h"
 #include "source/val/instruction.h"
 #include "source/val/instruction.h"
+#include "source/val/validate.h"
 #include "source/val/validation_state.h"
 #include "source/val/validation_state.h"
 
 
 namespace spvtools {
 namespace spvtools {
@@ -263,16 +263,25 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
                << "Logical addressing not supported: "
                << "Logical addressing not supported: "
                << spvOpcodeString(opcode);
                << spvOpcodeString(opcode);
 
 
-      if (_.addressing_model() ==
-          SpvAddressingModelPhysicalStorageBuffer64EXT) {
+      if (_.addressing_model() == SpvAddressingModelPhysicalStorageBuffer64) {
         uint32_t input_storage_class = 0;
         uint32_t input_storage_class = 0;
         uint32_t input_data_type = 0;
         uint32_t input_data_type = 0;
         _.GetPointerTypeInfo(input_type, &input_data_type,
         _.GetPointerTypeInfo(input_type, &input_data_type,
                              &input_storage_class);
                              &input_storage_class);
-        if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
+        if (input_storage_class != SpvStorageClassPhysicalStorageBuffer)
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
-                 << "Pointer storage class must be PhysicalStorageBufferEXT: "
+                 << "Pointer storage class must be PhysicalStorageBuffer: "
                  << spvOpcodeString(opcode);
                  << spvOpcodeString(opcode);
+
+        if (spvIsVulkanEnv(_.context()->target_env)) {
+          if (_.GetBitWidth(result_type) != 64) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << _.VkErrorID(4710)
+                   << "PhysicalStorageBuffer64 addressing mode requires the "
+                      "result integer type to have a 64-bit width for Vulkan "
+                      "environment.";
+          }
+        }
       }
       }
       break;
       break;
     }
     }
@@ -314,16 +323,25 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
                << "Logical addressing not supported: "
                << "Logical addressing not supported: "
                << spvOpcodeString(opcode);
                << spvOpcodeString(opcode);
 
 
-      if (_.addressing_model() ==
-          SpvAddressingModelPhysicalStorageBuffer64EXT) {
+      if (_.addressing_model() == SpvAddressingModelPhysicalStorageBuffer64) {
         uint32_t result_storage_class = 0;
         uint32_t result_storage_class = 0;
         uint32_t result_data_type = 0;
         uint32_t result_data_type = 0;
         _.GetPointerTypeInfo(result_type, &result_data_type,
         _.GetPointerTypeInfo(result_type, &result_data_type,
                              &result_storage_class);
                              &result_storage_class);
-        if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
+        if (result_storage_class != SpvStorageClassPhysicalStorageBuffer)
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
-                 << "Pointer storage class must be PhysicalStorageBufferEXT: "
+                 << "Pointer storage class must be PhysicalStorageBuffer: "
                  << spvOpcodeString(opcode);
                  << spvOpcodeString(opcode);
+
+        if (spvIsVulkanEnv(_.context()->target_env)) {
+          if (_.GetBitWidth(input_type) != 64) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << _.VkErrorID(4710)
+                   << "PhysicalStorageBuffer64 addressing mode requires the "
+                      "input integer to have a 64-bit width for Vulkan "
+                      "environment.";
+          }
+        }
       }
       }
       break;
       break;
     }
     }

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

@@ -379,6 +379,7 @@ bool IsAlignedTo(uint32_t offset, uint32_t alignment) {
 // or row major-ness.
 // or row major-ness.
 spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
 spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
                          const char* decoration_str, bool blockRules,
                          const char* decoration_str, bool blockRules,
+                         bool scalar_block_layout,
                          uint32_t incoming_offset,
                          uint32_t incoming_offset,
                          MemberConstraints& constraints,
                          MemberConstraints& constraints,
                          ValidationState_t& vstate) {
                          ValidationState_t& vstate) {
@@ -392,7 +393,6 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
   // For example, relaxed layout is implied by Vulkan 1.1.  But scalar layout
   // For example, relaxed layout is implied by Vulkan 1.1.  But scalar layout
   // is more permissive than relaxed layout.
   // is more permissive than relaxed layout.
   const bool relaxed_block_layout = vstate.IsRelaxedBlockLayout();
   const bool relaxed_block_layout = vstate.IsRelaxedBlockLayout();
-  const bool scalar_block_layout = vstate.options()->scalar_block_layout;
 
 
   auto fail = [&vstate, struct_id, storage_class_str, decoration_str,
   auto fail = [&vstate, struct_id, storage_class_str, decoration_str,
                blockRules, relaxed_block_layout,
                blockRules, relaxed_block_layout,
@@ -501,6 +501,7 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
     if (SpvOpTypeStruct == opcode &&
     if (SpvOpTypeStruct == opcode &&
         SPV_SUCCESS != (recursive_status = checkLayout(
         SPV_SUCCESS != (recursive_status = checkLayout(
                             id, storage_class_str, decoration_str, blockRules,
                             id, storage_class_str, decoration_str, blockRules,
+                            scalar_block_layout,
                             offset, constraints, vstate)))
                             offset, constraints, vstate)))
       return recursive_status;
       return recursive_status;
     // Check matrix stride.
     // Check matrix stride.
@@ -553,7 +554,8 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
         if (SpvOpTypeStruct == element_inst->opcode() &&
         if (SpvOpTypeStruct == element_inst->opcode() &&
             SPV_SUCCESS != (recursive_status = checkLayout(
             SPV_SUCCESS != (recursive_status = checkLayout(
                                 typeId, storage_class_str, decoration_str,
                                 typeId, storage_class_str, decoration_str,
-                                blockRules, next_offset, constraints, vstate)))
+                                blockRules, scalar_block_layout,
+                                next_offset, constraints, vstate)))
           return recursive_status;
           return recursive_status;
         // If offsets accumulate up to a 16-byte multiple stop checking since
         // If offsets accumulate up to a 16-byte multiple stop checking since
         // it will just repeat.
         // it will just repeat.
@@ -698,6 +700,9 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
     const auto& descs = vstate.entry_point_descriptions(entry_point);
     const auto& descs = vstate.entry_point_descriptions(entry_point);
     int num_builtin_inputs = 0;
     int num_builtin_inputs = 0;
     int num_builtin_outputs = 0;
     int num_builtin_outputs = 0;
+    int num_workgroup_variables = 0;
+    int num_workgroup_variables_with_block = 0;
+    int num_workgroup_variables_with_aliased = 0;
     for (const auto& desc : descs) {
     for (const auto& desc : descs) {
       std::unordered_set<Instruction*> seen_vars;
       std::unordered_set<Instruction*> seen_vars;
       for (auto interface : desc.interfaces) {
       for (auto interface : desc.interfaces) {
@@ -754,6 +759,16 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
           if (auto error = CheckBuiltInVariable(interface, vstate))
           if (auto error = CheckBuiltInVariable(interface, vstate))
             return error;
             return error;
         }
         }
+
+        if (storage_class == SpvStorageClassWorkgroup) {
+          ++num_workgroup_variables;
+          if (type_instr && SpvOpTypeStruct == type_instr->opcode()) {
+            if (hasDecoration(type_id, SpvDecorationBlock, vstate))
+              ++num_workgroup_variables_with_block;
+            if (hasDecoration(var_instr->id(), SpvDecorationAliased, vstate))
+              ++num_workgroup_variables_with_aliased;
+          }
+        }
       }
       }
       if (num_builtin_inputs > 1 || num_builtin_outputs > 1) {
       if (num_builtin_inputs > 1 || num_builtin_outputs > 1) {
         return vstate.diag(SPV_ERROR_INVALID_BINARY,
         return vstate.diag(SPV_ERROR_INVALID_BINARY,
@@ -777,6 +792,30 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
                  << " because it is targeted by an OpEntryPoint instruction.";
                  << " because it is targeted by an OpEntryPoint instruction.";
         }
         }
       }
       }
+
+      if (vstate.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayoutKHR) &&
+          num_workgroup_variables > 0 &&
+          num_workgroup_variables_with_block > 0) {
+        if (num_workgroup_variables != num_workgroup_variables_with_block) {
+          return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point))
+                 << "When declaring WorkgroupMemoryExplicitLayoutKHR, "
+                    "either all or none of the Workgroup Storage Class variables "
+                    "in the entry point interface must point to struct types "
+                    "decorated with Block.  Entry point id "
+                 << entry_point << " does not meet this requirement.";
+        }
+        if (num_workgroup_variables_with_block > 1 &&
+            num_workgroup_variables_with_block !=
+            num_workgroup_variables_with_aliased) {
+          return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point))
+                 << "When declaring WorkgroupMemoryExplicitLayoutKHR, "
+                    "if more than one Workgroup Storage Class variable in "
+                    "the entry point interface point to a type decorated "
+                    "with Block, all of them must be decorated with Aliased. "
+                    "Entry point id "
+                 << entry_point << " does not meet this requirement.";
+        }
+      }
     }
     }
   }
   }
   return SPV_SUCCESS;
   return SPV_SUCCESS;
@@ -942,14 +981,16 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
 
 
       const bool phys_storage_buffer =
       const bool phys_storage_buffer =
           storageClass == SpvStorageClassPhysicalStorageBufferEXT;
           storageClass == SpvStorageClassPhysicalStorageBufferEXT;
-      if (uniform || push_constant || storage_buffer || phys_storage_buffer) {
+      const bool workgroup = storageClass == SpvStorageClassWorkgroup;
+      if (uniform || push_constant || storage_buffer || phys_storage_buffer ||
+          workgroup) {
         const auto ptrInst = vstate.FindDef(words[1]);
         const auto ptrInst = vstate.FindDef(words[1]);
         assert(SpvOpTypePointer == ptrInst->opcode());
         assert(SpvOpTypePointer == ptrInst->opcode());
         auto id = ptrInst->words()[3];
         auto id = ptrInst->words()[3];
         auto id_inst = vstate.FindDef(id);
         auto id_inst = vstate.FindDef(id);
         // Jump through one level of arraying.
         // Jump through one level of arraying.
-        if (id_inst->opcode() == SpvOpTypeArray ||
-            id_inst->opcode() == SpvOpTypeRuntimeArray) {
+        if (!workgroup && (id_inst->opcode() == SpvOpTypeArray ||
+                           id_inst->opcode() == SpvOpTypeRuntimeArray)) {
           id = id_inst->GetOperandAs<uint32_t>(1u);
           id = id_inst->GetOperandAs<uint32_t>(1u);
           id_inst = vstate.FindDef(id);
           id_inst = vstate.FindDef(id);
         }
         }
@@ -961,7 +1002,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
         // Prepare for messages
         // Prepare for messages
         const char* sc_str =
         const char* sc_str =
             uniform ? "Uniform"
             uniform ? "Uniform"
-                    : (push_constant ? "PushConstant" : "StorageBuffer");
+                    : (push_constant ? "PushConstant"
+                                     : (workgroup ? "Workgroup"
+                                                  : "StorageBuffer"));
 
 
         if (spvIsVulkanEnv(vstate.context()->target_env)) {
         if (spvIsVulkanEnv(vstate.context()->target_env)) {
           const bool block = hasDecoration(id, SpvDecorationBlock, vstate);
           const bool block = hasDecoration(id, SpvDecorationBlock, vstate);
@@ -1029,8 +1072,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
           const bool bufferDeco = SpvDecorationBufferBlock == dec.dec_type();
           const bool bufferDeco = SpvDecorationBufferBlock == dec.dec_type();
           const bool blockRules = uniform && blockDeco;
           const bool blockRules = uniform && blockDeco;
           const bool bufferRules =
           const bool bufferRules =
-              (uniform && bufferDeco) || (push_constant && blockDeco) ||
-              ((storage_buffer || phys_storage_buffer) && blockDeco);
+              (uniform && bufferDeco) ||
+              ((push_constant || storage_buffer ||
+                phys_storage_buffer || workgroup) && blockDeco);
           if (uniform && blockDeco) {
           if (uniform && blockDeco) {
             vstate.RegisterPointerToUniformBlock(ptrInst->id());
             vstate.RegisterPointerToUniformBlock(ptrInst->id());
             vstate.RegisterStructForUniformBlock(id);
             vstate.RegisterStructForUniformBlock(id);
@@ -1044,6 +1088,10 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
           if (blockRules || bufferRules) {
           if (blockRules || bufferRules) {
             const char* deco_str = blockDeco ? "Block" : "BufferBlock";
             const char* deco_str = blockDeco ? "Block" : "BufferBlock";
             spv_result_t recursive_status = SPV_SUCCESS;
             spv_result_t recursive_status = SPV_SUCCESS;
+            const bool scalar_block_layout = workgroup ?
+                vstate.options()->workgroup_scalar_block_layout :
+                vstate.options()->scalar_block_layout;
+
             if (isMissingOffsetInStruct(id, vstate)) {
             if (isMissingOffsetInStruct(id, vstate)) {
               return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
               return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
                      << "Structure id " << id << " decorated as " << deco_str
                      << "Structure id " << id << " decorated as " << deco_str
@@ -1072,12 +1120,14 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
                         "decorations.";
                         "decorations.";
             } else if (blockRules &&
             } else if (blockRules &&
                        (SPV_SUCCESS != (recursive_status = checkLayout(
                        (SPV_SUCCESS != (recursive_status = checkLayout(
-                                            id, sc_str, deco_str, true, 0,
+                                            id, sc_str, deco_str, true,
+                                            scalar_block_layout, 0,
                                             constraints, vstate)))) {
                                             constraints, vstate)))) {
               return recursive_status;
               return recursive_status;
             } else if (bufferRules &&
             } else if (bufferRules &&
                        (SPV_SUCCESS != (recursive_status = checkLayout(
                        (SPV_SUCCESS != (recursive_status = checkLayout(
-                                            id, sc_str, deco_str, false, 0,
+                                            id, sc_str, deco_str, false,
+                                            scalar_block_layout, 0,
                                             constraints, vstate)))) {
                                             constraints, vstate)))) {
               return recursive_status;
               return recursive_status;
             }
             }

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

@@ -27,6 +27,7 @@
 #include "source/latest_version_glsl_std_450_header.h"
 #include "source/latest_version_glsl_std_450_header.h"
 #include "source/latest_version_opencl_std_header.h"
 #include "source/latest_version_opencl_std_header.h"
 #include "source/opcode.h"
 #include "source/opcode.h"
+#include "source/spirv_constant.h"
 #include "source/spirv_target_env.h"
 #include "source/spirv_target_env.h"
 #include "source/val/instruction.h"
 #include "source/val/instruction.h"
 #include "source/val/validate.h"
 #include "source/val/validate.h"
@@ -685,6 +686,20 @@ bool IsDebugVariableWithIntScalarType(ValidationState_t& _,
 
 
 }  // anonymous namespace
 }  // anonymous namespace
 
 
+spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
+  if (_.version() < SPV_SPIRV_VERSION_WORD(1, 4)) {
+    std::string extension = GetExtensionString(&(inst->c_inst()));
+    if (extension ==
+        ExtensionToString(kSPV_KHR_workgroup_memory_explicit_layout)) {
+      return _.diag(SPV_ERROR_WRONG_VERSION, inst)
+          << "SPV_KHR_workgroup_memory_explicit_layout extension "
+             "requires SPIR-V version 1.4 or later.";
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t ValidateExtInstImport(ValidationState_t& _,
 spv_result_t ValidateExtInstImport(ValidationState_t& _,
                                    const Instruction* inst) {
                                    const Instruction* inst) {
   const auto name_id = 1;
   const auto name_id = 1;
@@ -3124,6 +3139,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
 
 
 spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) {
 spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) {
   const SpvOp opcode = inst->opcode();
   const SpvOp opcode = inst->opcode();
+  if (opcode == SpvOpExtension) return ValidateExtension(_, inst);
   if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst);
   if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst);
   if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst);
   if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst);
 
 

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

@@ -441,6 +441,17 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
              << "Expected Image Operand Offset to have " << plane_size
              << "Expected Image Operand Offset to have " << plane_size
              << " components, but given " << offset_size;
              << " components, but given " << offset_size;
     }
     }
+
+    if (spvIsVulkanEnv(_.context()->target_env)) {
+      if (opcode != SpvOpImageGather && opcode != SpvOpImageDrefGather &&
+          opcode != SpvOpImageSparseGather &&
+          opcode != SpvOpImageSparseDrefGather) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << _.VkErrorID(4663)
+               << "Image Operand Offset can only be used with "
+                  "OpImage*Gather operations";
+      }
+    }
   }
   }
 
 
   if (mask & SpvImageOperandsConstOffsetsMask) {
   if (mask & SpvImageOperandsConstOffsetsMask) {
@@ -888,6 +899,7 @@ spv_result_t ValidateTypeSampledImage(ValidationState_t& _,
   // Vulkan uses the Sampled=1 case.
   // Vulkan uses the Sampled=1 case.
   if ((info.sampled != 0) && (info.sampled != 1)) {
   if ((info.sampled != 0) && (info.sampled != 1)) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << _.VkErrorID(4657)
            << "Sampled image type requires an image type with \"Sampled\" "
            << "Sampled image type requires an image type with \"Sampled\" "
               "operand set to 0 or 1";
               "operand set to 0 or 1";
   }
   }
@@ -1445,12 +1457,21 @@ spv_result_t ValidateImageGather(ValidationState_t& _,
   }
   }
 
 
   if (opcode == SpvOpImageGather || opcode == SpvOpImageSparseGather) {
   if (opcode == SpvOpImageGather || opcode == SpvOpImageSparseGather) {
-    const uint32_t component_index_type = _.GetOperandTypeId(inst, 4);
+    const uint32_t component = inst->GetOperandAs<uint32_t>(4);
+    const uint32_t component_index_type = _.GetTypeId(component);
     if (!_.IsIntScalarType(component_index_type) ||
     if (!_.IsIntScalarType(component_index_type) ||
         _.GetBitWidth(component_index_type) != 32) {
         _.GetBitWidth(component_index_type) != 32) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
              << "Expected Component to be 32-bit int scalar";
              << "Expected Component to be 32-bit int scalar";
     }
     }
+    if (spvIsVulkanEnv(_.context()->target_env)) {
+      if (!spvOpcodeIsConstant(_.GetIdOpcode(component))) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << _.VkErrorID(4664)
+               << "Expected Component Operand to be a const object for Vulkan "
+                  "environment";
+      }
+    }
   } else {
   } else {
     assert(opcode == SpvOpImageDrefGather ||
     assert(opcode == SpvOpImageDrefGather ||
            opcode == SpvOpImageSparseDrefGather);
            opcode == SpvOpImageSparseDrefGather);

+ 62 - 26
3rdparty/spirv-tools/source/val/validate_memory.cpp

@@ -407,6 +407,10 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
            << "' is not a pointer type.";
            << "' is not a pointer type.";
   }
   }
 
 
+  const auto type_index = 2;
+  const auto value_id = result_type->GetOperandAs<uint32_t>(type_index);
+  auto value_type = _.FindDef(value_id);
+
   const auto initializer_index = 3;
   const auto initializer_index = 3;
   const auto storage_class_index = 2;
   const auto storage_class_index = 2;
   if (initializer_index < inst->operands().size()) {
   if (initializer_index < inst->operands().size()) {
@@ -423,7 +427,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
              << "OpVariable Initializer <id> '" << _.getIdName(initializer_id)
              << "OpVariable Initializer <id> '" << _.getIdName(initializer_id)
              << "' is not a constant or module-scope variable.";
              << "' is not a constant or module-scope variable.";
     }
     }
-    if (initializer->type_id() != result_type->GetOperandAs<uint32_t>(2u)) {
+    if (initializer->type_id() != value_id) {
       return _.diag(SPV_ERROR_INVALID_ID, inst)
       return _.diag(SPV_ERROR_INVALID_ID, inst)
              << "Initializer type must match the type pointed to by the Result "
              << "Initializer type must match the type pointed to by the Result "
                 "Type";
                 "Type";
@@ -440,9 +444,6 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
       storage_class != SpvStorageClassHitAttributeNV &&
       storage_class != SpvStorageClassHitAttributeNV &&
       storage_class != SpvStorageClassCallableDataNV &&
       storage_class != SpvStorageClassCallableDataNV &&
       storage_class != SpvStorageClassIncomingCallableDataNV) {
       storage_class != SpvStorageClassIncomingCallableDataNV) {
-    const auto storage_index = 2;
-    const auto storage_id = result_type->GetOperandAs<uint32_t>(storage_index);
-    const auto storage = _.FindDef(storage_id);
     bool storage_input_or_output = storage_class == SpvStorageClassInput ||
     bool storage_input_or_output = storage_class == SpvStorageClassInput ||
                                    storage_class == SpvStorageClassOutput;
                                    storage_class == SpvStorageClassOutput;
     bool builtin = false;
     bool builtin = false;
@@ -455,7 +456,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
       }
       }
     }
     }
     if (!(storage_input_or_output && builtin) &&
     if (!(storage_input_or_output && builtin) &&
-        ContainsInvalidBool(_, storage, storage_input_or_output)) {
+        ContainsInvalidBool(_, value_type, storage_input_or_output)) {
       return _.diag(SPV_ERROR_INVALID_ID, inst)
       return _.diag(SPV_ERROR_INVALID_ID, inst)
              << "If OpTypeBool is stored in conjunction with OpVariable, it "
              << "If OpTypeBool is stored in conjunction with OpVariable, it "
              << "can only be used with non-externally visible shader Storage "
              << "can only be used with non-externally visible shader Storage "
@@ -535,18 +536,14 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
       if (!IsAllowedTypeOrArrayOfSame(
       if (!IsAllowedTypeOrArrayOfSame(
               _, pointee,
               _, pointee,
               {SpvOpTypeImage, SpvOpTypeSampler, SpvOpTypeSampledImage,
               {SpvOpTypeImage, SpvOpTypeSampler, SpvOpTypeSampledImage,
-               SpvOpTypeAccelerationStructureNV,
-               SpvOpTypeAccelerationStructureKHR, SpvOpTypeRayQueryKHR})) {
+               SpvOpTypeAccelerationStructureKHR})) {
         return _.diag(SPV_ERROR_INVALID_ID, inst)
         return _.diag(SPV_ERROR_INVALID_ID, inst)
-               << "UniformConstant OpVariable <id> '" << _.getIdName(inst->id())
-               << "' has illegal type.\n"
-               << "From Vulkan spec, section 14.5.2:\n"
+               << _.VkErrorID(4655) << "UniformConstant OpVariable <id> '"
+               << _.getIdName(inst->id()) << "' has illegal type.\n"
                << "Variables identified with the UniformConstant storage class "
                << "Variables identified with the UniformConstant storage class "
                << "are used only as handles to refer to opaque resources. Such "
                << "are used only as handles to refer to opaque resources. Such "
                << "variables must be typed as OpTypeImage, OpTypeSampler, "
                << "variables must be typed as OpTypeImage, OpTypeSampler, "
-               << "OpTypeSampledImage, OpTypeAccelerationStructureNV, "
-                  "OpTypeAccelerationStructureKHR, "
-                  "OpTypeRayQueryKHR, "
+               << "OpTypeSampledImage, OpTypeAccelerationStructureKHR, "
                << "or an array of one of these types.";
                << "or an array of one of these types.";
       }
       }
     }
     }
@@ -576,6 +573,28 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
                   "of this type";
                   "of this type";
       }
       }
     }
     }
+
+    // Check for invalid use of Invariant
+    if (storage_class != SpvStorageClassInput &&
+        storage_class != SpvStorageClassOutput) {
+      if (_.HasDecoration(inst->id(), SpvDecorationInvariant)) {
+        return _.diag(SPV_ERROR_INVALID_ID, inst)
+               << _.VkErrorID(4677)
+               << "Variable decorated with Invariant must only be identified "
+                  "with the Input or Output storage class in Vulkan "
+                  "environment.";
+      }
+      // Need to check if only the members in a struct are decorated
+      if (value_type && value_type->opcode() == SpvOpTypeStruct) {
+        if (_.HasDecoration(value_id, SpvDecorationInvariant)) {
+          return _.diag(SPV_ERROR_INVALID_ID, inst)
+                 << _.VkErrorID(4677)
+                 << "Variable struct member decorated with Invariant must only "
+                    "be identified with the Input or Output storage class in "
+                    "Vulkan environment.";
+        }
+      }
+    }
   }
   }
 
 
   // Vulkan Appendix A: Check that if contains initializer, then
   // Vulkan Appendix A: Check that if contains initializer, then
@@ -584,16 +603,26 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
       storage_class != SpvStorageClassPrivate &&
       storage_class != SpvStorageClassPrivate &&
       storage_class != SpvStorageClassFunction) {
       storage_class != SpvStorageClassFunction) {
     if (spvIsVulkanEnv(_.context()->target_env)) {
     if (spvIsVulkanEnv(_.context()->target_env)) {
-      return _.diag(SPV_ERROR_INVALID_ID, inst)
-             << _.VkErrorID(4651) << "OpVariable, <id> '"
-             << _.getIdName(inst->id())
-             << "', has a disallowed initializer & storage class "
-             << "combination.\n"
-             << "From " << spvLogStringForEnv(_.context()->target_env)
-             << " spec:\n"
-             << "Variable declarations that include initializers must have "
-             << "one of the following storage classes: Output, Private, or "
-             << "Function";
+      if (storage_class == SpvStorageClassWorkgroup) {
+        auto init_id = inst->GetOperandAs<uint32_t>(3);
+        auto init = _.FindDef(init_id);
+        if (init->opcode() != SpvOpConstantNull) {
+          return _.diag(SPV_ERROR_INVALID_ID, inst)
+                 << "Variable initializers in Workgroup storage class are "
+                    "limited to OpConstantNull";
+        }
+      } else {
+        return _.diag(SPV_ERROR_INVALID_ID, inst)
+               << _.VkErrorID(4651) << "OpVariable, <id> '"
+               << _.getIdName(inst->id())
+               << "', has a disallowed initializer & storage class "
+               << "combination.\n"
+               << "From " << spvLogStringForEnv(_.context()->target_env)
+               << " spec:\n"
+               << "Variable declarations that include initializers must have "
+               << "one of the following storage classes: Output, Private, "
+               << "Function or Workgroup";
+      }
     }
     }
   }
   }
 
 
@@ -630,9 +659,6 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
   }
   }
 
 
   // Vulkan specific validation rules for OpTypeRuntimeArray
   // Vulkan specific validation rules for OpTypeRuntimeArray
-  const auto type_index = 2;
-  const auto value_id = result_type->GetOperandAs<uint32_t>(type_index);
-  auto value_type = _.FindDef(value_id);
   if (spvIsVulkanEnv(_.context()->target_env)) {
   if (spvIsVulkanEnv(_.context()->target_env)) {
     // OpTypeRuntimeArray should only ever be in a container like OpTypeStruct,
     // OpTypeRuntimeArray should only ever be in a container like OpTypeStruct,
     // so should never appear as a bare variable.
     // so should never appear as a bare variable.
@@ -749,6 +775,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
             storage_class_ok = false;
             storage_class_ok = false;
           }
           }
           break;
           break;
+        case SpvStorageClassWorkgroup:
+          if (!_.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR)) {
+            storage_class_ok = false;
+          }
+          break;
         default:
         default:
           return _.diag(SPV_ERROR_INVALID_ID, inst)
           return _.diag(SPV_ERROR_INVALID_ID, inst)
                  << "Cannot allocate a variable containing a 16-bit type in "
                  << "Cannot allocate a variable containing a 16-bit type in "
@@ -800,6 +831,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
             storage_class_ok = false;
             storage_class_ok = false;
           }
           }
           break;
           break;
+        case SpvStorageClassWorkgroup:
+          if (!_.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR)) {
+            storage_class_ok = false;
+          }
+          break;
         default:
         default:
           return _.diag(SPV_ERROR_INVALID_ID, inst)
           return _.diag(SPV_ERROR_INVALID_ID, inst)
                  << "Cannot allocate a variable containing a 8-bit type in "
                  << "Cannot allocate a variable containing a 8-bit type in "

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

@@ -359,6 +359,7 @@ void ValidationState_t::RegisterCapability(SpvCapability cap) {
     case SpvCapabilityStorageBuffer8BitAccess:
     case SpvCapabilityStorageBuffer8BitAccess:
     case SpvCapabilityUniformAndStorageBuffer8BitAccess:
     case SpvCapabilityUniformAndStorageBuffer8BitAccess:
     case SpvCapabilityStoragePushConstant8:
     case SpvCapabilityStoragePushConstant8:
+    case SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR:
       features_.declare_int8_type = true;
       features_.declare_int8_type = true;
       break;
       break;
     case SpvCapabilityInt16:
     case SpvCapabilityInt16:
@@ -372,6 +373,7 @@ void ValidationState_t::RegisterCapability(SpvCapability cap) {
     case SpvCapabilityStorageUniform16:
     case SpvCapabilityStorageUniform16:
     case SpvCapabilityStoragePushConstant16:
     case SpvCapabilityStoragePushConstant16:
     case SpvCapabilityStorageInputOutput16:
     case SpvCapabilityStorageInputOutput16:
+    case SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR:
       features_.declare_int16_type = true;
       features_.declare_int16_type = true;
       features_.declare_float16_type = true;
       features_.declare_float16_type = true;
       features_.free_fp_rounding_mode = true;
       features_.free_fp_rounding_mode = true;
@@ -1692,24 +1694,36 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
       return VUID_WRAP(VUID-StandaloneSpirv-OriginLowerLeft-04653);
       return VUID_WRAP(VUID-StandaloneSpirv-OriginLowerLeft-04653);
     case 4654:
     case 4654:
       return VUID_WRAP(VUID-StandaloneSpirv-PixelCenterInteger-04654);
       return VUID_WRAP(VUID-StandaloneSpirv-PixelCenterInteger-04654);
+    case 4655:
+      return VUID_WRAP(VUID-StandaloneSpirv-UniformConstant-04655);
     case 4656:
     case 4656:
       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656);
       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656);
     case 4657:
     case 4657:
       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657);
       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657);
     case 4658:
     case 4658:
       return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658);
       return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658);
+    case 4659:
+      return VUID_WRAP(VUID-StandaloneSpirv-OpImageQuerySizeLod-04659);
     case 4662:
     case 4662:
       return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662);
       return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662);
+    case 4663:
+      return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663);
+    case 4664:
+      return VUID_WRAP(VUID-StandaloneSpirv-OpImageGather-04664);
     case 4669:
     case 4669:
       return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669);
       return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669);
     case 4675:
     case 4675:
       return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
       return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
+    case 4677:
+      return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677);
     case 4683:
     case 4683:
       return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683);
       return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683);
     case 4685:
     case 4685:
       return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
       return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
     case 4686:
     case 4686:
       return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
       return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
+    case 4710:
+      return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710);
     case 4711:
     case 4711:
       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711);
       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711);
     case 4730:
     case 4730:

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

@@ -103,6 +103,10 @@ class ValidationState_t {
     // Members need not be listed in offset order
     // Members need not be listed in offset order
     bool scalar_block_layout = false;
     bool scalar_block_layout = false;
 
 
+    // Use scalar block layout (as defined above) for Workgroup block
+    // variables.  See VK_KHR_workgroup_memory_explicit_layout.
+    bool workgroup_scalar_block_layout = false;
+
     // SPIR-V 1.4 allows us to select between any two composite values
     // SPIR-V 1.4 allows us to select between any two composite values
     // of the same type.
     // of the same type.
     bool select_between_composites = false;
     bool select_between_composites = false;