Browse Source

Updated spirv-tools.

Бранимир Караџић 7 years ago
parent
commit
16d7db088d
42 changed files with 2725 additions and 166 deletions
  1. 23 2
      3rdparty/spirv-tools/CHANGES
  2. 1 1
      3rdparty/spirv-tools/DEPS
  3. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  4. 2 2
      3rdparty/spirv-tools/include/spirv-tools/instrument.hpp
  5. 15 10
      3rdparty/spirv-tools/kokoro/scripts/windows/build.bat
  6. 3 0
      3rdparty/spirv-tools/source/operand.cpp
  7. 1 1
      3rdparty/spirv-tools/source/opt/constants.h
  8. 19 5
      3rdparty/spirv-tools/source/opt/fold.cpp
  9. 6 4
      3rdparty/spirv-tools/source/opt/instrument_pass.cpp
  10. 10 0
      3rdparty/spirv-tools/source/opt/ir_builder.h
  11. 2 2
      3rdparty/spirv-tools/source/opt/ir_context.cpp
  12. 65 10
      3rdparty/spirv-tools/source/opt/upgrade_memory_model.cpp
  13. 5 0
      3rdparty/spirv-tools/source/opt/upgrade_memory_model.h
  14. 58 1
      3rdparty/spirv-tools/source/val/validate.cpp
  15. 1 0
      3rdparty/spirv-tools/source/val/validate_atomics.cpp
  16. 9 1
      3rdparty/spirv-tools/source/val/validate_constants.cpp
  17. 34 0
      3rdparty/spirv-tools/source/val/validate_conversion.cpp
  18. 51 7
      3rdparty/spirv-tools/source/val/validate_decorations.cpp
  19. 73 0
      3rdparty/spirv-tools/source/val/validate_function.cpp
  20. 2 1
      3rdparty/spirv-tools/source/val/validate_logicals.cpp
  21. 151 26
      3rdparty/spirv-tools/source/val/validate_memory.cpp
  22. 28 0
      3rdparty/spirv-tools/source/val/validate_type.cpp
  23. 17 0
      3rdparty/spirv-tools/source/val/validation_state.cpp
  24. 24 5
      3rdparty/spirv-tools/source/val/validation_state.h
  25. 2 0
      3rdparty/spirv-tools/test/binary_parse_test.cpp
  26. 15 8
      3rdparty/spirv-tools/test/binary_to_text_test.cpp
  27. 2 1
      3rdparty/spirv-tools/test/ext_inst.glsl_test.cpp
  28. 1 6
      3rdparty/spirv-tools/test/opt/CMakeLists.txt
  29. 35 2
      3rdparty/spirv-tools/test/opt/fold_test.cpp
  30. 15 8
      3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp
  31. 5 5
      3rdparty/spirv-tools/test/opt/pass_fixture.h
  32. 330 49
      3rdparty/spirv-tools/test/opt/upgrade_memory_model_test.cpp
  33. 13 0
      3rdparty/spirv-tools/test/test_fixture.h
  34. 14 0
      3rdparty/spirv-tools/test/val/val_constants_test.cpp
  35. 112 0
      3rdparty/spirv-tools/test/val/val_conversion_test.cpp
  36. 169 0
      3rdparty/spirv-tools/test/val/val_data_test.cpp
  37. 497 5
      3rdparty/spirv-tools/test/val/val_decoration_test.cpp
  38. 19 3
      3rdparty/spirv-tools/test/val/val_fixtures.h
  39. 2 0
      3rdparty/spirv-tools/test/val/val_id_test.cpp
  40. 30 0
      3rdparty/spirv-tools/test/val/val_logicals_test.cpp
  41. 815 0
      3rdparty/spirv-tools/test/val/val_memory_test.cpp
  42. 48 0
      3rdparty/spirv-tools/test/val/val_validation_state_test.cpp

+ 23 - 2
3rdparty/spirv-tools/CHANGES

@@ -1,20 +1,39 @@
 Revision history for SPIRV-Tools
 Revision history for SPIRV-Tools
 
 
-v2018.7-dev 2018-12-10
+v2019.2-dev 2019-01-07
+ - Start v2019.2-dev
+
+v2019.1 2019-01-07
  - General:
  - General:
    - Created a new tool called spirv-reduce.
    - Created a new tool called spirv-reduce.
    - Add cmake option to turn off SPIRV_TIMER_ENABLED (#2103)
    - Add cmake option to turn off SPIRV_TIMER_ENABLED (#2103)
    - New optimization pass to update the memory model from GLSL450 to VulkanKHR.
    - New optimization pass to update the memory model from GLSL450 to VulkanKHR.
+   - Recognize OpTypeAccelerationStructureNV as a type instruction and ray tracing storage classes.
+   - Fix GCC8 build.
+   - Add --target-env flag to spirv-opt.
+   - Add --webgpu-mode flag to run optimizations for webgpu.
+   - The output disassembled line number stead of byte offset in validation errors. (#2091)
  - Optimizer
  - Optimizer
    - Added the instrumentation passes for bindless validation.
    - Added the instrumentation passes for bindless validation.
    - Added passes to help preserve OpLine information (#2027)
    - Added passes to help preserve OpLine information (#2027)
    - Add basic support for EXT_fragment_invocation_density (#2100)
    - Add basic support for EXT_fragment_invocation_density (#2100)
    - Fix invalid OpPhi generated by merge-return. (#2172)
    - Fix invalid OpPhi generated by merge-return. (#2172)
+   - Constant and type manager have been turned into analysies. (#2251)
    Fixes:
    Fixes:
    - #2018: Don't inline functions with a return in a structured CFG contstruct.
    - #2018: Don't inline functions with a return in a structured CFG contstruct.
    - #2047: Fix bug in folding when volatile stores are present.
    - #2047: Fix bug in folding when volatile stores are present.
    - #2053: Fix check for when folding floating pointer values is allowed.
    - #2053: Fix check for when folding floating pointer values is allowed.
    - #2130: Don't inline recursive functions.
    - #2130: Don't inline recursive functions.
+   - #2202: Handle multiple edges between two basic blocks in SSA-rewriter.
+   - #2205: Don't unswitch a latch condition during loop unswitch.
+   - #2245: Don't fold branch in loop unswitch.  Run dead branch elimination to fold them.
+   - #2204: Fix eliminate common uniform to place OpPhi instructions correctly.
+   - #2247: Fix type mismatches caused by scalar replacement.
+   - #2248: Fix missing OpPhi after merge return.
+   - #2211: After merge return, fix invalid continue target.
+   - #2210: Fix loop invariant code motion to not place code between merge instruction and branch.
+   - #2258: Handle CompositeInsert with no indices in VDCE.
+   - #2261: Have replace load size handle extact with no index.
  - Validator
  - Validator
    - Changed the naming convention of outputing ids with names in diagnostic messages.
    - Changed the naming convention of outputing ids with names in diagnostic messages.
    - Added validation rules for UniformConstant variables in Vulkan.
    - Added validation rules for UniformConstant variables in Vulkan.
@@ -32,12 +51,14 @@ v2018.7-dev 2018-12-10
    - Allow Float16/Int8 for Vulkan 1.0 (#2153)
    - Allow Float16/Int8 for Vulkan 1.0 (#2153)
    - Check binding annotations in resource variables (#2151, #2167)
    - Check binding annotations in resource variables (#2151, #2167)
    - Validate OpForwardPointer (#2156)
    - Validate OpForwardPointer (#2156)
+   - Validate operation for OpSpecConstantOp (#2260)
    Fixes:
    Fixes:
    - #2049: Allow InstanceId for NV ray tracing
    - #2049: Allow InstanceId for NV ray tracing
  - Reduce
  - Reduce
    - Initial commit wit a few passes to reduce test cases.
    - Initial commit wit a few passes to reduce test cases.
+   - Validation is run after each reduction step.
    Fixes:
    Fixes:
- 
+
 
 
 v2018.6 2018-11-07
 v2018.6 2018-11-07
  - General:
  - General:

+ 1 - 1
3rdparty/spirv-tools/DEPS

@@ -11,7 +11,7 @@ vars = {
   'googletest_revision': '98a0d007d7092b72eea0e501bb9ad17908a1a036',
   'googletest_revision': '98a0d007d7092b72eea0e501bb9ad17908a1a036',
   'testing_revision': '340252637e2e7c72c0901dcbeeacfff419e19b59',
   'testing_revision': '340252637e2e7c72c0901dcbeeacfff419e19b59',
   're2_revision': '6cf8ccd82dbaab2668e9b13596c68183c9ecd13f',
   're2_revision': '6cf8ccd82dbaab2668e9b13596c68183c9ecd13f',
-  'spirv_headers_revision': 'd5b2e1255f706ce1f88812217e9a554f299848af',
+  'spirv_headers_revision': '79b6681aadcb53c27d1052e5f8a0e82a981dbf2f',
 }
 }
 
 
 deps = {
 deps = {

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

@@ -1 +1 @@
-"v2018.7-dev", "SPIRV-Tools v2018.7-dev bc65303576278bfb67295395327dc395a6adbf98"
+"v2019.2-dev", "SPIRV-Tools v2019.2-dev 3c8b3c81ef7f378717ef88916c06cb221eea890b"

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

@@ -75,8 +75,8 @@ static const int kInstCommonOutCnt = 4;
 // error.
 // error.
 //
 //
 // Vertex Shader Output Record Offsets
 // Vertex Shader Output Record Offsets
-static const int kInstVertOutVertexId = kInstCommonOutCnt;
-static const int kInstVertOutInstanceId = kInstCommonOutCnt + 1;
+static const int kInstVertOutVertexIndex = kInstCommonOutCnt;
+static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1;
 
 
 // Frag Shader Output Record Offsets
 // Frag Shader Output Record Offsets
 static const int kInstFragOutFragCoordX = kInstCommonOutCnt;
 static const int kInstFragOutFragCoordX = kInstCommonOutCnt;

+ 15 - 10
3rdparty/spirv-tools/kokoro/scripts/windows/build.bat

@@ -58,33 +58,38 @@ if "%KOKORO_GITHUB_COMMIT%." == "." (
   set BUILD_SHA=%KOKORO_GITHUB_COMMIT%
   set BUILD_SHA=%KOKORO_GITHUB_COMMIT%
 )
 )
 
 
+set CMAKE_FLAGS=-GNinja -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe
+
 :: Skip building tests for VS2013
 :: Skip building tests for VS2013
 if %VS_VERSION% == 2013 (
 if %VS_VERSION% == 2013 (
-  cmake -GNinja -DSPIRV_SKIP_TESTS=ON -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe ..
-) else (
-  cmake -GNinja -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe ..
+  set CMAKE_FLAGS=%CMAKE_FLAGS% -DSPIRV_SKIP_TESTS=ON
 )
 )
 
 
-if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL%
+cmake %CMAKE_FLAGS% ..
+
+if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
 
 
 echo "Build everything... %DATE% %TIME%"
 echo "Build everything... %DATE% %TIME%"
 ninja
 ninja
-if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL%
+if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
 echo "Build Completed %DATE% %TIME%"
 echo "Build Completed %DATE% %TIME%"
 
 
+:: This lets us use !ERRORLEVEL! inside an IF ... () and get the actual error at that point.
+setlocal ENABLEDELAYEDEXPANSION
+
 :: ################################################
 :: ################################################
 :: Run the tests (We no longer run tests on VS2013)
 :: Run the tests (We no longer run tests on VS2013)
 :: ################################################
 :: ################################################
-if NOT %VS_VERSION% == 2013 (
-  echo "Running Tests... %DATE% %TIME%"
+echo "Running Tests... %DATE% %TIME%"
+if %VS_VERSION% NEQ 2013 (
   ctest -C %BUILD_TYPE% --output-on-failure --timeout 300
   ctest -C %BUILD_TYPE% --output-on-failure --timeout 300
-  if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL%
-  echo "Tests Completed %DATE% %TIME%"
+  if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL!
 )
 )
+echo "Tests Completed %DATE% %TIME%"
 
 
 :: Clean up some directories.
 :: Clean up some directories.
 rm -rf %SRC%\build
 rm -rf %SRC%\build
 rm -rf %SRC%\external
 rm -rf %SRC%\external
 
 
-exit /b %ERRORLEVEL%
+exit /b 0
 
 

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

@@ -481,6 +481,9 @@ std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
     case SpvOpTypeForwardPointer:
     case SpvOpTypeForwardPointer:
       out = [](unsigned index) { return index == 0; };
       out = [](unsigned index) { return index == 0; };
       break;
       break;
+    case SpvOpTypeArray:
+      out = [](unsigned index) { return index == 1; };
+      break;
     default:
     default:
       out = [](unsigned) { return false; };
       out = [](unsigned) { return false; };
       break;
       break;

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

@@ -15,7 +15,7 @@
 #ifndef SOURCE_OPT_CONSTANTS_H_
 #ifndef SOURCE_OPT_CONSTANTS_H_
 #define SOURCE_OPT_CONSTANTS_H_
 #define SOURCE_OPT_CONSTANTS_H_
 
 
-#include <inttypes.h>
+#include <cinttypes>
 #include <map>
 #include <map>
 #include <memory>
 #include <memory>
 #include <unordered_map>
 #include <unordered_map>

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

@@ -115,8 +115,10 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
 
 
     // Shifting
     // Shifting
     case SpvOp::SpvOpShiftRightLogical:
     case SpvOp::SpvOpShiftRightLogical:
-      if (b > 32) {
-        // This is undefined behaviour.  Choose 0 for consistency.
+      if (b >= 32) {
+        // This is undefined behaviour when |b| > 32.  Choose 0 for consistency.
+        // When |b| == 32, doing the shift in C++ in undefined, but the result
+        // will be 0, so just return that value.
         return 0;
         return 0;
       }
       }
       return a >> b;
       return a >> b;
@@ -125,10 +127,21 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
         // This is undefined behaviour.  Choose 0 for consistency.
         // This is undefined behaviour.  Choose 0 for consistency.
         return 0;
         return 0;
       }
       }
+      if (b == 32) {
+        // Doing the shift in C++ is undefined, but the result is defined in the
+        // spir-v spec.  Find that value another way.
+        if (static_cast<int32_t>(a) >= 0) {
+          return 0;
+        } else {
+          return static_cast<uint32_t>(-1);
+        }
+      }
       return (static_cast<int32_t>(a)) >> b;
       return (static_cast<int32_t>(a)) >> b;
     case SpvOp::SpvOpShiftLeftLogical:
     case SpvOp::SpvOpShiftLeftLogical:
-      if (b > 32) {
-        // This is undefined behaviour.  Choose 0 for consistency.
+      if (b >= 32) {
+        // This is undefined behaviour when |b| > 32.  Choose 0 for consistency.
+        // When |b| == 32, doing the shift in C++ in undefined, but the result
+        // will be 0, so just return that value.
         return 0;
         return 0;
       }
       }
       return a << b;
       return a << b;
@@ -307,7 +320,8 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
       if (constants[1] != nullptr) {
       if (constants[1] != nullptr) {
         // When shifting by a value larger than the size of the result, the
         // When shifting by a value larger than the size of the result, the
         // result is undefined.  We are setting the undefined behaviour to a
         // result is undefined.  We are setting the undefined behaviour to a
-        // result of 0.
+        // result of 0.  If the shift amount is the same as the size of the
+        // result, then the result is defined, and it 0.
         uint32_t shift_amount = constants[1]->GetU32BitValue();
         uint32_t shift_amount = constants[1]->GetU32BitValue();
         if (shift_amount >= 32) {
         if (shift_amount >= 32) {
           *result = 0;
           *result = 0;

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

@@ -168,10 +168,10 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
   switch (stage_idx) {
   switch (stage_idx) {
     case SpvExecutionModelVertex: {
     case SpvExecutionModelVertex: {
       // Load and store VertexId and InstanceId
       // Load and store VertexId and InstanceId
-      GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInVertexId),
-                           kInstVertOutVertexId, base_offset_id, builder);
-      GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInstanceId),
-                           kInstVertOutInstanceId, base_offset_id, builder);
+      GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInVertexIndex),
+                           kInstVertOutVertexIndex, base_offset_id, builder);
+      GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInstanceIndex),
+                           kInstVertOutInstanceIndex, base_offset_id, builder);
     } break;
     } break;
     case SpvExecutionModelGLCompute: {
     case SpvExecutionModelGLCompute: {
       // Load and store GlobalInvocationId. Second word is unused; store zero.
       // Load and store GlobalInvocationId. Second word is unused; store zero.
@@ -309,6 +309,8 @@ uint32_t InstrumentPass::GetOutputBufferId() {
     analysis::RuntimeArray uint_rarr_ty(reg_uint_ty);
     analysis::RuntimeArray uint_rarr_ty(reg_uint_ty);
     analysis::Type* reg_uint_rarr_ty =
     analysis::Type* reg_uint_rarr_ty =
         type_mgr->GetRegisteredType(&uint_rarr_ty);
         type_mgr->GetRegisteredType(&uint_rarr_ty);
+    uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(reg_uint_rarr_ty);
+    deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride, 4u);
     analysis::Struct obuf_ty({reg_uint_ty, reg_uint_rarr_ty});
     analysis::Struct obuf_ty({reg_uint_ty, reg_uint_rarr_ty});
     analysis::Type* reg_obuf_ty = type_mgr->GetRegisteredType(&obuf_ty);
     analysis::Type* reg_obuf_ty = type_mgr->GetRegisteredType(&obuf_ty);
     uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_obuf_ty);
     uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_obuf_ty);

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

@@ -455,6 +455,16 @@ class InstructionBuilder {
     return AddInstruction(std::move(new_inst));
     return AddInstruction(std::move(new_inst));
   }
   }
 
 
+  Instruction* AddStore(uint32_t ptr_id, uint32_t obj_id) {
+    std::vector<Operand> operands;
+    operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}});
+    operands.push_back({SPV_OPERAND_TYPE_ID, {obj_id}});
+
+    std::unique_ptr<Instruction> new_inst(
+        new Instruction(GetContext(), SpvOpStore, 0, 0, operands));
+    return AddInstruction(std::move(new_inst));
+  }
+
   // Inserts the new instruction before the insertion point.
   // Inserts the new instruction before the insertion point.
   Instruction* AddInstruction(std::unique_ptr<Instruction>&& insn) {
   Instruction* AddInstruction(std::unique_ptr<Instruction>&& insn) {
     Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));
     Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));

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

@@ -669,8 +669,8 @@ uint32_t IRContext::GetBuiltinVarId(uint32_t builtin) {
         reg_type = type_mgr->GetRegisteredType(&v4float_ty);
         reg_type = type_mgr->GetRegisteredType(&v4float_ty);
         break;
         break;
       }
       }
-      case SpvBuiltInVertexId:
-      case SpvBuiltInInstanceId:
+      case SpvBuiltInVertexIndex:
+      case SpvBuiltInInstanceIndex:
       case SpvBuiltInPrimitiveId:
       case SpvBuiltInPrimitiveId:
       case SpvBuiltInInvocationId:
       case SpvBuiltInInvocationId:
       case SpvBuiltInGlobalInvocationId: {
       case SpvBuiltInGlobalInvocationId: {

+ 65 - 10
3rdparty/spirv-tools/source/opt/upgrade_memory_model.cpp

@@ -16,6 +16,7 @@
 
 
 #include <utility>
 #include <utility>
 
 
+#include "source/opt/ir_builder.h"
 #include "source/opt/ir_context.h"
 #include "source/opt/ir_context.h"
 #include "source/util/make_unique.h"
 #include "source/util/make_unique.h"
 
 
@@ -68,6 +69,22 @@ void UpgradeMemoryModel::UpgradeInstructions() {
   // instructions. Additionally, Workgroup storage class variables and function
   // instructions. Additionally, Workgroup storage class variables and function
   // parameters are implicitly coherent in GLSL450.
   // parameters are implicitly coherent in GLSL450.
 
 
+  // Upgrade modf and frexp first since they generate new stores.
+  for (auto& func : *get_module()) {
+    func.ForEachInst([this](Instruction* inst) {
+      if (inst->opcode() == SpvOpExtInst) {
+        auto ext_inst = inst->GetSingleWordInOperand(1u);
+        if (ext_inst == GLSLstd450Modf || ext_inst == GLSLstd450Frexp) {
+          auto import =
+              get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u));
+          if (reinterpret_cast<char*>(import->GetInOperand(0u).words.data()) ==
+              std::string("GLSL.std.450")) {
+            UpgradeExtInst(inst);
+          }
+        }
+      }
+    });
+  }
   for (auto& func : *get_module()) {
   for (auto& func : *get_module()) {
     func.ForEachInst([this](Instruction* inst) {
     func.ForEachInst([this](Instruction* inst) {
       bool is_coherent = false;
       bool is_coherent = false;
@@ -104,11 +121,11 @@ void UpgradeMemoryModel::UpgradeInstructions() {
 
 
       switch (inst->opcode()) {
       switch (inst->opcode()) {
         case SpvOpLoad:
         case SpvOpLoad:
-          UpgradeFlags(inst, 1u, is_coherent, is_volatile, kAvailability,
+          UpgradeFlags(inst, 1u, is_coherent, is_volatile, kVisibility,
                        kMemory);
                        kMemory);
           break;
           break;
         case SpvOpStore:
         case SpvOpStore:
-          UpgradeFlags(inst, 2u, is_coherent, is_volatile, kVisibility,
+          UpgradeFlags(inst, 2u, is_coherent, is_volatile, kAvailability,
                        kMemory);
                        kMemory);
           break;
           break;
         case SpvOpCopyMemory:
         case SpvOpCopyMemory:
@@ -125,11 +142,11 @@ void UpgradeMemoryModel::UpgradeInstructions() {
           break;
           break;
         case SpvOpImageRead:
         case SpvOpImageRead:
         case SpvOpImageSparseRead:
         case SpvOpImageSparseRead:
-          UpgradeFlags(inst, 2u, is_coherent, is_volatile, kAvailability,
-                       kImage);
+          UpgradeFlags(inst, 2u, is_coherent, is_volatile, kVisibility, kImage);
           break;
           break;
         case SpvOpImageWrite:
         case SpvOpImageWrite:
-          UpgradeFlags(inst, 3u, is_coherent, is_volatile, kVisibility, kImage);
+          UpgradeFlags(inst, 3u, is_coherent, is_volatile, kAvailability,
+                       kImage);
           break;
           break;
         default:
         default:
           break;
           break;
@@ -143,15 +160,15 @@ void UpgradeMemoryModel::UpgradeInstructions() {
       }
       }
       // According to SPV_KHR_vulkan_memory_model, if both available and
       // According to SPV_KHR_vulkan_memory_model, if both available and
       // visible flags are used the first scope operand is for availability
       // visible flags are used the first scope operand is for availability
-      // (reads) and the second is for visibiity (writes).
-      if (src_coherent) {
-        inst->AddOperand(
-            {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(src_scope)}});
-      }
+      // (writes) and the second is for visibility (reads).
       if (dst_coherent) {
       if (dst_coherent) {
         inst->AddOperand(
         inst->AddOperand(
             {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(dst_scope)}});
             {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(dst_scope)}});
       }
       }
+      if (src_coherent) {
+        inst->AddOperand(
+            {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(src_scope)}});
+      }
     });
     });
   }
   }
 }
 }
@@ -581,5 +598,43 @@ bool UpgradeMemoryModel::IsDeviceScope(uint32_t scope_id) {
   return false;
   return false;
 }
 }
 
 
+void UpgradeMemoryModel::UpgradeExtInst(Instruction* ext_inst) {
+  const bool is_modf = ext_inst->GetSingleWordInOperand(1u) == GLSLstd450Modf;
+  auto ptr_id = ext_inst->GetSingleWordInOperand(3u);
+  auto ptr_type_id = get_def_use_mgr()->GetDef(ptr_id)->type_id();
+  auto pointee_type_id =
+      get_def_use_mgr()->GetDef(ptr_type_id)->GetSingleWordInOperand(1u);
+  auto element_type_id = ext_inst->type_id();
+  std::vector<const analysis::Type*> element_types(2);
+  element_types[0] = context()->get_type_mgr()->GetType(element_type_id);
+  element_types[1] = context()->get_type_mgr()->GetType(pointee_type_id);
+  analysis::Struct struct_type(element_types);
+  uint32_t struct_id =
+      context()->get_type_mgr()->GetTypeInstruction(&struct_type);
+  // Change the operation
+  GLSLstd450 new_op = is_modf ? GLSLstd450ModfStruct : GLSLstd450FrexpStruct;
+  ext_inst->SetOperand(3u, {static_cast<uint32_t>(new_op)});
+  // Remove the pointer argument
+  ext_inst->RemoveOperand(5u);
+  // Set the type id to the new struct.
+  ext_inst->SetResultType(struct_id);
+
+  // The result is now a struct of the original result. The zero'th element is
+  // old result and should replace the old result. The one'th element needs to
+  // be stored via a new instruction.
+  auto where = ext_inst->NextNode();
+  InstructionBuilder builder(
+      context(), where,
+      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+  auto extract_0 =
+      builder.AddCompositeExtract(element_type_id, ext_inst->result_id(), {0});
+  context()->ReplaceAllUsesWith(ext_inst->result_id(), extract_0->result_id());
+  // The extract's input was just changed to itself, so fix that.
+  extract_0->SetInOperand(0u, {ext_inst->result_id()});
+  auto extract_1 =
+      builder.AddCompositeExtract(pointee_type_id, ext_inst->result_id(), {1});
+  builder.AddStore(ptr_id, extract_1->result_id());
+}
+
 }  // namespace opt
 }  // namespace opt
 }  // namespace spvtools
 }  // namespace spvtools

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

@@ -118,6 +118,11 @@ class UpgradeMemoryModel : public Pass {
   // Returns true if |scope_id| is SpvScopeDevice.
   // Returns true if |scope_id| is SpvScopeDevice.
   bool IsDeviceScope(uint32_t scope_id);
   bool IsDeviceScope(uint32_t scope_id);
 
 
+  // Upgrades GLSL.std.450 modf and frexp. Both instructions are replaced with
+  // their struct versions. New extracts and a store are added in order to
+  // facilitate adding memory model flags.
+  void UpgradeExtInst(Instruction* modf);
+
   // Caches the result of TraceInstruction. For a given result id and set of
   // Caches the result of TraceInstruction. For a given result id and set of
   // indices, stores whether that combination is coherent and/or volatile.
   // indices, stores whether that combination is coherent and/or volatile.
   std::unordered_map<std::pair<uint32_t, std::vector<uint32_t>>,
   std::unordered_map<std::pair<uint32_t, std::vector<uint32_t>>,

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

@@ -169,6 +169,57 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) {
          << id_str.substr(0, id_str.size() - 1);
          << id_str.substr(0, id_str.size() - 1);
 }
 }
 
 
+std::vector<std::string> CalculateNamesForEntryPoint(ValidationState_t& _,
+                                                     const uint32_t id) {
+  auto id_descriptions = _.entry_point_descriptions(id);
+  auto id_names = std::vector<std::string>();
+  id_names.reserve((id_descriptions.size()));
+
+  for (auto description : id_descriptions) id_names.push_back(description.name);
+
+  return id_names;
+}
+
+spv_result_t ValidateEntryPointNameUnique(ValidationState_t& _,
+                                          const uint32_t id) {
+  auto id_names = CalculateNamesForEntryPoint(_, id);
+  const auto names =
+      std::unordered_set<std::string>(id_names.begin(), id_names.end());
+
+  if (id_names.size() != names.size()) {
+    std::sort(id_names.begin(), id_names.end());
+    for (size_t i = 0; i < id_names.size() - 1; i++) {
+      if (id_names[i] == id_names[i + 1]) {
+        return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id))
+               << "Entry point name \"" << id_names[i]
+               << "\" is not unique, which is not allow in WebGPU env.";
+      }
+    }
+  }
+
+  for (const auto other_id : _.entry_points()) {
+    if (other_id == id) continue;
+    const auto other_id_names = CalculateNamesForEntryPoint(_, other_id);
+    for (const auto other_id_name : other_id_names) {
+      if (names.find(other_id_name) != names.end()) {
+        return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id))
+               << "Entry point name \"" << other_id_name
+               << "\" is not unique, which is not allow in WebGPU env.";
+      }
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateEntryPointNamesUnique(ValidationState_t& _) {
+  for (const auto id : _.entry_points()) {
+    auto result = ValidateEntryPointNameUnique(_, id);
+    if (result != SPV_SUCCESS) return result;
+  }
+  return SPV_SUCCESS;
+}
+
 // Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the
 // Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the
 // SPIRV spec:
 // SPIRV spec:
 // * There is at least one OpEntryPoint instruction, unless the Linkage
 // * There is at least one OpEntryPoint instruction, unless the Linkage
@@ -177,7 +228,7 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) {
 //   OpFunctionCall instruction.
 //   OpFunctionCall instruction.
 //
 //
 // Additionally enforces that entry points for Vulkan and WebGPU should not have
 // Additionally enforces that entry points for Vulkan and WebGPU should not have
-// recursion.
+// recursion. And that entry names should be unique for WebGPU.
 spv_result_t ValidateEntryPoints(ValidationState_t& _) {
 spv_result_t ValidateEntryPoints(ValidationState_t& _) {
   _.ComputeFunctionToEntryPointMapping();
   _.ComputeFunctionToEntryPointMapping();
   _.ComputeRecursiveEntryPoints();
   _.ComputeRecursiveEntryPoints();
@@ -206,6 +257,12 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) {
                << "Entry points may not have a call graph with cycles.";
                << "Entry points may not have a call graph with cycles.";
       }
       }
     }
     }
+
+    // For WebGPU all entry point names must be unique.
+    if (spvIsWebGPUEnv(_.context()->target_env)) {
+      const auto result = ValidateEntryPointNamesUnique(_);
+      if (result != SPV_SUCCESS) return result;
+    }
   }
   }
 
 
   return SPV_SUCCESS;
   return SPV_SUCCESS;

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

@@ -127,6 +127,7 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) {
         case SpvStorageClassAtomicCounter:
         case SpvStorageClassAtomicCounter:
         case SpvStorageClassImage:
         case SpvStorageClassImage:
         case SpvStorageClassStorageBuffer:
         case SpvStorageClassStorageBuffer:
+        case SpvStorageClassPhysicalStorageBufferEXT:
           break;
           break;
         default:
         default:
           if (spvIsOpenCLEnv(_.context()->target_env)) {
           if (spvIsOpenCLEnv(_.context()->target_env)) {

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

@@ -329,11 +329,19 @@ spv_result_t ValidateSpecConstantOp(ValidationState_t& _,
       }
       }
       break;
       break;
 
 
+    case SpvOpUConvert:
+      if (!_.features().uconvert_spec_constant_op &&
+          !_.HasCapability(SpvCapabilityKernel)) {
+        return _.diag(SPV_ERROR_INVALID_ID, inst)
+               << "UConvert requires Kernel capability or extension "
+                  "SPV_AMD_gpu_shader_int16";
+      }
+      break;
+
     case SpvOpConvertFToS:
     case SpvOpConvertFToS:
     case SpvOpConvertSToF:
     case SpvOpConvertSToF:
     case SpvOpConvertFToU:
     case SpvOpConvertFToU:
     case SpvOpConvertUToF:
     case SpvOpConvertUToF:
-    case SpvOpUConvert:
     case SpvOpConvertPtrToU:
     case SpvOpConvertPtrToU:
     case SpvOpConvertUToPtr:
     case SpvOpConvertUToPtr:
     case SpvOpGenericCastToPtr:
     case SpvOpGenericCastToPtr:

+ 34 - 0
3rdparty/spirv-tools/source/val/validate_conversion.cpp

@@ -217,6 +217,23 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
       if (!_.IsPointerType(input_type))
       if (!_.IsPointerType(input_type))
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
+
+      if (_.addressing_model() == SpvAddressingModelLogical)
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Logical addressing not supported: "
+               << spvOpcodeString(opcode);
+
+      if (_.addressing_model() ==
+          SpvAddressingModelPhysicalStorageBuffer64EXT) {
+        uint32_t input_storage_class = 0;
+        uint32_t input_data_type = 0;
+        _.GetPointerTypeInfo(input_type, &input_data_type,
+                             &input_storage_class);
+        if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
+          return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                 << "Pointer storage class must be PhysicalStorageBufferEXT: "
+                 << spvOpcodeString(opcode);
+      }
       break;
       break;
     }
     }
 
 
@@ -251,6 +268,23 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
       if (!input_type || !_.IsIntScalarType(input_type))
       if (!input_type || !_.IsIntScalarType(input_type))
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected int scalar as input: " << spvOpcodeString(opcode);
                << "Expected int scalar as input: " << spvOpcodeString(opcode);
+
+      if (_.addressing_model() == SpvAddressingModelLogical)
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Logical addressing not supported: "
+               << spvOpcodeString(opcode);
+
+      if (_.addressing_model() ==
+          SpvAddressingModelPhysicalStorageBuffer64EXT) {
+        uint32_t result_storage_class = 0;
+        uint32_t result_data_type = 0;
+        _.GetPointerTypeInfo(result_type, &result_data_type,
+                             &result_storage_class);
+        if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
+          return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                 << "Pointer storage class must be PhysicalStorageBufferEXT: "
+                 << spvOpcodeString(opcode);
+      }
       break;
       break;
     }
     }
 
 

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

@@ -218,6 +218,9 @@ uint32_t getBaseAlignment(uint32_t member_id, bool roundUp,
       if (roundUp) baseAlignment = align(baseAlignment, 16u);
       if (roundUp) baseAlignment = align(baseAlignment, 16u);
       break;
       break;
     }
     }
+    case SpvOpTypePointer:
+      baseAlignment = vstate.pointer_size_and_alignment();
+      break;
     default:
     default:
       assert(0);
       assert(0);
       break;
       break;
@@ -254,6 +257,8 @@ uint32_t getScalarAlignment(uint32_t type_id, ValidationState_t& vstate) {
       }
       }
       return max_member_alignment;
       return max_member_alignment;
     } break;
     } break;
+    case SpvOpTypePointer:
+      return vstate.pointer_size_and_alignment();
     default:
     default:
       assert(0);
       assert(0);
       break;
       break;
@@ -331,6 +336,8 @@ uint32_t getSize(uint32_t member_id, const LayoutConstraints& inherited,
       const auto& constraint = constraints[std::make_pair(lastMember, lastIdx)];
       const auto& constraint = constraints[std::make_pair(lastMember, lastIdx)];
       return offset + getSize(lastMember, constraint, constraints, vstate);
       return offset + getSize(lastMember, constraint, constraints, vstate);
     }
     }
+    case SpvOpTypePointer:
+      return vstate.pointer_size_and_alignment();
     default:
     default:
       assert(0);
       assert(0);
       return 0;
       return 0;
@@ -847,7 +854,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
         }
         }
       }
       }
 
 
-      if (uniform || push_constant || storage_buffer) {
+      const bool phys_storage_buffer =
+          storageClass == SpvStorageClassPhysicalStorageBufferEXT;
+      if (uniform || push_constant || storage_buffer || phys_storage_buffer) {
         const auto ptrInst = vstate.FindDef(words[1]);
         const auto ptrInst = vstate.FindDef(words[1]);
         assert(SpvOpTypePointer == ptrInst->opcode());
         assert(SpvOpTypePointer == ptrInst->opcode());
         const auto id = ptrInst->words()[3];
         const auto id = ptrInst->words()[3];
@@ -899,9 +908,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
           const bool blockDeco = SpvDecorationBlock == dec.dec_type();
           const bool blockDeco = SpvDecorationBlock == dec.dec_type();
           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 = (uniform && bufferDeco) ||
-                                   (push_constant && blockDeco) ||
-                                   (storage_buffer && blockDeco);
+          const bool bufferRules =
+              (uniform && bufferDeco) || (push_constant && blockDeco) ||
+              ((storage_buffer || phys_storage_buffer) && blockDeco);
           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;
@@ -1127,12 +1136,13 @@ spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate,
     if (storage != SpvStorageClassStorageBuffer &&
     if (storage != SpvStorageClassStorageBuffer &&
         storage != SpvStorageClassUniform &&
         storage != SpvStorageClassUniform &&
         storage != SpvStorageClassPushConstant &&
         storage != SpvStorageClassPushConstant &&
-        storage != SpvStorageClassInput && storage != SpvStorageClassOutput) {
+        storage != SpvStorageClassInput && storage != SpvStorageClassOutput &&
+        storage != SpvStorageClassPhysicalStorageBufferEXT) {
       return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
       return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
              << "FPRoundingMode decoration can be applied only to the "
              << "FPRoundingMode decoration can be applied only to the "
                 "Object operand of an OpStore in the StorageBuffer, "
                 "Object operand of an OpStore in the StorageBuffer, "
-                "Uniform, PushConstant, Input, or Output Storage "
-                "Classes.";
+                "PhysicalStorageBufferEXT, Uniform, PushConstant, Input, or "
+                "Output Storage Classes.";
     }
     }
   }
   }
   return SPV_SUCCESS;
   return SPV_SUCCESS;
@@ -1170,6 +1180,36 @@ spv_result_t CheckUniformDecoration(ValidationState_t& vstate,
   return SPV_SUCCESS;
   return SPV_SUCCESS;
 }
 }
 
 
+// Returns SPV_SUCCESS if validation rules are satisfied for NoSignedWrap or
+// NoUnsignedWrap decorations. Otherwise emits a diagnostic and returns
+// something other than SPV_SUCCESS. Assumes each decoration on a group has been
+// propagated down to the group members.
+spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate,
+                                        const Instruction& inst,
+                                        const Decoration& decoration) {
+  switch (inst.opcode()) {
+    case SpvOpIAdd:
+    case SpvOpISub:
+    case SpvOpIMul:
+    case SpvOpShiftLeftLogical:
+    case SpvOpSNegate:
+      return SPV_SUCCESS;
+    case SpvOpExtInst:
+      // TODO(dneto): Only certain extended instructions allow these
+      // decorations.  For now allow anything.
+      return SPV_SUCCESS;
+    default:
+      break;
+  }
+
+  return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
+         << (decoration.dec_type() == SpvDecorationNoSignedWrap
+                 ? "NoSignedWrap"
+                 : "NoUnsignedWrap")
+         << " decoration may not be applied to "
+         << spvOpcodeString(inst.opcode());
+}
+
 #define PASS_OR_BAIL_AT_LINE(X, LINE)           \
 #define PASS_OR_BAIL_AT_LINE(X, LINE)           \
   {                                             \
   {                                             \
     spv_result_t e##LINE = (X);                 \
     spv_result_t e##LINE = (X);                 \
@@ -1206,6 +1246,10 @@ spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) {
         case SpvDecorationUniform:
         case SpvDecorationUniform:
           PASS_OR_BAIL(CheckUniformDecoration(vstate, *inst, decoration));
           PASS_OR_BAIL(CheckUniformDecoration(vstate, *inst, decoration));
           break;
           break;
+        case SpvDecorationNoSignedWrap:
+        case SpvDecorationNoUnsignedWrap:
+          PASS_OR_BAIL(CheckIntegerWrapDecoration(vstate, *inst, decoration));
+          break;
         default:
         default:
           break;
           break;
       }
       }

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

@@ -111,6 +111,79 @@ spv_result_t ValidateFunctionParameter(ValidationState_t& _,
            << "' does not match the OpTypeFunction parameter "
            << "' does not match the OpTypeFunction parameter "
               "type of the same index.";
               "type of the same index.";
   }
   }
+
+  // Validate that PhysicalStorageBufferEXT have one of Restrict, Aliased,
+  // RestrictPointerEXT, or AliasedPointerEXT.
+  auto param_nonarray_type_id = param_type->id();
+  while (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypeArray) {
+    param_nonarray_type_id =
+        _.FindDef(param_nonarray_type_id)->GetOperandAs<uint32_t>(1u);
+  }
+  if (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypePointer) {
+    auto param_nonarray_type = _.FindDef(param_nonarray_type_id);
+    if (param_nonarray_type->GetOperandAs<uint32_t>(1u) ==
+        SpvStorageClassPhysicalStorageBufferEXT) {
+      // check for Aliased or Restrict
+      const auto& decorations = _.id_decorations(inst->id());
+
+      bool foundAliased = std::any_of(
+          decorations.begin(), decorations.end(), [](const Decoration& d) {
+            return SpvDecorationAliased == d.dec_type();
+          });
+
+      bool foundRestrict = std::any_of(
+          decorations.begin(), decorations.end(), [](const Decoration& d) {
+            return SpvDecorationRestrict == d.dec_type();
+          });
+
+      if (!foundAliased && !foundRestrict) {
+        return _.diag(SPV_ERROR_INVALID_ID, inst)
+               << "OpFunctionParameter " << inst->id()
+               << ": expected Aliased or Restrict for PhysicalStorageBufferEXT "
+                  "pointer.";
+      }
+      if (foundAliased && foundRestrict) {
+        return _.diag(SPV_ERROR_INVALID_ID, inst)
+               << "OpFunctionParameter " << inst->id()
+               << ": can't specify both Aliased and Restrict for "
+                  "PhysicalStorageBufferEXT pointer.";
+      }
+    } else {
+      const auto pointee_type_id =
+          param_nonarray_type->GetOperandAs<uint32_t>(2);
+      const auto pointee_type = _.FindDef(pointee_type_id);
+      if (SpvOpTypePointer == pointee_type->opcode() &&
+          pointee_type->GetOperandAs<uint32_t>(1u) ==
+              SpvStorageClassPhysicalStorageBufferEXT) {
+        // check for AliasedPointerEXT/RestrictPointerEXT
+        const auto& decorations = _.id_decorations(inst->id());
+
+        bool foundAliased = std::any_of(
+            decorations.begin(), decorations.end(), [](const Decoration& d) {
+              return SpvDecorationAliasedPointerEXT == d.dec_type();
+            });
+
+        bool foundRestrict = std::any_of(
+            decorations.begin(), decorations.end(), [](const Decoration& d) {
+              return SpvDecorationRestrictPointerEXT == d.dec_type();
+            });
+
+        if (!foundAliased && !foundRestrict) {
+          return _.diag(SPV_ERROR_INVALID_ID, inst)
+                 << "OpFunctionParameter " << inst->id()
+                 << ": expected AliasedPointerEXT or RestrictPointerEXT for "
+                    "PhysicalStorageBufferEXT pointer.";
+        }
+        if (foundAliased && foundRestrict) {
+          return _.diag(SPV_ERROR_INVALID_ID, inst)
+                 << "OpFunctionParameter " << inst->id()
+                 << ": can't specify both AliasedPointerEXT and "
+                    "RestrictPointerEXT for PhysicalStorageBufferEXT pointer.";
+        }
+      }
+    }
+  }
+
   return SPV_SUCCESS;
   return SPV_SUCCESS;
 }
 }
 
 

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

@@ -154,7 +154,8 @@ spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) {
         const SpvOp type_opcode = type_inst->opcode();
         const SpvOp type_opcode = type_inst->opcode();
         switch (type_opcode) {
         switch (type_opcode) {
           case SpvOpTypePointer: {
           case SpvOpTypePointer: {
-            if (!_.features().variable_pointers &&
+            if (_.addressing_model() == SpvAddressingModelLogical &&
+                !_.features().variable_pointers &&
                 !_.features().variable_pointers_storage_buffer)
                 !_.features().variable_pointers_storage_buffer)
               return _.diag(SPV_ERROR_INVALID_DATA, inst)
               return _.diag(SPV_ERROR_INVALID_DATA, inst)
                      << "Using pointers with OpSelect requires capability "
                      << "Using pointers with OpSelect requires capability "

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

@@ -277,7 +277,20 @@ uint32_t GetMakeVisibleScope(const Instruction* inst, uint32_t mask) {
 }
 }
 
 
 spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
 spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
-                               uint32_t mask) {
+                               uint32_t index) {
+  SpvStorageClass dst_sc, src_sc;
+  std::tie(dst_sc, src_sc) = GetStorageClass(_, inst);
+  if (inst->operands().size() <= index) {
+    if (src_sc == SpvStorageClassPhysicalStorageBufferEXT ||
+        dst_sc == SpvStorageClassPhysicalStorageBufferEXT) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst) << "Memory accesses with "
+                                                   "PhysicalStorageBufferEXT "
+                                                   "must use Aligned.";
+    }
+    return SPV_SUCCESS;
+  }
+
+  uint32_t mask = inst->GetOperandAs<uint32_t>(index);
   if (mask & SpvMemoryAccessMakePointerAvailableKHRMask) {
   if (mask & SpvMemoryAccessMakePointerAvailableKHRMask) {
     if (inst->opcode() == SpvOpLoad) {
     if (inst->opcode() == SpvOpLoad) {
       return _.diag(SPV_ERROR_INVALID_ID, inst)
       return _.diag(SPV_ERROR_INVALID_ID, inst)
@@ -314,13 +327,12 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
   }
   }
 
 
   if (mask & SpvMemoryAccessNonPrivatePointerKHRMask) {
   if (mask & SpvMemoryAccessNonPrivatePointerKHRMask) {
-    SpvStorageClass dst_sc, src_sc;
-    std::tie(dst_sc, src_sc) = GetStorageClass(_, inst);
     if (dst_sc != SpvStorageClassUniform &&
     if (dst_sc != SpvStorageClassUniform &&
         dst_sc != SpvStorageClassWorkgroup &&
         dst_sc != SpvStorageClassWorkgroup &&
         dst_sc != SpvStorageClassCrossWorkgroup &&
         dst_sc != SpvStorageClassCrossWorkgroup &&
         dst_sc != SpvStorageClassGeneric && dst_sc != SpvStorageClassImage &&
         dst_sc != SpvStorageClassGeneric && dst_sc != SpvStorageClassImage &&
-        dst_sc != SpvStorageClassStorageBuffer) {
+        dst_sc != SpvStorageClassStorageBuffer &&
+        dst_sc != SpvStorageClassPhysicalStorageBufferEXT) {
       return _.diag(SPV_ERROR_INVALID_ID, inst)
       return _.diag(SPV_ERROR_INVALID_ID, inst)
              << "NonPrivatePointerKHR requires a pointer in Uniform, "
              << "NonPrivatePointerKHR requires a pointer in Uniform, "
                 "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
                 "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
@@ -330,7 +342,8 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
         src_sc != SpvStorageClassWorkgroup &&
         src_sc != SpvStorageClassWorkgroup &&
         src_sc != SpvStorageClassCrossWorkgroup &&
         src_sc != SpvStorageClassCrossWorkgroup &&
         src_sc != SpvStorageClassGeneric && src_sc != SpvStorageClassImage &&
         src_sc != SpvStorageClassGeneric && src_sc != SpvStorageClassImage &&
-        src_sc != SpvStorageClassStorageBuffer) {
+        src_sc != SpvStorageClassStorageBuffer &&
+        src_sc != SpvStorageClassPhysicalStorageBufferEXT) {
       return _.diag(SPV_ERROR_INVALID_ID, inst)
       return _.diag(SPV_ERROR_INVALID_ID, inst)
              << "NonPrivatePointerKHR requires a pointer in Uniform, "
              << "NonPrivatePointerKHR requires a pointer in Uniform, "
                 "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
                 "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
@@ -338,6 +351,15 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
     }
     }
   }
   }
 
 
+  if (!(mask & SpvMemoryAccessAlignedMask)) {
+    if (src_sc == SpvStorageClassPhysicalStorageBufferEXT ||
+        dst_sc == SpvStorageClassPhysicalStorageBufferEXT) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst) << "Memory accesses with "
+                                                   "PhysicalStorageBufferEXT "
+                                                   "must use Aligned.";
+    }
+  }
+
   return SPV_SUCCESS;
   return SPV_SUCCESS;
 }
 }
 
 
@@ -414,7 +436,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
   }
   }
 
 
   // Variable pointer related restrictions.
   // Variable pointer related restrictions.
-  auto pointee = _.FindDef(result_type->word(3));
+  const auto pointee = _.FindDef(result_type->word(3));
   if (_.addressing_model() == SpvAddressingModelLogical &&
   if (_.addressing_model() == SpvAddressingModelLogical &&
       !_.options()->relax_logical_pointer) {
       !_.options()->relax_logical_pointer) {
     // VariablePointersStorageBuffer is implied by VariablePointers.
     // VariablePointersStorageBuffer is implied by VariablePointers.
@@ -507,6 +529,125 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
     }
     }
   }
   }
 
 
+  // WebGPU: All variables with storage class Output, Private, or Function MUST
+  // have an initializer.
+  if (spvIsWebGPUEnv(_.context()->target_env) && inst->operands().size() <= 3 &&
+      (storage_class == SpvStorageClassOutput ||
+       storage_class == SpvStorageClassPrivate ||
+       storage_class == SpvStorageClassFunction)) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << "OpVariable, <id> '" << _.getIdName(inst->id())
+           << "', must have an initializer.\n"
+           << "From WebGPU execution environment spec:\n"
+           << "All variables in the following storage classes must have an "
+           << "initializer: Output, Private, or Function";
+  }
+
+  if (storage_class == SpvStorageClassPhysicalStorageBufferEXT) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << "PhysicalStorageBufferEXT must not be used with OpVariable.";
+  }
+
+  auto pointee_base = pointee;
+  while (pointee_base->opcode() == SpvOpTypeArray) {
+    pointee_base = _.FindDef(pointee_base->GetOperandAs<uint32_t>(1u));
+  }
+  if (pointee_base->opcode() == SpvOpTypePointer) {
+    if (pointee_base->GetOperandAs<uint32_t>(1u) ==
+        SpvStorageClassPhysicalStorageBufferEXT) {
+      // check for AliasedPointerEXT/RestrictPointerEXT
+      bool foundAliased =
+          _.HasDecoration(inst->id(), SpvDecorationAliasedPointerEXT);
+      bool foundRestrict =
+          _.HasDecoration(inst->id(), SpvDecorationRestrictPointerEXT);
+      if (!foundAliased && !foundRestrict) {
+        return _.diag(SPV_ERROR_INVALID_ID, inst)
+               << "OpVariable " << inst->id()
+               << ": expected AliasedPointerEXT or RestrictPointerEXT for "
+                  "PhysicalStorageBufferEXT pointer.";
+      }
+      if (foundAliased && foundRestrict) {
+        return _.diag(SPV_ERROR_INVALID_ID, inst)
+               << "OpVariable " << inst->id()
+               << ": can't specify both AliasedPointerEXT and "
+                  "RestrictPointerEXT for PhysicalStorageBufferEXT pointer.";
+      }
+    }
+  }
+
+  // Vulkan specific validation rules for OpTypeRuntimeArray
+  if (spvIsVulkanEnv(_.context()->target_env)) {
+    const auto type_index = 2;
+    const auto value_id = result_type->GetOperandAs<uint32_t>(type_index);
+    auto value_type = _.FindDef(value_id);
+    // OpTypeRuntimeArray should only ever be in a container like OpTypeStruct,
+    // so should never appear as a bare variable.
+    // Unless the module has the RuntimeDescriptorArrayEXT capability.
+    if (value_type && value_type->opcode() == SpvOpTypeRuntimeArray) {
+      if (!_.HasCapability(SpvCapabilityRuntimeDescriptorArrayEXT)) {
+        return _.diag(SPV_ERROR_INVALID_ID, inst)
+               << "OpVariable, <id> '" << _.getIdName(inst->id())
+               << "', is attempting to create memory for an illegal type, "
+                  "OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray can only "
+                  "appear as the final member of an OpTypeStruct, thus cannot "
+                  "be instantiated via OpVariable";
+      } else {
+        // A bare variable OpTypeRuntimeArray is allowed in this context, but
+        // still need to check the storage class.
+        if (storage_class != SpvStorageClassStorageBuffer &&
+            storage_class != SpvStorageClassUniform &&
+            storage_class != SpvStorageClassUniformConstant) {
+          return _.diag(SPV_ERROR_INVALID_ID, inst)
+                 << "For Vulkan with RuntimeDescriptorArrayEXT, a variable "
+                    "containing OpTypeRuntimeArray must have storage class of "
+                    "StorageBuffer, Uniform, or UniformConstant.";
+        }
+      }
+    }
+
+    // If an OpStruct has an OpTypeRuntimeArray somewhere within it, then it
+    // must either have the storage class StorageBuffer and be decorated
+    // with Block, or it must be in the Uniform storage class and be decorated
+    // as BufferBlock.
+    if (value_type && value_type->opcode() == SpvOpTypeStruct) {
+      bool contains_RTA = false;
+      for (size_t member_type_index = 1;
+           member_type_index < value_type->operands().size();
+           ++member_type_index) {
+        const auto member_type_id =
+            value_type->GetOperandAs<uint32_t>(member_type_index);
+        const auto member_type = _.FindDef(member_type_id);
+        if (member_type->opcode() == SpvOpTypeRuntimeArray) {
+          contains_RTA = true;
+          break;
+        }
+      }
+
+      if (contains_RTA) {
+        if (storage_class == SpvStorageClassStorageBuffer) {
+          if (!_.HasDecoration(value_id, SpvDecorationBlock)) {
+            return _.diag(SPV_ERROR_INVALID_ID, inst)
+                   << "For Vulkan, an OpTypeStruct variable containing an "
+                      "OpTypeRuntimeArray must be decorated with Block if it "
+                      "has storage class StorageBuffer.";
+          }
+        } else if (storage_class == SpvStorageClassUniform) {
+          if (!_.HasDecoration(value_id, SpvDecorationBufferBlock)) {
+            return _.diag(SPV_ERROR_INVALID_ID, inst)
+                   << "For Vulkan, an OpTypeStruct variable containing an "
+                      "OpTypeRuntimeArray must be decorated with BufferBlock "
+                      "if it has storage class Uniform.";
+          }
+        } else {
+          return _.diag(SPV_ERROR_INVALID_ID, inst)
+                 << "For Vulkan, OpTypeStruct variables containing "
+                    "OpTypeRuntimeArray must have storage class of "
+                    "StorageBuffer or Uniform.";
+        }
+      }
+    }
+  }
+
   return SPV_SUCCESS;
   return SPV_SUCCESS;
 }
 }
 
 
@@ -550,11 +691,7 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) {
            << "'s type.";
            << "'s type.";
   }
   }
 
 
-  if (inst->operands().size() > 3) {
-    if (auto error =
-            CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(3)))
-      return error;
-  }
+  if (auto error = CheckMemoryAccess(_, inst, 3)) return error;
 
 
   return SPV_SUCCESS;
   return SPV_SUCCESS;
 }
 }
@@ -642,11 +779,7 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction* inst) {
     }
     }
   }
   }
 
 
-  if (inst->operands().size() > 2) {
-    if (auto error =
-            CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(2)))
-      return error;
-  }
+  if (auto error = CheckMemoryAccess(_, inst, 2)) return error;
 
 
   return SPV_SUCCESS;
   return SPV_SUCCESS;
 }
 }
@@ -710,11 +843,7 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) {
              << _.getIdName(source_type->id()) << "'s type.";
              << _.getIdName(source_type->id()) << "'s type.";
     }
     }
 
 
-    if (inst->operands().size() > 2) {
-      if (auto error =
-              CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(2)))
-        return error;
-    }
+    if (auto error = CheckMemoryAccess(_, inst, 2)) return error;
   } else {
   } else {
     const auto size_id = inst->GetOperandAs<uint32_t>(2);
     const auto size_id = inst->GetOperandAs<uint32_t>(2);
     const auto size = _.FindDef(size_id);
     const auto size = _.FindDef(size_id);
@@ -758,11 +887,7 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) {
         break;
         break;
     }
     }
 
 
-    if (inst->operands().size() > 3) {
-      if (auto error =
-              CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(3)))
-        return error;
-    }
+    if (auto error = CheckMemoryAccess(_, inst, 3)) return error;
   }
   }
   return SPV_SUCCESS;
   return SPV_SUCCESS;
 }
 }

+ 28 - 0
3rdparty/spirv-tools/source/val/validate_type.cpp

@@ -17,6 +17,7 @@
 #include "source/val/validate.h"
 #include "source/val/validate.h"
 
 
 #include "source/opcode.h"
 #include "source/opcode.h"
+#include "source/spirv_target_env.h"
 #include "source/val/instruction.h"
 #include "source/val/instruction.h"
 #include "source/val/validation_state.h"
 #include "source/val/validation_state.h"
 
 
@@ -106,6 +107,13 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) {
            << "' is a void type.";
            << "' is a void type.";
   }
   }
 
 
+  if (spvIsVulkanEnv(_.context()->target_env) &&
+      element_type->opcode() == SpvOpTypeRuntimeArray) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << "OpTypeArray Element Type <id> '" << _.getIdName(element_type_id)
+           << "' is not valid in Vulkan environment.";
+  }
+
   const auto length_index = 2;
   const auto length_index = 2;
   const auto length_id = inst->GetOperandAs<uint32_t>(length_index);
   const auto length_id = inst->GetOperandAs<uint32_t>(length_index);
   const auto length = _.FindDef(length_id);
   const auto length = _.FindDef(length_id);
@@ -161,6 +169,14 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _,
            << _.getIdName(element_id) << "' is a void type.";
            << _.getIdName(element_id) << "' is a void type.";
   }
   }
 
 
+  if (spvIsVulkanEnv(_.context()->target_env) &&
+      element_type->opcode() == SpvOpTypeRuntimeArray) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << "OpTypeRuntimeArray Element Type <id> '"
+           << _.getIdName(element_id)
+           << "' is not valid in Vulkan environment.";
+  }
+
   return SPV_SUCCESS;
   return SPV_SUCCESS;
 }
 }
 
 
@@ -206,7 +222,19 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) {
                << ".";
                << ".";
       }
       }
     }
     }
+
+    if (spvIsVulkanEnv(_.context()->target_env) &&
+        member_type->opcode() == SpvOpTypeRuntimeArray) {
+      const bool is_last_member =
+          member_type_index == inst->operands().size() - 1;
+      if (!is_last_member) {
+        return _.diag(SPV_ERROR_INVALID_ID, inst)
+               << "In Vulkan, OpTypeRuntimeArray must only be used for the "
+                  "last member of an OpTypeStruct";
+      }
+    }
   }
   }
+
   std::unordered_set<uint32_t> built_in_members;
   std::unordered_set<uint32_t> built_in_members;
   for (auto decoration : _.id_decorations(struct_id)) {
   for (auto decoration : _.id_decorations(struct_id)) {
     if (decoration.dec_type() == SpvDecorationBuiltIn &&
     if (decoration.dec_type() == SpvDecorationBuiltIn &&

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

@@ -171,6 +171,7 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx,
       grammar_(ctx),
       grammar_(ctx),
       addressing_model_(SpvAddressingModelMax),
       addressing_model_(SpvAddressingModelMax),
       memory_model_(SpvMemoryModelMax),
       memory_model_(SpvMemoryModelMax),
+      pointer_size_and_alignment_(0),
       in_function_(false),
       in_function_(false),
       num_of_warnings_(0),
       num_of_warnings_(0),
       max_num_of_warnings_(max_warnings) {
       max_num_of_warnings_(max_warnings) {
@@ -411,6 +412,11 @@ void ValidationState_t::RegisterExtension(Extension ext) {
       // https://github.com/KhronosGroup/SPIRV-Tools/issues/1375
       // https://github.com/KhronosGroup/SPIRV-Tools/issues/1375
       features_.declare_float16_type = true;
       features_.declare_float16_type = true;
       break;
       break;
+    case kSPV_AMD_gpu_shader_int16:
+      // This is not yet in the extension, but it's recommended for it.
+      // See https://github.com/KhronosGroup/glslang/issues/848
+      features_.uconvert_spec_constant_op = true;
+      break;
     case kSPV_AMD_shader_ballot:
     case kSPV_AMD_shader_ballot:
       // The grammar doesn't encode the fact that SPV_AMD_shader_ballot
       // The grammar doesn't encode the fact that SPV_AMD_shader_ballot
       // enables the use of group operations Reduce, InclusiveScan,
       // enables the use of group operations Reduce, InclusiveScan,
@@ -435,6 +441,17 @@ bool ValidationState_t::HasAnyOfExtensions(
 
 
 void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
 void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
   addressing_model_ = am;
   addressing_model_ = am;
+  switch (am) {
+    case SpvAddressingModelPhysical32:
+      pointer_size_and_alignment_ = 4;
+      break;
+    default:
+      // fall through
+    case SpvAddressingModelPhysical64:
+    case SpvAddressingModelPhysicalStorageBuffer64EXT:
+      pointer_size_and_alignment_ = 8;
+      break;
+  }
 }
 }
 
 
 SpvAddressingModel ValidationState_t::addressing_model() const {
 SpvAddressingModel ValidationState_t::addressing_model() const {

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

@@ -15,6 +15,7 @@
 #ifndef SOURCE_VAL_VALIDATION_STATE_H_
 #ifndef SOURCE_VAL_VALIDATION_STATE_H_
 #define SOURCE_VAL_VALIDATION_STATE_H_
 #define SOURCE_VAL_VALIDATION_STATE_H_
 
 
+#include <algorithm>
 #include <map>
 #include <map>
 #include <set>
 #include <set>
 #include <string>
 #include <string>
@@ -104,6 +105,10 @@ class ValidationState_t {
     // - ArrayStride and MatrixStride are multiples of scalar alignment
     // - ArrayStride and MatrixStride are multiples of scalar alignment
     // 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;
+
+    // Permit UConvert as an OpSpecConstantOp operation.
+    // The Kernel capability already enables it, separately from this flag.
+    bool uconvert_spec_constant_op = false;
   };
   };
 
 
   ValidationState_t(const spv_const_context context,
   ValidationState_t(const spv_const_context context,
@@ -339,6 +344,11 @@ class ValidationState_t {
   /// Returns the addressing model of this module, or Logical if uninitialized.
   /// Returns the addressing model of this module, or Logical if uninitialized.
   SpvAddressingModel addressing_model() const;
   SpvAddressingModel addressing_model() const;
 
 
+  /// Returns the addressing model of this module, or Logical if uninitialized.
+  uint32_t pointer_size_and_alignment() const {
+    return pointer_size_and_alignment_;
+  }
+
   /// Sets the memory model of this module.
   /// Sets the memory model of this module.
   void set_memory_model(SpvMemoryModel mm);
   void set_memory_model(SpvMemoryModel mm);
 
 
@@ -387,17 +397,23 @@ class ValidationState_t {
   std::vector<Decoration>& id_decorations(uint32_t id) {
   std::vector<Decoration>& id_decorations(uint32_t id) {
     return id_decorations_[id];
     return id_decorations_[id];
   }
   }
-  const std::vector<Decoration>& id_decorations(uint32_t id) const {
-    // TODO: This would throw or generate SIGABRT if id has no
-    // decorations. Remove/refactor this function.
-    return id_decorations_.at(id);
-  }
 
 
   // Returns const pointer to the internal decoration container.
   // Returns const pointer to the internal decoration container.
   const std::map<uint32_t, std::vector<Decoration>>& id_decorations() const {
   const std::map<uint32_t, std::vector<Decoration>>& id_decorations() const {
     return id_decorations_;
     return id_decorations_;
   }
   }
 
 
+  /// Returns true if the given id <id> has the given decoration <dec>,
+  /// otherwise returns false.
+  bool HasDecoration(uint32_t id, SpvDecoration dec) {
+    const auto& decorations = id_decorations_.find(id);
+    if (decorations == id_decorations_.end()) return false;
+
+    return std::any_of(
+        decorations->second.begin(), decorations->second.end(),
+        [dec](const Decoration& d) { return dec == d.dec_type(); });
+  }
+
   /// Finds id's def, if it exists.  If found, returns the definition otherwise
   /// Finds id's def, if it exists.  If found, returns the definition otherwise
   /// nullptr
   /// nullptr
   const Instruction* FindDef(uint32_t id) const;
   const Instruction* FindDef(uint32_t id) const;
@@ -656,6 +672,9 @@ class ValidationState_t {
 
 
   SpvAddressingModel addressing_model_;
   SpvAddressingModel addressing_model_;
   SpvMemoryModel memory_model_;
   SpvMemoryModel memory_model_;
+  // pointer size derived from addressing model. Assumes all storage classes
+  // have the same pointer size (for physical pointer types).
+  uint32_t pointer_size_and_alignment_;
 
 
   /// NOTE: See correspoding getter functions
   /// NOTE: See correspoding getter functions
   bool in_function_;
   bool in_function_;

+ 2 - 0
3rdparty/spirv-tools/test/binary_parse_test.cpp

@@ -197,6 +197,8 @@ ParsedInstruction MakeParsedInt32TypeInstruction(uint32_t result_id) {
 
 
 class BinaryParseTest : public spvtest::TextToBinaryTestBase<::testing::Test> {
 class BinaryParseTest : public spvtest::TextToBinaryTestBase<::testing::Test> {
  protected:
  protected:
+  ~BinaryParseTest() { spvDiagnosticDestroy(diagnostic_); }
+
   void Parse(const SpirvVector& words, spv_result_t expected_result,
   void Parse(const SpirvVector& words, spv_result_t expected_result,
              bool flip_words = false) {
              bool flip_words = false) {
     SpirvVector flipped_words(words);
     SpirvVector flipped_words(words);

+ 15 - 8
3rdparty/spirv-tools/test/binary_to_text_test.cpp

@@ -34,8 +34,12 @@ using ::testing::HasSubstr;
 
 
 class BinaryToText : public ::testing::Test {
 class BinaryToText : public ::testing::Test {
  public:
  public:
-  BinaryToText() : context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)) {}
-  ~BinaryToText() { spvContextDestroy(context); }
+  BinaryToText()
+      : context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)), binary(nullptr) {}
+  ~BinaryToText() {
+    spvBinaryDestroy(binary);
+    spvContextDestroy(context);
+  }
 
 
   virtual void SetUp() {
   virtual void SetUp() {
     const char* textStr = R"(
     const char* textStr = R"(
@@ -63,17 +67,20 @@ class BinaryToText : public ::testing::Test {
     spv_diagnostic diagnostic = nullptr;
     spv_diagnostic diagnostic = nullptr;
     spv_result_t error =
     spv_result_t error =
         spvTextToBinary(context, text.str, text.length, &binary, &diagnostic);
         spvTextToBinary(context, text.str, text.length, &binary, &diagnostic);
-    if (error) {
-      spvDiagnosticPrint(diagnostic);
-      spvDiagnosticDestroy(diagnostic);
-      ASSERT_EQ(SPV_SUCCESS, error);
-    }
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+    ASSERT_EQ(SPV_SUCCESS, error);
   }
   }
 
 
-  virtual void TearDown() { spvBinaryDestroy(binary); }
+  virtual void TearDown() {
+    spvBinaryDestroy(binary);
+    binary = nullptr;
+  }
 
 
   // Compiles the given assembly text, and saves it into 'binary'.
   // Compiles the given assembly text, and saves it into 'binary'.
   void CompileSuccessfully(std::string text) {
   void CompileSuccessfully(std::string text) {
+    spvBinaryDestroy(binary);
+    binary = nullptr;
     spv_diagnostic diagnostic = nullptr;
     spv_diagnostic diagnostic = nullptr;
     EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(),
     EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(),
                                            &binary, &diagnostic));
                                            &binary, &diagnostic));

+ 2 - 1
3rdparty/spirv-tools/test/ext_inst.glsl_test.cpp

@@ -61,7 +61,7 @@ OpFunctionEnd
 ; Generator: Khronos SPIR-V Tools Assembler; 0
 ; Generator: Khronos SPIR-V Tools Assembler; 0
 ; Bound: 9
 ; Bound: 9
 ; Schema: 0)";
 ; Schema: 0)";
-  spv_binary binary;
+  spv_binary binary = nullptr;
   spv_diagnostic diagnostic;
   spv_diagnostic diagnostic;
   spv_result_t error = spvTextToBinary(context, spirv.c_str(), spirv.size(),
   spv_result_t error = spvTextToBinary(context, spirv.c_str(), spirv.size(),
                                        &binary, &diagnostic);
                                        &binary, &diagnostic);
@@ -102,6 +102,7 @@ OpFunctionEnd
   }
   }
   EXPECT_EQ(spirv_header + spirv, output_text->str);
   EXPECT_EQ(spirv_header + spirv, output_text->str);
   spvTextDestroy(output_text);
   spvTextDestroy(output_text);
+  spvBinaryDestroy(binary);
   spvContextDestroy(context);
   spvContextDestroy(context);
 }
 }
 
 

+ 1 - 6
3rdparty/spirv-tools/test/opt/CMakeLists.txt

@@ -81,6 +81,7 @@ add_spvtools_unittest(TARGET opt
        type_manager_test.cpp
        type_manager_test.cpp
        types_test.cpp
        types_test.cpp
        unify_const_test.cpp
        unify_const_test.cpp
+       upgrade_memory_model_test.cpp
        utils_test.cpp pass_utils.cpp
        utils_test.cpp pass_utils.cpp
        value_table_test.cpp
        value_table_test.cpp
        vector_dce_test.cpp
        vector_dce_test.cpp
@@ -88,9 +89,3 @@ add_spvtools_unittest(TARGET opt
   LIBS SPIRV-Tools-opt
   LIBS SPIRV-Tools-opt
   PCH_FILE pch_test_opt
   PCH_FILE pch_test_opt
 )
 )
-
-add_spvtools_unittest(TARGET upgrade_memory_model
-  SRCS upgrade_memory_model_test.cpp pass_utils.cpp
-  LIBS SPIRV-Tools-opt
-  PCH_FILE pch_test_opt
-)

+ 35 - 2
3rdparty/spirv-tools/test/opt/fold_test.cpp

@@ -168,6 +168,7 @@ OpName %main "main"
 %int_2 = OpConstant %int 2
 %int_2 = OpConstant %int 2
 %int_3 = OpConstant %int 3
 %int_3 = OpConstant %int 3
 %int_4 = OpConstant %int 4
 %int_4 = OpConstant %int 4
+%int_n24 = OpConstant %int -24
 %int_min = OpConstant %int -2147483648
 %int_min = OpConstant %int -2147483648
 %int_max = OpConstant %int 2147483647
 %int_max = OpConstant %int 2147483647
 %long_0 = OpConstant %long 0
 %long_0 = OpConstant %long 0
@@ -486,7 +487,7 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
           "OpReturn\n" +
           "OpReturn\n" +
           "OpFunctionEnd",
           "OpFunctionEnd",
       2, 0),
       2, 0),
-  // Test case 21: fold signed n >> 42 (undefined, so set to zero).
+  // Test case 23: fold signed n >> 42 (undefined, so set to zero).
   InstructionFoldingCase<uint32_t>(
   InstructionFoldingCase<uint32_t>(
       Header() + "%main = OpFunction %void None %void_func\n" +
       Header() + "%main = OpFunction %void None %void_func\n" +
           "%main_lab = OpLabel\n" +
           "%main_lab = OpLabel\n" +
@@ -496,7 +497,7 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
           "OpReturn\n" +
           "OpReturn\n" +
           "OpFunctionEnd",
           "OpFunctionEnd",
       2, 0),
       2, 0),
-  // Test case 22: fold n << 42 (undefined, so set to zero).
+  // Test case 24: fold n << 42 (undefined, so set to zero).
   InstructionFoldingCase<uint32_t>(
   InstructionFoldingCase<uint32_t>(
       Header() + "%main = OpFunction %void None %void_func\n" +
       Header() + "%main = OpFunction %void None %void_func\n" +
           "%main_lab = OpLabel\n" +
           "%main_lab = OpLabel\n" +
@@ -505,6 +506,38 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
           "%2 = OpShiftLeftLogical %int %load %uint_42\n" +
           "%2 = OpShiftLeftLogical %int %load %uint_42\n" +
           "OpReturn\n" +
           "OpReturn\n" +
           "OpFunctionEnd",
           "OpFunctionEnd",
+      2, 0),
+  // Test case 25: fold -24 >> 32 (defined as -1)
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, -1),
+  // Test case 26: fold 2 >> 32 (signed)
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, 0),
+  // Test case 27: fold 2 >> 32 (unsigned)
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, 0),
+  // Test case 28: fold 2 << 32
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
       2, 0)
       2, 0)
 ));
 ));
 // clang-format on
 // clang-format on

+ 15 - 8
3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp

@@ -92,7 +92,8 @@ OpDecorate %_entryPointOutput_vColor Location 0
 )";
 )";
 
 
   const std::string new_annots =
   const std::string new_annots =
-      R"(OpDecorate %_struct_55 Block
+      R"(OpDecorate %_runtimearr_uint ArrayStride 4
+OpDecorate %_struct_55 Block
 OpMemberDecorate %_struct_55 0 Offset 0
 OpMemberDecorate %_struct_55 0 Offset 0
 OpMemberDecorate %_struct_55 1 Offset 4
 OpMemberDecorate %_struct_55 1 Offset 4
 OpDecorate %57 DescriptorSet 7
 OpDecorate %57 DescriptorSet 7
@@ -441,6 +442,7 @@ OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %g_sAniso DescriptorSet 0
 OpDecorate %g_sAniso DescriptorSet 0
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
+OpDecorate %_runtimearr_uint ArrayStride 4
 OpDecorate %_struct_63 Block
 OpDecorate %_struct_63 Block
 OpMemberDecorate %_struct_63 0 Offset 0
 OpMemberDecorate %_struct_63 0 Offset 0
 OpMemberDecorate %_struct_63 1 Offset 4
 OpMemberDecorate %_struct_63 1 Offset 4
@@ -735,6 +737,7 @@ OpDecorate %_entryPointOutput_vColor Location 0
 OpDecorate %10 DescriptorSet 7
 OpDecorate %10 DescriptorSet 7
 OpDecorate %10 Binding 0
 OpDecorate %10 Binding 0
 OpDecorate %gl_FragCoord BuiltIn FragCoord
 OpDecorate %gl_FragCoord BuiltIn FragCoord
+OpDecorate %_runtimearr_uint ArrayStride 4
 OpDecorate %_struct_34 Block
 OpDecorate %_struct_34 Block
 OpMemberDecorate %_struct_34 0 Offset 0
 OpMemberDecorate %_struct_34 0 Offset 0
 OpMemberDecorate %_struct_34 1 Offset 4
 OpMemberDecorate %_struct_34 1 Offset 4
@@ -968,6 +971,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
+OpDecorate %_runtimearr_uint ArrayStride 4
 OpDecorate %_struct_51 Block
 OpDecorate %_struct_51 Block
 OpMemberDecorate %_struct_51 0 Offset 0
 OpMemberDecorate %_struct_51 0 Offset 0
 OpMemberDecorate %_struct_51 1 Offset 4
 OpMemberDecorate %_struct_51 1 Offset 4
@@ -1193,6 +1197,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
+OpDecorate %_runtimearr_uint ArrayStride 4
 OpDecorate %_struct_49 Block
 OpDecorate %_struct_49 Block
 OpMemberDecorate %_struct_49 0 Offset 0
 OpMemberDecorate %_struct_49 0 Offset 0
 OpMemberDecorate %_struct_49 1 Offset 4
 OpMemberDecorate %_struct_49 1 Offset 4
@@ -1418,6 +1423,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
+OpDecorate %_runtimearr_uint ArrayStride 4
 OpDecorate %_struct_48 Block
 OpDecorate %_struct_48 Block
 OpMemberDecorate %_struct_48 0 Offset 0
 OpMemberDecorate %_struct_48 0 Offset 0
 OpMemberDecorate %_struct_48 1 Offset 4
 OpMemberDecorate %_struct_48 1 Offset 4
@@ -1644,7 +1650,7 @@ OpCapability Sampled1D
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
-OpEntryPoint Vertex %main "main" %_ %coords2D %gl_VertexID %gl_InstanceID
+OpEntryPoint Vertex %main "main" %_ %coords2D %gl_VertexIndex %gl_InstanceIndex
 OpSource GLSL 450
 OpSource GLSL 450
 OpName %main "main"
 OpName %main "main"
 OpName %lod "lod"
 OpName %lod "lod"
@@ -1672,13 +1678,14 @@ OpDecorate %foo Block
 OpDecorate %__0 DescriptorSet 0
 OpDecorate %__0 DescriptorSet 0
 OpDecorate %__0 Binding 5
 OpDecorate %__0 Binding 5
 OpDecorate %coords2D Location 0
 OpDecorate %coords2D Location 0
+OpDecorate %_runtimearr_uint ArrayStride 4
 OpDecorate %_struct_61 Block
 OpDecorate %_struct_61 Block
 OpMemberDecorate %_struct_61 0 Offset 0
 OpMemberDecorate %_struct_61 0 Offset 0
 OpMemberDecorate %_struct_61 1 Offset 4
 OpMemberDecorate %_struct_61 1 Offset 4
 OpDecorate %63 DescriptorSet 7
 OpDecorate %63 DescriptorSet 7
 OpDecorate %63 Binding 0
 OpDecorate %63 Binding 0
-OpDecorate %gl_VertexID BuiltIn VertexId
-OpDecorate %gl_InstanceID BuiltIn InstanceId
+OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
 %void = OpTypeVoid
 %void = OpTypeVoid
 %12 = OpTypeFunction %void
 %12 = OpTypeFunction %void
 %float = OpTypeFloat 32
 %float = OpTypeFloat 32
@@ -1723,8 +1730,8 @@ OpDecorate %gl_InstanceID BuiltIn InstanceId
 %uint_2 = OpConstant %uint 2
 %uint_2 = OpConstant %uint 2
 %uint_3 = OpConstant %uint 3
 %uint_3 = OpConstant %uint 3
 %_ptr_Input_uint = OpTypePointer Input %uint
 %_ptr_Input_uint = OpTypePointer Input %uint
-%gl_VertexID = OpVariable %_ptr_Input_uint Input
-%gl_InstanceID = OpVariable %_ptr_Input_uint Input
+%gl_VertexIndex = OpVariable %_ptr_Input_uint Input
+%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
 %uint_5 = OpConstant %uint 5
 %uint_5 = OpConstant %uint 5
 %uint_6 = OpConstant %uint 6
 %uint_6 = OpConstant %uint 6
 %uint_7 = OpConstant %uint 7
 %uint_7 = OpConstant %uint 7
@@ -1812,11 +1819,11 @@ OpStore %81 %55
 %83 = OpIAdd %uint %68 %uint_3
 %83 = OpIAdd %uint %68 %uint_3
 %84 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %83
 %84 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %83
 OpStore %84 %uint_0
 OpStore %84 %uint_0
-%87 = OpLoad %uint %gl_VertexID
+%87 = OpLoad %uint %gl_VertexIndex
 %88 = OpIAdd %uint %68 %uint_4
 %88 = OpIAdd %uint %68 %uint_4
 %89 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %88
 %89 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %88
 OpStore %89 %87
 OpStore %89 %87
-%91 = OpLoad %uint %gl_InstanceID
+%91 = OpLoad %uint %gl_InstanceIndex
 %93 = OpIAdd %uint %68 %uint_5
 %93 = OpIAdd %uint %68 %uint_5
 %94 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %93
 %94 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %93
 OpStore %94 %91
 OpStore %94 %91

+ 5 - 5
3rdparty/spirv-tools/test/opt/pass_fixture.h

@@ -49,7 +49,7 @@ class PassTest : public TestT {
             [](spv_message_level_t, const char*, const spv_position_t&,
             [](spv_message_level_t, const char*, const spv_position_t&,
                const char* message) { std::cerr << message << std::endl; }),
                const char* message) { std::cerr << message << std::endl; }),
         context_(nullptr),
         context_(nullptr),
-        tools_(SPV_ENV_UNIVERSAL_1_1),
+        tools_(SPV_ENV_UNIVERSAL_1_3),
         manager_(new PassManager()),
         manager_(new PassManager()),
         assemble_options_(SpirvTools::kDefaultAssembleOption),
         assemble_options_(SpirvTools::kDefaultAssembleOption),
         disassemble_options_(SpirvTools::kDefaultDisassembleOption) {}
         disassemble_options_(SpirvTools::kDefaultDisassembleOption) {}
@@ -59,7 +59,7 @@ class PassTest : public TestT {
   // from pass Process() function.
   // from pass Process() function.
   std::tuple<std::vector<uint32_t>, Pass::Status> OptimizeToBinary(
   std::tuple<std::vector<uint32_t>, Pass::Status> OptimizeToBinary(
       Pass* pass, const std::string& original, bool skip_nop) {
       Pass* pass, const std::string& original, bool skip_nop) {
-    context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer_, original,
+    context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_3, consumer_, original,
                                      assemble_options_));
                                      assemble_options_));
     EXPECT_NE(nullptr, context()) << "Assembling failed for shader:\n"
     EXPECT_NE(nullptr, context()) << "Assembling failed for shader:\n"
                                   << original << std::endl;
                                   << original << std::endl;
@@ -97,7 +97,7 @@ class PassTest : public TestT {
     std::tie(optimized_bin, status) = SinglePassRunToBinary<PassT>(
     std::tie(optimized_bin, status) = SinglePassRunToBinary<PassT>(
         assembly, skip_nop, std::forward<Args>(args)...);
         assembly, skip_nop, std::forward<Args>(args)...);
     if (do_validation) {
     if (do_validation) {
-      spv_target_env target_env = SPV_ENV_UNIVERSAL_1_1;
+      spv_target_env target_env = SPV_ENV_UNIVERSAL_1_3;
       spv_context spvContext = spvContextCreate(target_env);
       spv_context spvContext = spvContextCreate(target_env);
       spv_diagnostic diagnostic = nullptr;
       spv_diagnostic diagnostic = nullptr;
       spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()};
       spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()};
@@ -134,7 +134,7 @@ class PassTest : public TestT {
     EXPECT_EQ(original == expected,
     EXPECT_EQ(original == expected,
               status == Pass::Status::SuccessWithoutChange);
               status == Pass::Status::SuccessWithoutChange);
     if (do_validation) {
     if (do_validation) {
-      spv_target_env target_env = SPV_ENV_UNIVERSAL_1_1;
+      spv_target_env target_env = SPV_ENV_UNIVERSAL_1_3;
       spv_context spvContext = spvContextCreate(target_env);
       spv_context spvContext = spvContextCreate(target_env);
       spv_diagnostic diagnostic = nullptr;
       spv_diagnostic diagnostic = nullptr;
       spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()};
       spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()};
@@ -202,7 +202,7 @@ class PassTest : public TestT {
   void RunAndCheck(const std::string& original, const std::string& expected) {
   void RunAndCheck(const std::string& original, const std::string& expected) {
     assert(manager_->NumPasses());
     assert(manager_->NumPasses());
 
 
-    context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, original,
+    context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, original,
                                      assemble_options_));
                                      assemble_options_));
     ASSERT_NE(nullptr, context());
     ASSERT_NE(nullptr, context());
 
 

+ 330 - 49
3rdparty/spirv-tools/test/opt/upgrade_memory_model_test.cpp

@@ -23,7 +23,6 @@ using namespace spvtools;
 
 
 using UpgradeMemoryModelTest = opt::PassTest<::testing::Test>;
 using UpgradeMemoryModelTest = opt::PassTest<::testing::Test>;
 
 
-#ifdef SPIRV_EFFCEE
 TEST_F(UpgradeMemoryModelTest, InvalidMemoryModelOpenCL) {
 TEST_F(UpgradeMemoryModelTest, InvalidMemoryModelOpenCL) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK: OpMemoryModel Logical OpenCL
 ; CHECK: OpMemoryModel Logical OpenCL
@@ -80,8 +79,8 @@ OpDecorate %var Coherent
 TEST_F(UpgradeMemoryModelTest, WorkgroupVariable) {
 TEST_F(UpgradeMemoryModelTest, WorkgroupVariable) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
@@ -104,8 +103,8 @@ OpFunctionEnd
 TEST_F(UpgradeMemoryModelTest, WorkgroupFunctionParameter) {
 TEST_F(UpgradeMemoryModelTest, WorkgroupFunctionParameter) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
@@ -129,8 +128,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformVariable) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
@@ -156,8 +155,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameter) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
@@ -209,8 +208,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformVariableCopied) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
@@ -237,8 +236,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameterCopied) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
@@ -266,8 +265,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformVariableAccessChain) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
@@ -298,8 +297,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameterAccessChain) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
@@ -331,8 +330,8 @@ TEST_F(UpgradeMemoryModelTest, VariablePointerSelect) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpCapability VariablePointers
 OpCapability VariablePointers
@@ -364,8 +363,8 @@ TEST_F(UpgradeMemoryModelTest, VariablePointerSelectConservative) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpCapability VariablePointers
 OpCapability VariablePointers
@@ -397,8 +396,8 @@ TEST_F(UpgradeMemoryModelTest, VariablePointerIncrement) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate {{%\w+}} Coherent
 ; CHECK-NOT: OpDecorate {{%\w+}} Coherent
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpCapability VariablePointers
 OpCapability VariablePointers
@@ -440,8 +439,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentStructElement) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -471,8 +470,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentElementFullStructAccess) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -530,8 +529,8 @@ TEST_F(UpgradeMemoryModelTest, MultiIndexAccessCoherent) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -600,8 +599,8 @@ TEST_F(UpgradeMemoryModelTest, ConsecutiveAccessChainCoherent) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -682,8 +681,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentStructElementAccess) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -723,8 +722,8 @@ TEST_F(UpgradeMemoryModelTest, NonCoherentLoadCoherentStore) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK-NOT: OpMemberDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK-NOT: MakePointerAvailableKHR
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK-NOT: MakePointerVisibleKHR
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -823,7 +822,7 @@ TEST_F(UpgradeMemoryModelTest, CopyMemoryTwoScopes) {
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK-DAG: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK-DAG: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK-DAG: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2
 ; CHECK-DAG: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|MakePointerVisibleKHR|NonPrivatePointerKHR [[queuefamily]] [[workgroup]]
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|MakePointerVisibleKHR|NonPrivatePointerKHR [[workgroup]] [[queuefamily]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -883,8 +882,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageRead) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]] 
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]] 
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpCapability StorageImageReadWithoutFormat
 OpCapability StorageImageReadWithoutFormat
@@ -917,9 +916,9 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageReadExtractedFromSampledImage) {
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[image:%\w+]] = OpTypeImage
 ; CHECK: [[image:%\w+]] = OpTypeImage
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad [[image]] {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
 ; CHECK-NOT: NonPrivatePointerKHR
 ; CHECK-NOT: NonPrivatePointerKHR
-; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpCapability StorageImageReadWithoutFormat
 OpCapability StorageImageReadWithoutFormat
@@ -990,8 +989,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageWrite) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR
-; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR
+; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpCapability StorageImageWriteWithoutFormat
 OpCapability StorageImageWriteWithoutFormat
@@ -1023,9 +1022,9 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageWriteExtractFromSampledImage) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR
 ; CHECK-NOT: NonPrivatePointerKHR
 ; CHECK-NOT: NonPrivatePointerKHR
-; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpCapability StorageImageWriteWithoutFormat
 OpCapability StorageImageWriteWithoutFormat
@@ -1098,8 +1097,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageSparseRead) {
   const std::string text = R"(
   const std::string text = R"(
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]] 
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]] 
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpCapability StorageImageReadWithoutFormat
 OpCapability StorageImageReadWithoutFormat
@@ -1135,9 +1134,9 @@ TEST_F(UpgradeMemoryModelTest,
 ; CHECK-NOT: OpDecorate
 ; CHECK-NOT: OpDecorate
 ; CHECK: [[image:%\w+]] = OpTypeImage
 ; CHECK: [[image:%\w+]] = OpTypeImage
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
 ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad [[image]] {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
 ; CHECK-NOT: NonPrivatePointerKHR
 ; CHECK-NOT: NonPrivatePointerKHR
-; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
 OpCapability Shader
 OpCapability Shader
 OpCapability Linkage
 OpCapability Linkage
 OpCapability StorageImageReadWithoutFormat
 OpCapability StorageImageReadWithoutFormat
@@ -1430,6 +1429,288 @@ OpFunctionEnd
   SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
   SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
 }
 }
 
 
-#endif
+TEST_F(UpgradeMemoryModelTest, UpgradeModfNoFlags) {
+  const std::string text = R"(
+; CHECK: [[float:%\w+]] = OpTypeFloat 32
+; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
+; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]]
+; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
+; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]]
+; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
+; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
+; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
+; CHECK: OpStore [[var]] [[ex1]]
+; CHECK-NOT: NonPrivatePointerKHR
+; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+%import = OpExtInstImport "GLSL.std.450"
+OpEntryPoint GLCompute %func "func"
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%float_0 = OpConstant %float 0
+%ptr_ssbo_float = OpTypePointer StorageBuffer %float
+%ssbo_var = OpVariable %ptr_ssbo_float StorageBuffer
+%func_ty = OpTypeFunction %void
+%func = OpFunction %void None %func_ty
+%1 = OpLabel
+%2 = OpExtInst %float %import Modf %float_0 %ssbo_var
+%3 = OpFAdd %float %float_0 %2
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
+}
+
+TEST_F(UpgradeMemoryModelTest, UpgradeModfWorkgroupCoherent) {
+  const std::string text = R"(
+; CHECK: [[float:%\w+]] = OpTypeFloat 32
+; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
+; CHECK: [[ptr:%\w+]] = OpTypePointer Workgroup [[float]]
+; CHECK: [[var:%\w+]] = OpVariable [[ptr]] Workgroup
+; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]]
+; CHECK: [[wg_scope:%\w+]] = OpConstant {{%\w+}} 2
+; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
+; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
+; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
+; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[wg_scope]]
+; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+%import = OpExtInstImport "GLSL.std.450"
+OpEntryPoint GLCompute %func "func"
+OpDecorate %wg_var Coherent
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%float_0 = OpConstant %float 0
+%ptr_wg_float = OpTypePointer Workgroup %float
+%wg_var = OpVariable %ptr_wg_float Workgroup
+%func_ty = OpTypeFunction %void
+%func = OpFunction %void None %func_ty
+%1 = OpLabel
+%2 = OpExtInst %float %import Modf %float_0 %wg_var
+%3 = OpFAdd %float %float_0 %2
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
+}
+
+TEST_F(UpgradeMemoryModelTest, UpgradeModfSSBOCoherent) {
+  const std::string text = R"(
+; CHECK: [[float:%\w+]] = OpTypeFloat 32
+; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
+; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]]
+; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
+; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]]
+; CHECK: [[qf_scope:%\w+]] = OpConstant {{%\w+}} 5
+; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
+; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
+; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
+; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[qf_scope]]
+; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+%import = OpExtInstImport "GLSL.std.450"
+OpEntryPoint GLCompute %func "func"
+OpDecorate %ssbo_var Coherent
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%float_0 = OpConstant %float 0
+%ptr_ssbo_float = OpTypePointer StorageBuffer %float
+%ssbo_var = OpVariable %ptr_ssbo_float StorageBuffer
+%func_ty = OpTypeFunction %void
+%func = OpFunction %void None %func_ty
+%1 = OpLabel
+%2 = OpExtInst %float %import Modf %float_0 %ssbo_var
+%3 = OpFAdd %float %float_0 %2
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
+}
+
+TEST_F(UpgradeMemoryModelTest, UpgradeModfSSBOVolatile) {
+  const std::string text = R"(
+; CHECK: [[float:%\w+]] = OpTypeFloat 32
+; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
+; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]]
+; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
+; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]]
+; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
+; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
+; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
+; CHECK: OpStore [[var]] [[ex1]] Volatile
+; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+%import = OpExtInstImport "GLSL.std.450"
+OpEntryPoint GLCompute %func "func"
+OpDecorate %wg_var Volatile
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%float_0 = OpConstant %float 0
+%ptr_ssbo_float = OpTypePointer StorageBuffer %float
+%wg_var = OpVariable %ptr_ssbo_float StorageBuffer
+%func_ty = OpTypeFunction %void
+%func = OpFunction %void None %func_ty
+%1 = OpLabel
+%2 = OpExtInst %float %import Modf %float_0 %wg_var
+%3 = OpFAdd %float %float_0 %2
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
+}
+
+TEST_F(UpgradeMemoryModelTest, UpgradeFrexpNoFlags) {
+  const std::string text = R"(
+; CHECK: [[float:%\w+]] = OpTypeFloat 32
+; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
+; CHECK: [[int:%\w+]] = OpTypeInt 32 0
+; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]]
+; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
+; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]]
+; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
+; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
+; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
+; CHECK: OpStore [[var]] [[ex1]]
+; CHECK-NOT: NonPrivatePointerKHR
+; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+%import = OpExtInstImport "GLSL.std.450"
+OpEntryPoint GLCompute %func "func"
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%float_0 = OpConstant %float 0
+%int = OpTypeInt 32 0
+%ptr_ssbo_int = OpTypePointer StorageBuffer %int
+%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
+%func_ty = OpTypeFunction %void
+%func = OpFunction %void None %func_ty
+%1 = OpLabel
+%2 = OpExtInst %float %import Frexp %float_0 %ssbo_var
+%3 = OpFAdd %float %float_0 %2
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
+}
+
+TEST_F(UpgradeMemoryModelTest, UpgradeFrexpWorkgroupCoherent) {
+  const std::string text = R"(
+; CHECK: [[float:%\w+]] = OpTypeFloat 32
+; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
+; CHECK: [[int:%\w+]] = OpTypeInt 32 0
+; CHECK: [[ptr:%\w+]] = OpTypePointer Workgroup [[int]]
+; CHECK: [[var:%\w+]] = OpVariable [[ptr]] Workgroup
+; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]]
+; CHECK: [[wg_scope:%\w+]] = OpConstant {{%\w+}} 2
+; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
+; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
+; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
+; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[wg_scope]]
+; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+%import = OpExtInstImport "GLSL.std.450"
+OpEntryPoint GLCompute %func "func"
+OpDecorate %wg_var Coherent
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%float_0 = OpConstant %float 0
+%int = OpTypeInt 32 0
+%ptr_wg_int = OpTypePointer Workgroup %int
+%wg_var = OpVariable %ptr_wg_int Workgroup
+%func_ty = OpTypeFunction %void
+%func = OpFunction %void None %func_ty
+%1 = OpLabel
+%2 = OpExtInst %float %import Frexp %float_0 %wg_var
+%3 = OpFAdd %float %float_0 %2
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
+}
+
+TEST_F(UpgradeMemoryModelTest, UpgradeFrexpSSBOCoherent) {
+  const std::string text = R"(
+; CHECK: [[float:%\w+]] = OpTypeFloat 32
+; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
+; CHECK: [[int:%\w+]] = OpTypeInt 32 0
+; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]]
+; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
+; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]]
+; CHECK: [[qf_scope:%\w+]] = OpConstant {{%\w+}} 5
+; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
+; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
+; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
+; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[qf_scope]]
+; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+%import = OpExtInstImport "GLSL.std.450"
+OpEntryPoint GLCompute %func "func"
+OpDecorate %ssbo_var Coherent
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%float_0 = OpConstant %float 0
+%int = OpTypeInt 32 0
+%ptr_ssbo_int = OpTypePointer StorageBuffer %int
+%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
+%func_ty = OpTypeFunction %void
+%func = OpFunction %void None %func_ty
+%1 = OpLabel
+%2 = OpExtInst %float %import Frexp %float_0 %ssbo_var
+%3 = OpFAdd %float %float_0 %2
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
+}
+
+TEST_F(UpgradeMemoryModelTest, UpgradeFrexpSSBOVolatile) {
+  const std::string text = R"(
+; CHECK: [[float:%\w+]] = OpTypeFloat 32
+; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
+; CHECK: [[int:%\w+]] = OpTypeInt 32 0
+; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]]
+; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
+; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]]
+; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
+; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
+; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
+; CHECK: OpStore [[var]] [[ex1]] Volatile
+; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+%import = OpExtInstImport "GLSL.std.450"
+OpEntryPoint GLCompute %func "func"
+OpDecorate %wg_var Volatile
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%float_0 = OpConstant %float 0
+%int = OpTypeInt 32 0
+%ptr_ssbo_int = OpTypePointer StorageBuffer %int
+%wg_var = OpVariable %ptr_ssbo_int StorageBuffer
+%func_ty = OpTypeFunction %void
+%func = OpFunction %void None %func_ty
+%1 = OpLabel
+%2 = OpExtInst %float %import Frexp %float_0 %wg_var
+%3 = OpFAdd %float %float_0 %2
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
+}
 
 
 }  // namespace
 }  // namespace

+ 13 - 0
3rdparty/spirv-tools/test/test_fixture.h

@@ -61,6 +61,8 @@ class TextToBinaryTestBase : public T {
   // compilation success. Returns the compiled code.
   // compilation success. Returns the compiled code.
   SpirvVector CompileSuccessfully(const std::string& txt,
   SpirvVector CompileSuccessfully(const std::string& txt,
                                   spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
                                   spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
+    DestroyBinary();
+    DestroyDiagnostic();
     spv_result_t status =
     spv_result_t status =
         spvTextToBinary(ScopedContext(env).context, txt.c_str(), txt.size(),
         spvTextToBinary(ScopedContext(env).context, txt.c_str(), txt.size(),
                         &binary, &diagnostic);
                         &binary, &diagnostic);
@@ -79,6 +81,8 @@ class TextToBinaryTestBase : public T {
   // Returns the error message(s).
   // Returns the error message(s).
   std::string CompileFailure(const std::string& txt,
   std::string CompileFailure(const std::string& txt,
                              spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
                              spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
+    DestroyBinary();
+    DestroyDiagnostic();
     EXPECT_NE(SPV_SUCCESS,
     EXPECT_NE(SPV_SUCCESS,
               spvTextToBinary(ScopedContext(env).context, txt.c_str(),
               spvTextToBinary(ScopedContext(env).context, txt.c_str(),
                               txt.size(), &binary, &diagnostic))
                               txt.size(), &binary, &diagnostic))
@@ -94,6 +98,7 @@ class TextToBinaryTestBase : public T {
       uint32_t disassemble_options = SPV_BINARY_TO_TEXT_OPTION_NONE,
       uint32_t disassemble_options = SPV_BINARY_TO_TEXT_OPTION_NONE,
       spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
       spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
     DestroyBinary();
     DestroyBinary();
+    DestroyDiagnostic();
     ScopedContext context(env);
     ScopedContext context(env);
     disassemble_options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER;
     disassemble_options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER;
     spv_result_t error = spvTextToBinary(context.context, txt.c_str(),
     spv_result_t error = spvTextToBinary(context.context, txt.c_str(),
@@ -126,6 +131,8 @@ class TextToBinaryTestBase : public T {
   // Returns the error message.
   // Returns the error message.
   std::string EncodeSuccessfullyDecodeFailed(
   std::string EncodeSuccessfullyDecodeFailed(
       const std::string& txt, const SpirvVector& words_to_append) {
       const std::string& txt, const SpirvVector& words_to_append) {
+    DestroyBinary();
+    DestroyDiagnostic();
     SpirvVector code =
     SpirvVector code =
         spvtest::Concatenate({CompileSuccessfully(txt), words_to_append});
         spvtest::Concatenate({CompileSuccessfully(txt), words_to_append});
 
 
@@ -169,6 +176,12 @@ class TextToBinaryTestBase : public T {
     binary = nullptr;
     binary = nullptr;
   }
   }
 
 
+  // Destroys the diagnostic, if it exists.
+  void DestroyDiagnostic() {
+    spvDiagnosticDestroy(diagnostic);
+    diagnostic = nullptr;
+  }
+
   spv_diagnostic diagnostic;
   spv_diagnostic diagnostic;
 
 
   std::string textString;
   std::string textString;

+ 14 - 0
3rdparty/spirv-tools/test/val/val_constants_test.cpp

@@ -280,6 +280,20 @@ INSTANTIATE_TEST_CASE_P(
                       "InBoundsPtrAccessChain"),
                       "InBoundsPtrAccessChain"),
     }));
     }));
 
 
+INSTANTIATE_TEST_CASE_P(
+    UConvertInAMD_gpu_shader_int16, ValidateConstantOp,
+    ValuesIn(std::vector<ConstantOpCase>{
+        // SPV_AMD_gpu_shader_int16 should enable UConvert for OpSpecConstantOp
+        // https://github.com/KhronosGroup/glslang/issues/848
+        {SPV_ENV_UNIVERSAL_1_0,
+         "OpCapability Shader "
+         "OpCapability Linkage ; So we don't need to define a function\n"
+         "OpExtension \"SPV_AMD_gpu_shader_int16\" "
+         "OpMemoryModel Logical Simple " kBasicTypes
+         "%v = OpSpecConstantOp %uint UConvert %uint_0",
+         true, ""},
+    }));
+
 }  // namespace
 }  // namespace
 }  // namespace val
 }  // namespace val
 }  // namespace spvtools
 }  // namespace spvtools

+ 112 - 0
3rdparty/spirv-tools/test/val/val_conversion_test.cpp

@@ -1302,6 +1302,118 @@ OpFunctionEnd
                                                "type"));
                                                "type"));
 }
 }
 
 
+TEST_F(ValidateConversion, ConvertUToPtrPSBSuccess) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpConvertUToPtr %ptr %u64_1
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateConversion, ConvertUToPtrPSBStorageClass) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer Function %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpConvertUToPtr %ptr %u64_1
+%val2 = OpConvertPtrToU %uint64 %val1
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Pointer storage class must be "
+                        "PhysicalStorageBufferEXT: ConvertUToPtr"));
+}
+
+TEST_F(ValidateConversion, ConvertPtrToUPSBSuccess) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 RestrictPointerEXT
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpConvertPtrToU %uint64 %val2
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateConversion, ConvertPtrToUPSBStorageClass) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer Function %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %ptr Function
+%val2 = OpConvertPtrToU %uint64 %val1
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Pointer storage class must be "
+                        "PhysicalStorageBufferEXT: ConvertPtrToU"));
+}
+
 }  // namespace
 }  // namespace
 }  // namespace val
 }  // namespace val
 }  // namespace spvtools
 }  // namespace spvtools

+ 169 - 0
3rdparty/spirv-tools/test/val/val_data_test.cpp

@@ -36,6 +36,24 @@ std::string HeaderWith(std::string cap) {
          cap + " OpMemoryModel Logical GLSL450 ";
          cap + " OpMemoryModel Logical GLSL450 ";
 }
 }
 
 
+std::string WebGPUHeaderWith(std::string cap) {
+  return R"(
+OpCapability Shader
+OpCapability )" +
+         cap + R"(
+OpCapability VulkanMemoryModelKHR
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical VulkanKHR
+)";
+}
+
+std::string webgpu_header = R"(
+OpCapability Shader
+OpCapability VulkanMemoryModelKHR
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical VulkanKHR
+)";
+
 std::string header = R"(
 std::string header = R"(
      OpCapability Shader
      OpCapability Shader
      OpCapability Linkage
      OpCapability Linkage
@@ -249,6 +267,18 @@ TEST_F(ValidateData, int8_with_storage_push_constant_8_good) {
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
 }
 }
 
 
+TEST_F(ValidateData, webgpu_int8_bad) {
+  std::string str = WebGPUHeaderWith("Int8") + "%2 = OpTypeInt 8 0";
+  CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
+            ValidateInstructions(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Capability Int8 is not allowed by WebGPU specification (or "
+                "requires extension)\n"
+                "  OpCapability Int8\n"));
+}
+
 TEST_F(ValidateData, int16_good) {
 TEST_F(ValidateData, int16_good) {
   std::string str = header_with_int16 + "%2 = OpTypeInt 16 1";
   std::string str = header_with_int16 + "%2 = OpTypeInt 16 1";
   CompileSuccessfully(str.c_str());
   CompileSuccessfully(str.c_str());
@@ -308,6 +338,34 @@ TEST_F(ValidateData, int16_bad) {
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error));
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error));
 }
 }
 
 
+TEST_F(ValidateData, webgpu_int16_bad) {
+  std::string str = WebGPUHeaderWith("Int16") + "%2 = OpTypeInt 16 1";
+  CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
+            ValidateInstructions(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Capability Int16 is not allowed by WebGPU specification (or "
+                "requires extension)\n"
+                "  OpCapability Int16\n"));
+}
+
+TEST_F(ValidateData, webgpu_int32_good) {
+  std::string str = webgpu_header + R"(
+          OpEntryPoint Fragment %func "func"
+          OpExecutionMode %func OriginUpperLeft
+%uint_t = OpTypeInt 32 0
+  %void = OpTypeVoid
+%func_t = OpTypeFunction %void
+  %func = OpFunction %void None %func_t
+     %1 = OpLabel
+          OpReturn
+          OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
+}
+
 TEST_F(ValidateData, int64_good) {
 TEST_F(ValidateData, int64_good) {
   std::string str = header_with_int64 + "%2 = OpTypeInt 64 1";
   std::string str = header_with_int64 + "%2 = OpTypeInt 64 1";
   CompileSuccessfully(str.c_str());
   CompileSuccessfully(str.c_str());
@@ -321,6 +379,18 @@ TEST_F(ValidateData, int64_bad) {
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error));
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error));
 }
 }
 
 
+TEST_F(ValidateData, webgpu_int64_bad) {
+  std::string str = WebGPUHeaderWith("Int64") + "%2 = OpTypeInt 64 1";
+  CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
+            ValidateInstructions(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Capability Int64 is not allowed by WebGPU specification (or "
+                "requires extension)\n"
+                "  OpCapability Int64\n"));
+}
+
 // Number of bits in an integer may be only one of: {8,16,32,64}
 // Number of bits in an integer may be only one of: {8,16,32,64}
 TEST_F(ValidateData, int_invalid_num_bits) {
 TEST_F(ValidateData, int_invalid_num_bits) {
   std::string str = header + "%2 = OpTypeInt 48 1";
   std::string str = header + "%2 = OpTypeInt 48 1";
@@ -348,6 +418,34 @@ TEST_F(ValidateData, float16_bad) {
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error));
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error));
 }
 }
 
 
+TEST_F(ValidateData, webgpu_float16_bad) {
+  std::string str = WebGPUHeaderWith("Float16") + "%2 = OpTypeFloat 16";
+  CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
+            ValidateInstructions(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Capability Float16 is not allowed by WebGPU specification (or "
+                "requires extension)\n"
+                "  OpCapability Float16\n"));
+}
+
+TEST_F(ValidateData, webgpu_float32_good) {
+  std::string str = webgpu_header + R"(
+           OpEntryPoint Fragment %func "func"
+           OpExecutionMode %func OriginUpperLeft
+%float_t = OpTypeFloat 32
+   %void = OpTypeVoid
+ %func_t = OpTypeFunction %void
+   %func = OpFunction %void None %func_t
+      %1 = OpLabel
+           OpReturn
+           OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
+}
+
 TEST_F(ValidateData, float64_good) {
 TEST_F(ValidateData, float64_good) {
   std::string str = header_with_float64 + "%2 = OpTypeFloat 64";
   std::string str = header_with_float64 + "%2 = OpTypeFloat 64";
   CompileSuccessfully(str.c_str());
   CompileSuccessfully(str.c_str());
@@ -361,6 +459,18 @@ TEST_F(ValidateData, float64_bad) {
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error));
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error));
 }
 }
 
 
+TEST_F(ValidateData, webgpu_float64_bad) {
+  std::string str = WebGPUHeaderWith("Float64") + "%2 = OpTypeFloat 64";
+  CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
+            ValidateInstructions(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Capability Float64 is not allowed by WebGPU specification (or "
+                "requires extension)\n"
+                "  OpCapability Float64\n"));
+}
+
 // Number of bits in a float may be only one of: {16,32,64}
 // Number of bits in a float may be only one of: {16,32,64}
 TEST_F(ValidateData, float_invalid_num_bits) {
 TEST_F(ValidateData, float_invalid_num_bits) {
   std::string str = header + "%2 = OpTypeFloat 48";
   std::string str = header + "%2 = OpTypeFloat 48";
@@ -703,6 +813,65 @@ TEST_F(ValidateData, void_runtime_array) {
       HasSubstr(
       HasSubstr(
           "OpTypeRuntimeArray Element Type <id> '1[%void]' is a void type."));
           "OpTypeRuntimeArray Element Type <id> '1[%void]' is a void type."));
 }
 }
+
+TEST_F(ValidateData, vulkan_RTA_array_at_end_of_struct) {
+  std::string str = R"(
+              OpCapability Shader
+              OpMemoryModel Logical GLSL450
+              OpEntryPoint Fragment %func "func"
+              OpExecutionMode %func OriginUpperLeft
+              OpDecorate %array_t ArrayStride 4
+              OpMemberDecorate %struct_t 0 Offset 0
+              OpMemberDecorate %struct_t 1 Offset 4
+              OpDecorate %struct_t Block
+     %uint_t = OpTypeInt 32 0
+   %array_t = OpTypeRuntimeArray %uint_t
+  %struct_t = OpTypeStruct %uint_t %array_t
+%struct_ptr = OpTypePointer StorageBuffer %struct_t
+         %2 = OpVariable %struct_ptr StorageBuffer
+      %void = OpTypeVoid
+    %func_t = OpTypeFunction %void
+      %func = OpFunction %void None %func_t
+         %1 = OpLabel
+              OpReturn
+              OpFunctionEnd
+)";
+
+  CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+}
+
+TEST_F(ValidateData, vulkan_RTA_not_at_end_of_struct) {
+  std::string str = R"(
+              OpCapability Shader
+              OpMemoryModel Logical GLSL450
+              OpEntryPoint Fragment %func "func"
+              OpExecutionMode %func OriginUpperLeft
+              OpDecorate %array_t ArrayStride 4
+              OpMemberDecorate %struct_t 0 Offset 0
+              OpMemberDecorate %struct_t 1 Offset 4
+              OpDecorate %struct_t Block
+     %uint_t = OpTypeInt 32 0
+   %array_t = OpTypeRuntimeArray %uint_t
+  %struct_t = OpTypeStruct %array_t %uint_t
+%struct_ptr = OpTypePointer StorageBuffer %struct_t
+         %2 = OpVariable %struct_ptr StorageBuffer
+      %void = OpTypeVoid
+    %func_t = OpTypeFunction %void
+      %func = OpFunction %void None %func_t
+         %1 = OpLabel
+              OpReturn
+              OpFunctionEnd
+)";
+
+  CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("In Vulkan, OpTypeRuntimeArray must only be used for "
+                        "the last member of an OpTypeStruct\n  %_struct_3 = "
+                        "OpTypeStruct %_runtimearr_uint %uint\n"));
+}
+
 }  // namespace
 }  // namespace
 }  // namespace val
 }  // namespace val
 }  // namespace spvtools
 }  // namespace spvtools

+ 497 - 5
3rdparty/spirv-tools/test/val/val_decoration_test.cpp

@@ -4345,11 +4345,11 @@ OpFunctionEnd
 
 
   CompileSuccessfully(spirv);
   CompileSuccessfully(spirv);
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
-  EXPECT_THAT(
-      getDiagnosticString(),
-      HasSubstr("FPRoundingMode decoration can be applied only to the "
-                "Object operand of an OpStore in the StorageBuffer, Uniform, "
-                "PushConstant, Input, or Output Storage Classes."));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("FPRoundingMode decoration can be applied only to the "
+                        "Object operand of an OpStore in the StorageBuffer, "
+                        "PhysicalStorageBufferEXT, Uniform, "
+                        "PushConstant, Input, or Output Storage Classes."));
 }
 }
 
 
 TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) {
 TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) {
@@ -4810,6 +4810,498 @@ TEST_F(ValidateDecorations, BlockAndBufferBlockDecorationsOnSameID) {
           "ID '2' decorated with both BufferBlock and Block is not allowed."));
           "ID '2' decorated with both BufferBlock and Block is not allowed."));
 }
 }
 
 
+std::string MakeIntegerShader(
+    const std::string& decoration, const std::string& inst,
+    const std::string& extension =
+        "OpExtension \"SPV_KHR_no_integer_wrap_decoration\"") {
+  return R"(
+OpCapability Shader
+OpCapability Linkage
+)" + extension +
+         R"(
+%glsl = OpExtInstImport "GLSL.std.450"
+%opencl = OpExtInstImport "OpenCL.std"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpName %entry "entry"
+)" + decoration +
+         R"(
+    %void = OpTypeVoid
+  %voidfn = OpTypeFunction %void
+     %int = OpTypeInt 32 1
+    %zero = OpConstantNull %int
+   %float = OpTypeFloat 32
+  %float0 = OpConstantNull %float
+    %main = OpFunction %void None %voidfn
+   %entry = OpLabel
+)" + inst +
+         R"(
+OpReturn
+OpFunctionEnd)";
+}
+
+// NoSignedWrap
+
+TEST_F(ValidateDecorations, NoSignedWrapOnTypeBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %void NoSignedWrap", "");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("NoSignedWrap decoration may not be applied to TypeVoid"));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapOnLabelBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %entry NoSignedWrap", "");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("NoSignedWrap decoration may not be applied to Label"));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
+                                        "%val = OpIAdd %int %zero %zero", "");
+
+  CompileSuccessfully(spirv);
+  EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("requires one of these extensions: "
+                        "SPV_KHR_no_integer_wrap_decoration"));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapIAddGood) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
+                                        "%val = OpIAdd %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapISubGood) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
+                                        "%val = OpISub %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapIMulGood) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
+                                        "%val = OpIMul %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapShiftLeftLogicalGood) {
+  std::string spirv =
+      MakeIntegerShader("OpDecorate %val NoSignedWrap",
+                        "%val = OpShiftLeftLogical %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapSNegateGood) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
+                                        "%val = OpSNegate %int %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapSRemBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
+                                        "%val = OpSRem %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("NoSignedWrap decoration may not be applied to SRem"));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapFAddBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
+                                        "%val = OpFAdd %float %float0 %float0");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("NoSignedWrap decoration may not be applied to FAdd"));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapExtInstOpenCLGood) {
+  std::string spirv =
+      MakeIntegerShader("OpDecorate %val NoSignedWrap",
+                        "%val = OpExtInst %int %opencl s_abs %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoSignedWrapExtInstGLSLGood) {
+  std::string spirv = MakeIntegerShader(
+      "OpDecorate %val NoSignedWrap", "%val = OpExtInst %int %glsl SAbs %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+// TODO(dneto): For NoSignedWrap and NoUnsignedWrap, permit
+// "OpExtInst for instruction numbers specified in the extended
+// instruction-set specifications as accepting this decoration."
+
+// NoUnignedWrap
+
+TEST_F(ValidateDecorations, NoUnsignedWrapOnTypeBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %void NoUnsignedWrap", "");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("NoUnsignedWrap decoration may not be applied to TypeVoid"));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapOnLabelBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %entry NoUnsignedWrap", "");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("NoUnsignedWrap decoration may not be applied to Label"));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                                        "%val = OpIAdd %int %zero %zero", "");
+
+  CompileSuccessfully(spirv);
+  EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("requires one of these extensions: "
+                        "SPV_KHR_no_integer_wrap_decoration"));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapIAddGood) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                                        "%val = OpIAdd %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapISubGood) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                                        "%val = OpISub %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapIMulGood) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                                        "%val = OpIMul %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapShiftLeftLogicalGood) {
+  std::string spirv =
+      MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                        "%val = OpShiftLeftLogical %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapSNegateGood) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                                        "%val = OpSNegate %int %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapSRemBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                                        "%val = OpSRem %int %zero %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("NoUnsignedWrap decoration may not be applied to SRem"));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapFAddBad) {
+  std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                                        "%val = OpFAdd %float %float0 %float0");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("NoUnsignedWrap decoration may not be applied to FAdd"));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapExtInstOpenCLGood) {
+  std::string spirv =
+      MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                        "%val = OpExtInst %int %opencl s_abs %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, NoUnsignedWrapExtInstGLSLGood) {
+  std::string spirv =
+      MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
+                        "%val = OpExtInst %int %glsl SAbs %zero");
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+// TODO(dneto): For NoUnsignedWrap and NoUnsignedWrap, permit
+// "OpExtInst for instruction numbers specified in the extended
+// instruction-set specifications as accepting this decoration."
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictPointerSuccess) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 RestrictPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictPointerMissing) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("expected AliasedPointerEXT or RestrictPointerEXT for "
+                        "PhysicalStorageBufferEXT pointer"));
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictPointerBoth) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 RestrictPointerEXT
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("can't specify both AliasedPointerEXT and RestrictPointerEXT "
+                "for PhysicalStorageBufferEXT pointer"));
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamSuccess) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %fparam Restrict
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%fnptr = OpTypeFunction %void %ptr
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+%fn = OpFunction %void None %fnptr
+%fparam = OpFunctionParameter %ptr
+%lab = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamMissing) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%fnptr = OpTypeFunction %void %ptr
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+%fn = OpFunction %void None %fnptr
+%fparam = OpFunctionParameter %ptr
+%lab = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("expected Aliased or Restrict for "
+                        "PhysicalStorageBufferEXT pointer"));
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamBoth) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %fparam Restrict
+OpDecorate %fparam Aliased
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%fnptr = OpTypeFunction %void %ptr
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+%fn = OpFunction %void None %fnptr
+%fparam = OpFunctionParameter %ptr
+%lab = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("can't specify both Aliased and Restrict for "
+                        "PhysicalStorageBufferEXT pointer"));
+}
+
+TEST_F(ValidateDecorations, PSBFPRoundingModeSuccess) {
+  std::string spirv = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Shader
+OpCapability Linkage
+OpCapability StorageBuffer16BitAccess
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpExtension "SPV_KHR_variable_pointers"
+OpExtension "SPV_KHR_16bit_storage"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint GLCompute %main "main"
+OpDecorate %_ FPRoundingMode RTE
+OpDecorate %half_ptr_var AliasedPointerEXT
+%half = OpTypeFloat 16
+%float = OpTypeFloat 32
+%float_1_25 = OpConstant %float 1.25
+%half_ptr = OpTypePointer PhysicalStorageBufferEXT %half
+%half_pptr_f = OpTypePointer Function %half_ptr
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+%half_ptr_var = OpVariable %half_pptr_f Function
+%val1 = OpLoad %half_ptr %half_ptr_var
+%_ = OpFConvert %half %float_1_25
+OpStore %val1 %_ Aligned 2
+OpReturn
+OpFunctionEnd
+  )";
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+}
+
 }  // namespace
 }  // namespace
 }  // namespace val
 }  // namespace val
 }  // namespace spvtools
 }  // namespace spvtools

+ 19 - 3
3rdparty/spirv-tools/test/val/val_fixtures.h

@@ -56,6 +56,18 @@ class ValidateBase : public ::testing::Test,
   spv_result_t ValidateAndRetrieveValidationState(
   spv_result_t ValidateAndRetrieveValidationState(
       spv_target_env env = SPV_ENV_UNIVERSAL_1_0);
       spv_target_env env = SPV_ENV_UNIVERSAL_1_0);
 
 
+  // Destroys the stored binary.
+  void DestroyBinary() {
+    spvBinaryDestroy(binary_);
+    binary_ = nullptr;
+  }
+
+  // Destroys the stored diagnostic.
+  void DestroyDiagnostic() {
+    spvDiagnosticDestroy(diagnostic_);
+    diagnostic_ = nullptr;
+  }
+
   std::string getDiagnosticString();
   std::string getDiagnosticString();
   spv_position_t getErrorPosition();
   spv_position_t getErrorPosition();
   spv_validator_options getValidatorOptions();
   spv_validator_options getValidatorOptions();
@@ -67,7 +79,7 @@ class ValidateBase : public ::testing::Test,
 };
 };
 
 
 template <typename T>
 template <typename T>
-ValidateBase<T>::ValidateBase() : binary_(), diagnostic_() {
+ValidateBase<T>::ValidateBase() : binary_(nullptr), diagnostic_(nullptr) {
   // Initialize to default command line options. Different tests can then
   // Initialize to default command line options. Different tests can then
   // specialize specific options as necessary.
   // specialize specific options as necessary.
   options_ = spvValidatorOptionsCreate();
   options_ = spvValidatorOptionsCreate();
@@ -83,14 +95,15 @@ void ValidateBase<T>::TearDown() {
   if (diagnostic_) {
   if (diagnostic_) {
     spvDiagnosticPrint(diagnostic_);
     spvDiagnosticPrint(diagnostic_);
   }
   }
-  spvDiagnosticDestroy(diagnostic_);
-  spvBinaryDestroy(binary_);
+  DestroyBinary();
+  DestroyDiagnostic();
   spvValidatorOptionsDestroy(options_);
   spvValidatorOptionsDestroy(options_);
 }
 }
 
 
 template <typename T>
 template <typename T>
 void ValidateBase<T>::CompileSuccessfully(std::string code,
 void ValidateBase<T>::CompileSuccessfully(std::string code,
                                           spv_target_env env) {
                                           spv_target_env env) {
+  DestroyBinary();
   spv_diagnostic diagnostic = nullptr;
   spv_diagnostic diagnostic = nullptr;
   ASSERT_EQ(SPV_SUCCESS,
   ASSERT_EQ(SPV_SUCCESS,
             spvTextToBinary(ScopedContext(env).context, code.c_str(),
             spvTextToBinary(ScopedContext(env).context, code.c_str(),
@@ -98,6 +111,7 @@ void ValidateBase<T>::CompileSuccessfully(std::string code,
       << "ERROR: " << diagnostic->error
       << "ERROR: " << diagnostic->error
       << "\nSPIR-V could not be compiled into binary:\n"
       << "\nSPIR-V could not be compiled into binary:\n"
       << code;
       << code;
+  spvDiagnosticDestroy(diagnostic);
 }
 }
 
 
 template <typename T>
 template <typename T>
@@ -110,6 +124,7 @@ void ValidateBase<T>::OverwriteAssembledBinary(uint32_t index, uint32_t word) {
 
 
 template <typename T>
 template <typename T>
 spv_result_t ValidateBase<T>::ValidateInstructions(spv_target_env env) {
 spv_result_t ValidateBase<T>::ValidateInstructions(spv_target_env env) {
+  DestroyDiagnostic();
   return spvValidateWithOptions(ScopedContext(env).context, options_,
   return spvValidateWithOptions(ScopedContext(env).context, options_,
                                 get_const_binary(), &diagnostic_);
                                 get_const_binary(), &diagnostic_);
 }
 }
@@ -117,6 +132,7 @@ spv_result_t ValidateBase<T>::ValidateInstructions(spv_target_env env) {
 template <typename T>
 template <typename T>
 spv_result_t ValidateBase<T>::ValidateAndRetrieveValidationState(
 spv_result_t ValidateBase<T>::ValidateAndRetrieveValidationState(
     spv_target_env env) {
     spv_target_env env) {
+  DestroyDiagnostic();
   return spvtools::val::ValidateBinaryAndKeepValidationState(
   return spvtools::val::ValidateBinaryAndKeepValidationState(
       ScopedContext(env).context, options_, get_const_binary()->code,
       ScopedContext(env).context, options_, get_const_binary()->code,
       get_const_binary()->wordCount, &diagnostic_, &vstate_);
       get_const_binary()->wordCount, &diagnostic_, &vstate_);

+ 2 - 0
3rdparty/spirv-tools/test/val/val_id_test.cpp

@@ -780,6 +780,8 @@ class OpTypeArrayLengthTest
   // Runs spvValidate() on v, printing any errors via spvDiagnosticPrint().
   // Runs spvValidate() on v, printing any errors via spvDiagnosticPrint().
   spv_result_t Val(const SpirvVector& v, const std::string& expected_err = "") {
   spv_result_t Val(const SpirvVector& v, const std::string& expected_err = "") {
     spv_const_binary_t cbinary{v.data(), v.size()};
     spv_const_binary_t cbinary{v.data(), v.size()};
+    spvDiagnosticDestroy(diagnostic_);
+    diagnostic_ = nullptr;
     const auto status =
     const auto status =
         spvValidate(ScopedContext().context, &cbinary, &diagnostic_);
         spvValidate(ScopedContext().context, &cbinary, &diagnostic_);
     if (status != SPV_SUCCESS) {
     if (status != SPV_SUCCESS) {

+ 30 - 0
3rdparty/spirv-tools/test/val/val_logicals_test.cpp

@@ -919,6 +919,36 @@ TEST_F(ValidateLogicals, OpSGreaterThanDifferentBitWidth) {
                         "width: SGreaterThan"));
                         "width: SGreaterThan"));
 }
 }
 
 
+TEST_F(ValidateLogicals, PSBSelectSuccess) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpSelect %ptr %true %val2 %val2
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
 }  // namespace
 }  // namespace
 }  // namespace val
 }  // namespace val
 }  // namespace spvtools
 }  // namespace spvtools

+ 815 - 0
3rdparty/spirv-tools/test/val/val_memory_test.cpp

@@ -138,7 +138,9 @@ OpFunctionEnd
 
 
 TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceRuntimeArrayGood) {
 TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceRuntimeArrayGood) {
   std::string spirv = R"(
   std::string spirv = R"(
+OpCapability RuntimeDescriptorArrayEXT
 OpCapability Shader
 OpCapability Shader
+OpExtension "SPV_EXT_descriptor_indexing"
 OpMemoryModel Logical GLSL450
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %func "func"
 OpEntryPoint Fragment %func "func"
 OpExecutionMode %func OriginUpperLeft
 OpExecutionMode %func OriginUpperLeft
@@ -455,6 +457,93 @@ OpFunctionEnd
           "  %5 = OpVariable %_ptr_Uniform_float Uniform %float_1\n"));
           "  %5 = OpVariable %_ptr_Uniform_float Uniform %float_1\n"));
 }
 }
 
 
+TEST_F(ValidateMemory, WebGPUOutputStorageClassWithoutInitializerBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpCapability VulkanMemoryModelKHR
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical VulkanKHR
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%float = OpTypeFloat 32
+%float_ptr = OpTypePointer Output %float
+%1 = OpVariable %float_ptr Output
+%void = OpTypeVoid
+%functy = OpTypeFunction %void
+%func = OpFunction %void None %functy
+%2 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("OpVariable, <id> '4[%4]', must have an initializer.\n"
+                "From WebGPU execution environment spec:\n"
+                "All variables in the following storage classes must have an "
+                "initializer: Output, Private, or Function\n"
+                "  %4 = OpVariable %_ptr_Output_float Output\n"));
+}
+
+TEST_F(ValidateMemory, WebGPUFunctionStorageClassWithoutInitializerBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpCapability VulkanMemoryModelKHR
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical VulkanKHR
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%float = OpTypeFloat 32
+%float_ptr = OpTypePointer Function %float
+%void = OpTypeVoid
+%functy = OpTypeFunction %void
+%func = OpFunction %void None %functy
+%1 = OpLabel
+%2 = OpVariable %float_ptr Function
+OpReturn
+OpFunctionEnd
+)";
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("OpVariable, <id> '7[%7]', must have an initializer.\n"
+                "From WebGPU execution environment spec:\n"
+                "All variables in the following storage classes must have an "
+                "initializer: Output, Private, or Function\n"
+                "  %7 = OpVariable %_ptr_Function_float Function\n"));
+}
+
+TEST_F(ValidateMemory, WebGPUPrivateStorageClassWithoutInitializerBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpCapability VulkanMemoryModelKHR
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical VulkanKHR
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%float = OpTypeFloat 32
+%float_ptr = OpTypePointer Private %float
+%1 = OpVariable %float_ptr Private
+%void = OpTypeVoid
+%functy = OpTypeFunction %void
+%func = OpFunction %void None %functy
+%2 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("OpVariable, <id> '4[%4]', must have an initializer.\n"
+                "From WebGPU execution environment spec:\n"
+                "All variables in the following storage classes must have an "
+                "initializer: Output, Private, or Function\n"
+                "  %4 = OpVariable %_ptr_Private_float Private\n"));
+}
+
 TEST_F(ValidateMemory, VulkanInitializerWithOutputStorageClassesGood) {
 TEST_F(ValidateMemory, VulkanInitializerWithOutputStorageClassesGood) {
   std::string spirv = R"(
   std::string spirv = R"(
 OpCapability Shader
 OpCapability Shader
@@ -1537,6 +1626,732 @@ OpFunctionEnd
               HasSubstr("Operand 1[%incorrect] requires a type"));
               HasSubstr("Operand 1[%incorrect] requires a type"));
 }
 }
 
 
+TEST_F(ValidateMemory, PSBLoadAlignedSuccess) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpLoad %uint64 %val2 Aligned 8
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateMemory, PSBLoadAlignedMissing) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpLoad %uint64 %val2
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
+}
+
+TEST_F(ValidateMemory, PSBStoreAlignedSuccess) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+OpStore %val2 %u64_1 Aligned 8
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateMemory, PSBStoreAlignedMissing) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+OpStore %val2 %u64_1 None
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
+}
+
+TEST_F(ValidateMemory, PSBVariable) {
+  const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%val1 = OpVariable %ptr PhysicalStorageBufferEXT
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("PhysicalStorageBufferEXT must not be used with OpVariable"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAOutsideOfStructBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%sampler_t = OpTypeSampler
+%array_t = OpTypeRuntimeArray %sampler_t
+%array_ptr = OpTypePointer UniformConstant %array_t
+%2 = OpVariable %array_ptr UniformConstant
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpVariable, <id> '5[%5]', is attempting to create memory for an "
+          "illegal type, OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray "
+          "can only appear as the final member of an OpTypeStruct, thus cannot "
+          "be instantiated via OpVariable\n  %5 = OpVariable "
+          "%_ptr_UniformConstant__runtimearr_2 UniformConstant\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayGood) {
+  std::string spirv = R"(
+OpCapability Shader
+OpCapability RuntimeDescriptorArrayEXT
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%sampler_t = OpTypeSampler
+%array_t = OpTypeRuntimeArray %sampler_t
+%array_sb_ptr = OpTypePointer StorageBuffer %array_t
+%2 = OpVariable %array_sb_ptr StorageBuffer
+%array_uc_ptr = OpTypePointer UniformConstant %array_t
+%3 = OpVariable %array_uc_ptr UniformConstant
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+}
+
+TEST_F(
+    ValidateMemory,
+    VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayAndWrongStorageClassBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpCapability RuntimeDescriptorArrayEXT
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%uint_t = OpTypeInt 32 0
+%array_t = OpTypeRuntimeArray %uint_t
+%array_ptr = OpTypePointer Workgroup %array_t
+%2 = OpVariable %array_ptr Workgroup
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("For Vulkan with RuntimeDescriptorArrayEXT, a variable "
+                "containing OpTypeRuntimeArray must have storage class of "
+                "StorageBuffer, Uniform, or UniformConstant.\n  %5 = "
+                "OpVariable %_ptr_Workgroup__runtimearr_uint Workgroup\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructGood) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t ArrayStride 4
+OpMemberDecorate %struct_t 0 Offset 0
+OpDecorate %struct_t Block
+%uint_t = OpTypeInt 32 0
+%array_t = OpTypeRuntimeArray %uint_t
+%struct_t = OpTypeStruct %array_t
+%struct_ptr = OpTypePointer StorageBuffer %struct_t
+%2 = OpVariable %struct_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideWrongStorageClassStructBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%uint_t = OpTypeInt 32 0
+%array_t = OpTypeRuntimeArray %uint_t
+%struct_t = OpTypeStruct %array_t
+%struct_ptr = OpTypePointer Workgroup %struct_t
+%2 = OpVariable %struct_ptr Workgroup
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "For Vulkan, OpTypeStruct variables containing OpTypeRuntimeArray "
+          "must have storage class of StorageBuffer or Uniform.\n  %6 = "
+          "OpVariable %_ptr_Workgroup__struct_4 Workgroup\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructWithoutBlockBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%uint_t = OpTypeInt 32 0
+%array_t = OpTypeRuntimeArray %uint_t
+%struct_t = OpTypeStruct %array_t
+%struct_ptr = OpTypePointer StorageBuffer %struct_t
+%2 = OpVariable %struct_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("For Vulkan, an OpTypeStruct variable containing an "
+                        "OpTypeRuntimeArray must be decorated with Block if it "
+                        "has storage class StorageBuffer.\n  %6 = OpVariable "
+                        "%_ptr_StorageBuffer__struct_4 StorageBuffer\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideUniformStructGood) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t ArrayStride 4
+OpMemberDecorate %struct_t 0 Offset 0
+OpDecorate %struct_t BufferBlock
+%uint_t = OpTypeInt 32 0
+%array_t = OpTypeRuntimeArray %uint_t
+%struct_t = OpTypeStruct %array_t
+%struct_ptr = OpTypePointer Uniform %struct_t
+%2 = OpVariable %struct_ptr Uniform
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideUniformStructWithoutBufferBlockBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%uint_t = OpTypeInt 32 0
+%array_t = OpTypeRuntimeArray %uint_t
+%struct_t = OpTypeStruct %array_t
+%struct_ptr = OpTypePointer Uniform %struct_t
+%2 = OpVariable %struct_ptr Uniform
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("For Vulkan, an OpTypeStruct variable containing an "
+                        "OpTypeRuntimeArray must be decorated with BufferBlock "
+                        "if it has storage class Uniform.\n  %6 = OpVariable "
+                        "%_ptr_Uniform__struct_4 Uniform\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideRTABad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%sampler_t = OpTypeSampler
+%inner_array_t = OpTypeRuntimeArray %sampler_t
+%array_t = OpTypeRuntimeArray %inner_array_t
+%array_ptr = OpTypePointer UniformConstant %array_t
+%2 = OpVariable %array_ptr UniformConstant
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpTypeRuntimeArray Element Type <id> '3[%_runtimearr_2]' is not "
+          "valid in Vulkan environment.\n  %_runtimearr__runtimearr_2 = "
+          "OpTypeRuntimeArray %_runtimearr_2\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideRTAWithRuntimeDescriptorArrayBad) {
+  std::string spirv = R"(
+OpCapability RuntimeDescriptorArrayEXT
+OpCapability Shader
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t Block
+%uint_t = OpTypeInt 32 0
+%inner_array_t = OpTypeRuntimeArray %uint_t
+%array_t = OpTypeRuntimeArray %inner_array_t
+%array_ptr = OpTypePointer StorageBuffer %array_t
+%2 = OpVariable %array_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpTypeRuntimeArray Element Type <id> '4[%_runtimearr_uint]' is not "
+          "valid in Vulkan environment.\n  %_runtimearr__runtimearr_uint = "
+          "OpTypeRuntimeArray %_runtimearr_uint\n"));
+}
+
+TEST_F(ValidateMemory,
+       VulkanUniformStructInsideRTAWithRuntimeDescriptorArrayGood) {
+  std::string spirv = R"(
+OpCapability RuntimeDescriptorArrayEXT
+OpCapability Shader
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t ArrayStride 4
+OpMemberDecorate %struct_t 0 Offset 0
+OpDecorate %struct_t Block
+%uint_t = OpTypeInt 32 0
+%struct_t = OpTypeStruct %uint_t
+%array_t = OpTypeRuntimeArray %struct_t
+%array_ptr = OpTypePointer Uniform %array_t
+%2 = OpVariable %array_ptr Uniform
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideRTAInsideStructBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t ArrayStride 4
+OpMemberDecorate %struct_t 0 Offset 0
+OpDecorate %struct_t Block
+%uint_t = OpTypeInt 32 0
+%inner_array_t = OpTypeRuntimeArray %uint_t
+%array_t = OpTypeRuntimeArray %inner_array_t
+%struct_t = OpTypeStruct %array_t
+%struct_ptr = OpTypePointer StorageBuffer %struct_t
+%2 = OpVariable %struct_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpTypeRuntimeArray Element Type <id> '5[%_runtimearr_uint]' is not "
+          "valid in Vulkan environment.\n  %_runtimearr__runtimearr_uint = "
+          "OpTypeRuntimeArray %_runtimearr_uint\n"));
+}
+
+TEST_F(ValidateMemory,
+       VulkanRTAInsideRTAInsideStructWithRuntimeDescriptorArrayBad) {
+  std::string spirv = R"(
+OpCapability RuntimeDescriptorArrayEXT
+OpCapability Shader
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t ArrayStride 4
+OpMemberDecorate %struct_t 0 Offset 0
+OpDecorate %struct_t Block
+%uint_t = OpTypeInt 32 0
+%inner_array_t = OpTypeRuntimeArray %uint_t
+%array_t = OpTypeRuntimeArray %inner_array_t
+%struct_t = OpTypeStruct %array_t
+%struct_ptr = OpTypePointer StorageBuffer %struct_t
+%2 = OpVariable %struct_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpTypeRuntimeArray Element Type <id> '5[%_runtimearr_uint]' is not "
+          "valid in Vulkan environment.\n  %_runtimearr__runtimearr_uint = "
+          "OpTypeRuntimeArray %_runtimearr_uint\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideArrayBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+%uint_t = OpTypeInt 32 0
+%dim = OpConstant %uint_t 1
+%sampler_t = OpTypeSampler
+%inner_array_t = OpTypeRuntimeArray %sampler_t
+%array_t = OpTypeArray %inner_array_t %dim
+%array_ptr = OpTypePointer UniformConstant %array_t
+%2 = OpVariable %array_ptr UniformConstant
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("OpTypeArray Element Type <id> '5[%_runtimearr_4]' is not "
+                "valid in Vulkan environment.\n  %_arr__runtimearr_4_uint_1 = "
+                "OpTypeArray %_runtimearr_4 %uint_1\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideArrayWithRuntimeDescriptorArrayBad) {
+  std::string spirv = R"(
+OpCapability RuntimeDescriptorArrayEXT
+OpCapability Shader
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t Block
+%uint_t = OpTypeInt 32 0
+%dim = OpConstant %uint_t 1
+%sampler_t = OpTypeSampler
+%inner_array_t = OpTypeRuntimeArray %uint_t
+%array_t = OpTypeRuntimeArray %inner_array_t
+%array_ptr = OpTypePointer StorageBuffer %array_t
+%2 = OpVariable %array_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpTypeRuntimeArray Element Type <id> '6[%_runtimearr_uint]' is not "
+          "valid in Vulkan environment.\n  %_runtimearr__runtimearr_uint = "
+          "OpTypeRuntimeArray %_runtimearr_uint\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAInsideArrayInsideStructBad) {
+  std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t ArrayStride 4
+OpMemberDecorate %struct_t 0 Offset 0
+OpDecorate %struct_t Block
+%uint_t = OpTypeInt 32 0
+%dim = OpConstant %uint_t 1
+%inner_array_t = OpTypeRuntimeArray %uint_t
+%array_t = OpTypeArray %inner_array_t %dim
+%struct_t = OpTypeStruct %array_t
+%struct_ptr = OpTypePointer StorageBuffer %struct_t
+%2 = OpVariable %struct_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
+                "valid in Vulkan environment.\n  %_arr__runtimearr_uint_uint_1 "
+                "= OpTypeArray %_runtimearr_uint %uint_1\n"));
+}
+
+TEST_F(ValidateMemory,
+       VulkanRTAInsideArrayInsideStructWithRuntimeDescriptorArrayBad) {
+  std::string spirv = R"(
+OpCapability RuntimeDescriptorArrayEXT
+OpCapability Shader
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t ArrayStride 4
+OpMemberDecorate %struct_t 0 Offset 0
+OpDecorate %struct_t Block
+%uint_t = OpTypeInt 32 0
+%dim = OpConstant %uint_t 1
+%inner_array_t = OpTypeRuntimeArray %uint_t
+%array_t = OpTypeArray %inner_array_t %dim
+%struct_t = OpTypeStruct %array_t
+%struct_ptr = OpTypePointer StorageBuffer %struct_t
+%2 = OpVariable %struct_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
+                "valid in Vulkan environment.\n  %_arr__runtimearr_uint_uint_1 "
+                "= OpTypeArray %_runtimearr_uint %uint_1\n"));
+}
+
+TEST_F(ValidateMemory, VulkanRTAStructInsideRTAWithRuntimeDescriptorArrayGood) {
+  std::string spirv = R"(
+OpCapability RuntimeDescriptorArrayEXT
+OpCapability Shader
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t ArrayStride 4
+OpMemberDecorate %struct_t 0 Offset 0
+OpDecorate %struct_t Block
+%uint_t = OpTypeInt 32 0
+%inner_array_t = OpTypeRuntimeArray %uint_t
+%struct_t = OpTypeStruct %inner_array_t
+%array_t = OpTypeRuntimeArray %struct_t
+%array_ptr = OpTypePointer StorageBuffer %array_t
+%2 = OpVariable %array_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+}
+
+TEST_F(ValidateMemory, VulkanRTAStructInsideArrayGood) {
+  std::string spirv = R"(
+OpCapability RuntimeDescriptorArrayEXT
+OpCapability Shader
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+OpExecutionMode %func OriginUpperLeft
+OpDecorate %array_t ArrayStride 4
+OpMemberDecorate %struct_t 0 Offset 0
+OpDecorate %struct_t Block
+%uint_t = OpTypeInt 32 0
+%inner_array_t = OpTypeRuntimeArray %uint_t
+%struct_t = OpTypeStruct %inner_array_t
+%array_size = OpConstant %uint_t 5
+%array_t = OpTypeArray %struct_t %array_size
+%array_ptr = OpTypePointer StorageBuffer %array_t
+%2 = OpVariable %array_ptr StorageBuffer
+%void = OpTypeVoid
+%func_t = OpTypeFunction %void
+%func = OpFunction %void None %func_t
+%1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+}
+
 }  // namespace
 }  // namespace
 }  // namespace val
 }  // namespace val
 }  // namespace spvtools
 }  // namespace spvtools

+ 48 - 0
3rdparty/spirv-tools/test/val/val_validation_state_test.cpp

@@ -306,6 +306,54 @@ TEST_F(ValidationStateTest, CheckWebGPUIndirectlyRecursiveBodyBad) {
                         "called.\n  %9 = OpFunctionCall %_struct_5 %10\n"));
                         "called.\n  %9 = OpFunctionCall %_struct_5 %10\n"));
 }
 }
 
 
+TEST_F(ValidationStateTest,
+       CheckWebGPUDuplicateEntryNamesDifferentFunctionsBad) {
+  std::string spirv = std::string(kVulkanMemoryHeader) + R"(
+OpEntryPoint Fragment %func_1 "main"
+OpEntryPoint Vertex %func_2 "main"
+OpExecutionMode %func_1 OriginUpperLeft
+%void    = OpTypeVoid
+%void_f  = OpTypeFunction %void
+%func_1  = OpFunction %void None %void_f
+%label_1 = OpLabel
+           OpReturn
+           OpFunctionEnd
+%func_2  = OpFunction %void None %void_f
+%label_2 = OpLabel
+           OpReturn
+           OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
+  EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+            ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Entry point name \"main\" is not unique, which is not allow "
+                "in WebGPU env.\n  %1 = OpFunction %void None %4\n"));
+}
+
+TEST_F(ValidationStateTest, CheckWebGPUDuplicateEntryNamesSameFunctionBad) {
+  std::string spirv = std::string(kVulkanMemoryHeader) + R"(
+OpEntryPoint GLCompute %func_1 "main"
+OpEntryPoint Vertex %func_1 "main"
+%void    = OpTypeVoid
+%void_f  = OpTypeFunction %void
+%func_1  = OpFunction %void None %void_f
+%label_1 = OpLabel
+           OpReturn
+           OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
+  EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+            ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Entry point name \"main\" is not unique, which is not allow "
+                "in WebGPU env.\n  %1 = OpFunction %void None %3\n"));
+}
+
 }  // namespace
 }  // namespace
 }  // namespace val
 }  // namespace val
 }  // namespace spvtools
 }  // namespace spvtools