Update SPIR-V Tools to dd4b663e1

Changes:
    dd4b663e1 Prepare release v2024.2 (#5651)
    be6fb2a54 build(deps): bump the github-actions group across 1 directory with 4 updates (#5650)
    dadb3012d Add SPIRV_TOOLS_EXPORT to public C++ API (#5591)
    53c073606 A fix to support of SPV_QCOM_image_processing2 (#5646)
    67a3ed670 opt: add GroupNonUniformPartitionedNV capability to trim pass (#5648)
    2904985ae spirv-val: Add Vulkan check for Rect Dim in OpTypeImage (#5644)
    02470f606 Validate duplicate decorations and execution modes (#5641)
    6761288d3 Validator: Support SPV_NV_raw_access_chains (#5568)
    3983d15a1 Fix rebuilding types with circular references (#5623). (#5637)
    ade1f7cfd Add AliasedPointer decoration (#5635)
    24f2cdad8 build(deps): bump the github-actions group with 1 update (#5634)
    58ab8baf7 docs: explain LunarG is the source of truth for releases (#5627)
    7fe5f75e5 Roll external/re2/ 6598a8ecd..917047f36 (3 commits) (#5626)
    87721a100 Roll external/spirv-headers/ 7d500c4d7..4f7b471f1 (1 commit) (#5625)
    fe7bae090 Minor fix to cmakelists to avoid rerunning command each build (#5620)
    fc4286556 build(deps): bump the github-actions group with 2 updates (#5621)
    67451ebf6 Roll external/spirv-headers/ 04db24d69..7d500c4d7 (1 commit) (#5619)
    dda7731e9 build(deps): bump the github-actions group with 2 updates (#5618)
    3fafcc20e Roll external/spirv-headers/ 8b246ff75..04db24d69 (1 commit) (#5617)
    3a0471c3b build(deps): bump the github-actions group with 1 update (#5615)
    6c3f632a2 roll deps (#5614)
    c6615779e Roll external/googletest/ b479e7a3c..c231e6f5b (1 commit) (#5613)
    f20663ca7 add support for vulkan-shader-profiler external passes (#5512)
    f74f4e74c Roll external/re2/ ed9fc269e..d00d1e937 (2 commits) (#5589)
    e39cabca2 build(deps): bump the github-actions group with 2 updates (#5610)
    efb0fce2d Use bazel 7 and bzlmod (#5601)
    02c79e908 kokoro: Update bazel to 7.0.2 for Linux builds (#5609)
    f869d391a [OPT] Fix handling of analyses rebuild (#5608)
    d15a7aa25 kokoro: Update bazel to 7.0.2 for Mac builds (#5606)
    04896c462 Prepare release v2024.1 (#5605)
    7c363050d Add operand types for SPV_NV_raw_access_chains (#5602)
    5bc7c2876 build(deps): bump the github-actions group with 2 updates (#5598)
    75ad1345d Remove redundant function declarations from source/operand.h (#5584)
    9bd44d028 Suppot for SPV_QCOM_image_processing2 (#5582)
    0b027bafa Support operand kind for SPV_INTEL_maximum_registers (#5580)
    fbc7a14b3 Fix access chain struct checks (#5592)
    99a3ad32f build(deps): bump the github-actions group with 1 update (#5594)
    c3a9ffd74 build(deps): bump the github-actions group with 1 update (#5593)
    1b643eac5 spirv-val: Make Constant evaluation consistent (#5587)
    dc6676445 Roll external/googletest/ 6eb225cb8..5df0241ea (2 commits) (#5583)
    7da2c941f Update WORKSPACE (#5588)
    16af142c1 build(deps): bump the github-actions group with 1 update (#5586)
    b0a5c4ac1 SPV_NV_shader_atomic_fp16_vector (#5581)
    55cb3989e build(deps): bump the github-actions group with 1 update (#5578)
    11afeb4bb roll deps (#5576)
    7604147c2 [OPT] Add removed unused interface var pass to legalization passes (#5579)
    f9184c650 spirv-val: Revert Validate PhysicalStorageBuffer Stage Interface (#5575)
    20ad38c18 spirv-val: Multiple interface var with same SC (#5528)
    e08c012b1 [OPT] Identify arrays with unknown length in copy prop arrays (#5570)
    56a51dd94 Roll external/spirv-headers/ e77d03080..d3c2a6fa9 (1 commit) (#5574)
    0c986f596 update image enum tests to remove Kernel capability (#5562)
    b7413609c [OPT] Use new instruction folder for for all opcodes in spec consti folding (#5569)
    784b064f9 spirv-val: Validate PhysicalStorageBuffer Stage Interface (#5539)
    a8959dc65 Fold 64-bit int operations (#5561)
    80926d97a roll deps (#5566)
    9a7b1af90 build(deps): bump the github-actions group with 1 update (#5564)
    1a2cbabd8 Roll external/googletest/ 48729681a..64be1c79f (1 commit) (#5563)
    7657cb1c6 build(deps): bump the github-actions group with 3 updates (#5560)
    032c15aaf [NFC] Refactor code to fold instruction in fold tests. (#5558)
    9938f5bc2 Roll external/googletest/ 456574145..48729681a (1 commit) (#5559)
    ab59dc608 opt: prevent meld to merge block with MaximalReconvergence (#5557)
    6c11c2bd4 Roll external/re2/ 283636ffb..ab7c5918b (2 commits) (#5555)
    a8afbe941 roll deps (#5550)
    8d3ee2e8f spirv-opt: Fix OpCompositeExtract relaxation with struct operands (#5536)
    61c51d4ba spirv-val: Add Mesh Primitive Built-In validaiton (#5529)
    5d3c8b73f opt: Add OpEntryPoint to DescriptorScalarReplacement pass (#5553)
    de65e8174 [NFC] Remove unused code (#5554)
    ad11927e6 opt: add SPV_EXT_mesh_shader to opt allowlist (#5551)
    27ffe976e build(deps): bump the github-actions group with 2 updates (#5549)
    e5fcb7fac Roll external/re2/ 264e71e88..826ad10e5 (1 commit) (#5538)
    80bc99c3d Skip entire test/ folder if SPIRV_SKIP_TESTS is set. (#5548)
    0a6f0d189 opt: Add TrimCapabilities pass to spirv-opt tool (#5545)
    b951948ea SPV_KHR_quad_control (#5547)
    69197ba90 Add modify-maximal-reconvergence to spirv-opt help (#5546)
    0045b01ff opt: Add VulkanMemoryModelDeviceScope to trim (#5544)
    ef2f43236 Add support for SPV_KHR_float_controls2 (#5543)
    de3d5acc0 Add tooling support for SPV_KHR_maximal_reconvergence (#5542)
    14000ad47 Use python3 explicitly. (#5540)
    359012927 workflow: add vulkan-sdk tags as release tags (#5518)
    3e6bdd0f9 build(deps): bump the github-actions group with 3 updates (#5537)
    ed6835aff Roll external/re2/ c042630ed..32c181e0a (1 commit) (#5532)
    c96fe8b94 spirv-val: Re-enable OpControlBarrier VU (#5527)
    5dbdc7b60 build(deps): bump the github-actions group with 4 updates (#5531)
    155728b2e Add preserver-interface option to spirv-opt (#5524)
    01ee1bf31 Roll external/googletest/ b10fad38c..76bb2afb8 (1 commit) (#5485)
    36be541ee Remove unnecessary debug code (#5523)
    c7affa170 opt: add Int16 and Float16 to capability trim pass (#5519)
    0a9f3d1f2 Revert "Fix(cmake): CMake doesn't find system installed SPIRV-Headers (#5422)" (#5517)
    7d2429594 Fix(cmake): CMake doesn't find system installed SPIRV-Headers (#5422)
    f0cc85efd Prepare release v2023.6 (#5510)
    e03c8f5c8 Fix broken build (#5505)
    d75b3cfbb Zero initialize local variables (#5501)
    6b4f0c9d0 instrument: Fix handling of gl_InvocationID (#5493)
    b5d60826e printf: Remove stage specific info (#5495)
    e7a52b70f build(deps): bump the github-actions group with 1 update (#5498)
    2da75e152 Do not crash when tryingto fold unsupported spec constant (#5496)
    0d8784553 Remove uses of std::system(nullptr) (#5494)
    f4a73dd7a std::system requires include of <cstdlib> (#5486)
    ffe645023 Add iOS build to CI (#5490)
    afaf8fda2 Fix iOS / Android CMake builds (#5482)
    7d2a618bf build(deps): bump the github-actions group with 1 update (#5484)
    2a238ed24 Roll external/spirv-headers/ 38f39dae5..cca08c63c (2 commits) (#5480)
    246e6d4c6 spirv-val: Loosen restriction on base type of DebugTypePointer and DebugTypeQualifier (#5479)
    0df791f97 Fix nullptr argument in MarkInsertChain (#5465)
    fb91e6f0e Flush stdout before changing mode back to text (#5477)
    560eea6d7 build(deps): bump the github-actions group with 1 update (#5478)
    c8510a5e8 Fix python warning seen on Fedora 39 (#5474)
    8ee3ae524 Add comment to --inst-debug-printf option (#5466)
    f43c464d5 opt: add PhysicalStorageBufferAddresses to trim (#5476)
    c91e9d09b opt: add StorageImageReadWithoutFormat to cap trim (#5475)
    d88742fbd fix(build): git describe all tagged versions (#5447)
    6b1e609ef Support missing git in update_build_version.py (#5473)
    fbf047cc8 Roll external/re2/ 24d460a9d..974f44c8d (4 commits) (#5470)
    9e7a1f2dd Fix array size calculation (#5463)
    eacc969b7 build(deps): bump the github-actions group with 2 updates (#5457)
    7210d247c Roll external/googletest/ 518387203..5b7fd63d6 (1 commit) (#5454)
    a08f648c8 Remove references to __FILE__ (#5462)
    c87755bb9 spirv-val: Add WorkgroupMemoryExplicitLayoutKHR check for Block (#5461)
    4f014aff9 Roll external/re2/ 601d9ea3e..a0b3bc60c (1 commit) (#5453)
    33bac5144 Roll external/googletest/ 116b7e552..518387203 (1 commit) (#5450)
    01e851be9 Roll external/re2/ 928a015e6..601d9ea3e (1 commit) (#5448)
    1928c76cd Roll external/googletest/ 2dd1c1319..829c19901 (1 commit) (#5444)
    73876defc opt: support 64-bit OpAccessChain index in FixStorageClass (#5446)
    5084f58e5 build(deps): bump the github-actions group with 4 updates (#5445)
    a9c61d137 update_build_version.py produce deterministic header. (#5426)
    5bb595091 Add ComputeDerivativeGroup*NV capabilities to trim capabilities pass. (#5430)
    3985f0da0 Roll external/spirv-headers/ e867c0663..4183b260f (1 commit) (#5439)
    661f429b1 Roll external/re2/ b673de358..ece4cecab (2 commits) (#5437)
    360d469b9 Prepare release v2023.5.rc1 (#5423)
    74005dfa6 Roll external/re2/ 35bb195de..b673de358 (2 commits) (#5433)
    933db564c roll deps (#5432)
    ce995b319 Hash pin workflows and config dependabot (#5412)
    df2f2a031 build(deps): bump get-func-name from 2.0.0 to 2.0.2 in /tools/sva (#5418)
    866e60def Roll external/spirv-headers/ 79743b899..e867c0663 (2 commits) (#5427)
    023a8c79e opt: add Float64 capability to trim pass (#5428)
    4fab7435b Roll external/googletest/ e47544ad3..beb552fb4 (2 commits) (#5424)
    847715d6c instrument: Ensure linking works even of nothing is changed (#5419)
    dc9900967 Update BUILD.gn to include header for new pass (#5421)
    1bc0e6f59 Add a new legalization pass to dedupe invocation interlock instructions (#5409)
    48c97c131 roll deps (#5415)
    27673a054 Remove reviewer from autoroller (#5414)
    ee7598d49 instrument: Use Import linkage for instrumentation functions (#5355)
    a40483d31 roll deps (#5408)
    a996591b1 Update SPIRV-Headers, add cache control operand kinds (#5406)
    fc54e178e Change autoroll pr review id (#5404)
    2d6996f73 Check for git repository before git commands (#5403)
    361638cfd Make sure that fragment shader interlock instructions are not removed by DCE (#5400)
    5e6054c1c Roll external/re2/ e0077036c..a807e8a3a (6 commits) (#5401)
    47b63a4d7 val: re-add ImageMSArray validation (#5394)
    d660bb55b Add SPV_KHR_physical_storage_buffer to allowlists (#5402)
    440f018cc Fix `AddMemberDecoration` variable names. (#5399)
    4e0b94ed7 opt: add ImageMSArray capability to trim pass. (#5395)
    d474a0708 Add SPV_EXT_fragment_shader_interlock to allow lists (#5393)
    1f07f483e opt: add raytracing/rayquery to trim pass (#5397)
    158bc7bd6 Roll external/re2/ 523f9b097..e0077036c (2 commits) (#5391)
    1121c2319 opt: add Int64 capability to trim pass (#5398)
    3cc7e1c4c NFC: rename tests using capability as prefix (#5396)
    4c16c35b1 opt: add FragmentShader*InterlockEXT to capability trim pass (#5390)
    9b923f7cc QNX has support for ANSI ESC codes, default terminal is QANSI. (#5387)
    51367c40f Enable OpenSSF Scorecard and Badge (#5377)
    d09c753a4 Roll external/re2/ 73031bbc0..523f9b097 (1 commit) (#5389)
    b6893ccdf Roll external/googletest/ 460ae9826..8a6feabf0 (1 commit) (#5388)
    1b3c4cb68 roll deps (#5386)
    abd548b81 roll deps (#5384)
    2601f644e Roll external/googletest/ 9fce54804..61332bd7e (2 commits) (#5383)
    714966003 opt: Add SwitchDescriptorSetPass (#5375)
    6520d83ef linker: Add --use-highest-version option (#5376)
    bfc94f63a roll deps (#5382)
    b12fc2904 Roll external/googletest/ 7e33b6a1c..987e22561 (5 commits) (#5381)
    89ca3aa57 SPV_QCOM_image_processing support (#5223)
    c55888661 Fix failing action when PR is already open. (#5380)
    0f17d05c4 opt: add bitmask support for capability trimming (#5372)
    fddcc8ced Roll external/re2/ 9dc7ae7b5..6148386f0 (3 commits) (#5379)
    7ddc65c72 Support 2 Intel extensions (#5357)
    43b888649 roll deps (#5374)
    d6300ee92 Fix -Wunreachable-code-loop-increment warning (#5373)
    8714d7fad enable StorageUniform16 (#5371)
    8e3da01b4 Move token version/cap/ext checks from parsing to validation (#5370)
    4788ff157 opt: add StorageUniformBufferBlock16 to trim pass (#5367)
    ebda56e35 opt: add StoragePushConstant16 to trim pass (#5366)
    3af4244ae Roll external/googletest/ 46db91ef6..89b25572d (1 commit) (#5365)
    60e684fe7 opt: fix StorageInputOutput16 trimming. (#5359)
    13892fe86 Roll external/googletest/ 6f6ab4212..e7fd109b5 (2 commits) (#5356)
    727f4346d docs: update references to `main` branch (#5363)
    e553b884c Prepare release for v2023.4.rc2 (#5362)
    4a9881fe9 Use absolute path to depot_tools (#5360)
    09b76c23e Update SPIRV-Headers; test some coop matrix enums (#5361)
    1d14d84f2 opt: fix missing CreateTrimCapabilitiesPass definition (#5353)
    47fff21d5 instrument: Reduce number of inst_bindless_stream_write_6 calls (#5327)
    02cd71d41 roll deps (#5352)
    e68fe9be4 Add SPV_EXT_shader_atomic_float_add to allow lists (#5348)
    c6d0b0480 build: fix missing files in BUILD.gn (#5351)
    b5f600c08 Roll external/googletest/ 01e18376e..40412d851 (1 commit) (#5347)
    a0f1c8727 opt: Fix incorrect half float conversion (#5349)
    35d8b05de opt: add capability trimming pass (not default). (#5278)
    ec90d2872 roll deps (#5345)
    d52c39c37 Do not crash when folding 16-bit OpFDiv (#5338)
    17d9669d5 enumset: add iterator based constructor/insert (#5344)
    daad2295c Roll external/googletest/ cc366710b..d66ce5851 (2 commits) (#5337)
    45f7e55af Bump word-wrap from 1.2.3 to 1.2.4 in /tools/sva (#5343)
    bf03d4092 opt: change Get* functions to return const& (#5331)
    876ccc6cd Add /bigobj to test_opt for VS 2017 (#5336)
    c50bc49f5 Fix link flags for Clang-based MinGW cross compile (#5342)
    2813da268 kokoro: rename glslang (#5339)
    883417544 Set cmake_policy CMP0128 (#5341)
    6c7e1acc5 NFC: fix missing algorithm include in enumset file (#5334)
    61221e7d6 Add python3 requirement for the script (#5326)
    4b6bd5a66 Prepare release v2023.4 (#5330)
    9e0b780ff Create SECURITY.md (#5325)
    7dd5f95d2 [spirv-opt] Handle OpFunction in GetPtr (#5316)
    6add9ccf0 Add support for LiteralFloat type (#5323)
    85a448213 NFC: makes the FeatureManager immutable for users (#5329)
    29431859f NFC: replace EnumSet::ForEach with range-based-for (#5322)
    d6b9389f6 Roll external/spirv-headers/ d0006a393..f1ba373ef (2 commits) (#5320)
    5b4fb072e enumset: fix bug in the new iterator class (#5321)
    9ab811a12 NFC: fix missing comments on functions (#5318)
    9266197c3 instrument: Cast gl_VertexIndex and InstanceIndex to uint (#5319)
    ee50fa7d8 Roll external/googletest/ 4a1a299b2..cc366710b (1 commit) (#5317)
    3424b16c1 enumset: STL-ize container (#5311)
    7ff331af6 source: Give better message if using new Source Language (#5314)
    abcd228d9 Update README to say Android NDK r25c is required (#5312)
    0530a532f Validate GroupNonUniform instructions (#5296)
    4594ffce9 Roll external/re2/ a57a1d646..e66463312 (1 commit) (#5313)
    4be7d0e3c Use android ndk r25 (#5309)
    e751c7e7d Treat spir-v.xml as utf-8 (#5306)
    0f3bea06e NFC: rewrite EnumSet to handle larger enums. (#5289)
    870fd1e17 spirv-val: Label SPV_KHR_cooperative_matrix VUID (#5301)
    a1e8fff14 Roll external/re2/ 2d39b703d..1c1ffbe3c (1 commit) (#5304)
    58459c2b1 roll deps (#5300)
    d3b0a522c Roll external/googletest/ 687c58994..251e72039 (1 commit) (#5299)
    ea5af2fb5 roll deps (#5297)
    f83f50d23 Roll external/googletest/ ec4fed932..8e32de89c (2 commits) (#5294)
    7520bfa6b build: remove last references of c++11 (#5295)
    e090ce9c4 Update CMakeLists.txt (#5293)
    bfb40a240 fix ndk build standard to c++17 (#5290)
    310a67020 Validate layouts for PhysicalStorageBuffer pointers (#5291)
    c640b1934 Update CMakeLists.txt (#5288)
    cfb99efd7 Roll external/googletest/ af39146b4..ec4fed932 (1 commit) (#5287)
    04cdb2d34 SPV_KHR_cooperative_matrix (#5286)
    16098b3c1 Have effcee add abseil subdirectory (#5281)
    daee1e7d3 instrument: Combine descriptor length and init state checking (#5274)
    a68ef7b2c cmake: Remove unused SPIRV-Headers variables (#5284)
    b12c0fe6f Roll external/googletest/ fb11778f4..af39146b4 (1 commit) (#5285)
    54691dcd7 Migrate `exec_tools` back to `tools`. (#5280)
    a6b57f2f0 Roll external/googletest/ 9b12f749f..fb11778f4 (4 commits) (#5279)
    a63ac9f73 cmake: Use modern Python3 CMake support (#5277)
    951980e5a Enable vector constant folding (#4913) (#5272)
    a720a6926 Roll external/googletest/ 18fa6a4db..9b12f749f (1 commit) (#5276)
    6b9fc7933 Fold negation of integer vectors (#5269)
    285f6cefa roll deps (#5273)
    d33bea584 instrument: Fix buffer address length calculations (#5257)
    b4f352e54 Expose preserve_interface in Optimizer::Register*Passes. (#5268)
    40dde04ca Roll external/googletest/ 65cfeca1a..e9078161e (1 commit) (#5267)
    6d0e3cf6a Roll external/googletest/ 334704df2..65cfeca1a (1 commit) (#5265)
    9c66587d1 spirv-diff: Update test expectations (#5264)
    ae1843b67 spirv-diff: Leave undefined ids unpaired. (#5262)
    93c13345e spirv-diff: Properly match SPV_KHR_ray_query types. (#5259)
    9da026922 roll deps (#5263)
    1d7dec3c5 Use windows 2019 to workaround bazel issue (#5261)
    59b4febd8 Allow OpTypeBool in UniformConstant (#5237)
    5ed21eb1e Add folding rule for OpTranspose (#5241)
    ec244c859 Increase tested Android API level (#5253)
    c7e436921 roll deps (#5243)
    182fd9ebc Allow physical storage buffer pointer in IO (#5251)
    226c3bbe6 Fix broken link in README (#5250)
    9ed2ac257 Fix pairing of function parameters. (#5225)
    8841d560c Add c++ version to .bazelrc (#5247)
    cf62673e4 Error for invalid location type (#5249)
    673d8bfcb Checkout abseil in the smoketest (#5248)
    06bbd7f53 Update deps in sva (#5246)
    23cb9b96c spirv-val: Remove VUID from 1.3.251 spec (#5244)
    1021ec302 Add Abseil dep to the README (#5242)
    3e82fa067 Revert "Disable RE2 autoroll (#5234)" (#5239)
    e0936b646 Roll external/spirv-headers/ bdbfd019b..69155b22b (1 commit) (#5238)
    af27ece75 Check if const is zero before getting components. (#5217)
    235800182 Add Abseil as a dep and update RE2 (#5236)
    f29e11dcb diff: Don't give up entry point matching too early. (#5224)
    82b1a87b2 Add SPV_NV_bindless_texture to spirv optimizations (#5231)
    60c546f3f Roll external/googletest/ bc860af08..bb2941fcc (1 commit) (#5220)
    dcfea36ab Have the macos bazel build us git-sync-deps (#5235)
    44c9da6fe Remove const zero image operands (#5232)
    e357a36cc Disable RE2 autoroll (#5234)
    e7c6084fd Prepare release 2023.3 (#5222)
    17a26b45f Improve an error message in the assembler (#5219)
    7c39951f6 spirv-val: Label Interface Location/Component VUIDs (#5221)

Commands:
    ./third_party/update-spirvtools.sh

Bug: b/123642959
Change-Id: I4e497c6d70e17beb10e859266dbfa905d1f99136
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/73373
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Tested-by: Romaric Jodin <rjodin@chromium.org>
Presubmit-Ready: Romaric Jodin <rjodin@chromium.org>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/third_party/SPIRV-Tools/.bazelrc b/third_party/SPIRV-Tools/.bazelrc
new file mode 100644
index 0000000..79ad594
--- /dev/null
+++ b/third_party/SPIRV-Tools/.bazelrc
@@ -0,0 +1,7 @@
+# Enable Bzlmod for every Bazel command
+common --enable_bzlmod
+
+build --enable_platform_specific_config
+build:linux --cxxopt=-std=c++17
+build:macos --cxxopt=-std=c++17
+build:windows --cxxopt=/std:c++17
diff --git a/third_party/SPIRV-Tools/.bazelversion b/third_party/SPIRV-Tools/.bazelversion
index 0062ac9..a8907c0 100644
--- a/third_party/SPIRV-Tools/.bazelversion
+++ b/third_party/SPIRV-Tools/.bazelversion
@@ -1 +1 @@
-5.0.0
+7.0.2
diff --git a/third_party/SPIRV-Tools/.github/dependabot.yml b/third_party/SPIRV-Tools/.github/dependabot.yml
new file mode 100644
index 0000000..dca857a
--- /dev/null
+++ b/third_party/SPIRV-Tools/.github/dependabot.yml
@@ -0,0 +1,25 @@
+# Copyright 2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+version: 2
+updates:
+  - package-ecosystem: github-actions
+    directory: /
+    schedule:
+      interval: daily
+    groups:
+      github-actions:
+        patterns:
+          - "*"
+    open-pull-requests-limit: 3
diff --git a/third_party/SPIRV-Tools/.github/workflows/autoroll.yml b/third_party/SPIRV-Tools/.github/workflows/autoroll.yml
index 4520309..ed33622 100644
--- a/third_party/SPIRV-Tools/.github/workflows/autoroll.yml
+++ b/third_party/SPIRV-Tools/.github/workflows/autoroll.yml
@@ -16,14 +16,14 @@
     runs-on: ubuntu-latest
 
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
 
       # Checkout the depot tools they are needed by roll_deps.sh
       - name: Checkout depot tools
         run: git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
 
       - name: Update PATH
-        run: echo "./depot_tools" >> $GITHUB_PATH
+        run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
 
       - name: Download dependencies
         run: python3 utils/git-sync-deps
@@ -47,6 +47,10 @@
         if: steps.update_dependencies.outputs.changed == 'true'
         run: |
           git push --force --set-upstream origin roll_deps
-          gh pr create --label 'kokoro:run' --base main -f -r s-perron
+          # Create a PR. If it aready exists, the command fails, so ignore the return code.
+          gh pr create --base main -f || true 
+          # Add the 'kokoro:run' label so that the kokoro tests will be run.
+          gh pr edit --add-label 'kokoro:run'
+          gh pr merge --auto --squash
         env:
           GITHUB_TOKEN: ${{ github.token }}
diff --git a/third_party/SPIRV-Tools/.github/workflows/bazel.yml b/third_party/SPIRV-Tools/.github/workflows/bazel.yml
index 88700c4..43c99d6 100644
--- a/third_party/SPIRV-Tools/.github/workflows/bazel.yml
+++ b/third_party/SPIRV-Tools/.github/workflows/bazel.yml
@@ -13,30 +13,22 @@
     timeout-minutes: 120
     strategy:
       matrix:
-        os: [ubuntu-latest, macos-latest, windows-latest]
+        os: [ubuntu-latest, macos-latest, windows-2019]
 
     runs-on: ${{matrix.os}}
 
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
         with:
           fetch-depth: '0'
       - name: Download dependencies
         run: python3 utils/git-sync-deps
       - name: Mount Bazel cache
-        uses: actions/cache@v3
+        uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
         with:
           path: ~/.bazel/cache
           key: bazel-cache-${{ runner.os }}
-      - name: Build All (Windows)
-        if: ${{matrix.os == 'windows-latest' }}
-        run: bazel --output_user_root=~/.bazel/cache build --cxxopt=/std:c++17 //...
-      - name: Test All (Windows)
-        if: ${{matrix.os == 'windows-latest' }}
-        run: bazel --output_user_root=~/.bazel/cache test --cxxopt=/std:c++17 //...
-      - name: Build All (Linux, MacOS)
-        if: ${{ matrix.os != 'windows-latest' }}
-        run: bazel --output_user_root=~/.bazel/cache build --cxxopt=-std=c++17 //...
-      - name: Test All (Linux, MacOS)
-        if: ${{ matrix.os != 'windows-latest' }}
-        run: bazel --output_user_root=~/.bazel/cache test --cxxopt=-std=c++17 //...
+      - name: Build All
+        run: bazel --output_user_root=~/.bazel/cache build //...
+      - name: Test All
+        run: bazel --output_user_root=~/.bazel/cache test //...
diff --git a/third_party/SPIRV-Tools/.github/workflows/ios.yml b/third_party/SPIRV-Tools/.github/workflows/ios.yml
new file mode 100644
index 0000000..feb64a7
--- /dev/null
+++ b/third_party/SPIRV-Tools/.github/workflows/ios.yml
@@ -0,0 +1,30 @@
+name: iOS
+permissions:
+  contents: read
+
+on: [push, pull_request, workflow_dispatch]
+
+jobs:
+  build:
+    runs-on: ${{ matrix.os }}
+    strategy:
+        matrix:
+          os: [ macos-12, macos-13 ]
+    steps:
+        - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
+        - uses: lukka/get-cmake@4931ab1fc1604964c055eb330edb3f6b26ba0cfa # v3.29.2
+        - name: Download dependencies
+          run: python3 utils/git-sync-deps
+        # NOTE: The MacOS SDK ships universal binaries. CI should reflect this.
+        - name: Configure Universal Binary for iOS
+          run: |
+            cmake -S . -B build \
+            -D CMAKE_BUILD_TYPE=Debug \
+            -D CMAKE_SYSTEM_NAME=iOS \
+            "-D CMAKE_OSX_ARCHITECTURES=arm64;x86_64" \
+            -G Ninja
+          env:
+            # Linker warnings as errors
+            LDFLAGS: -Wl,-fatal_warnings
+        - run: cmake --build build
+        - run: cmake --install build --prefix /tmp
diff --git a/third_party/SPIRV-Tools/.github/workflows/release.yml b/third_party/SPIRV-Tools/.github/workflows/release.yml
index ada9431..583c8f1 100644
--- a/third_party/SPIRV-Tools/.github/workflows/release.yml
+++ b/third_party/SPIRV-Tools/.github/workflows/release.yml
@@ -6,13 +6,14 @@
   push:
     tags:
       - 'v[0-9]+.[0-9]+'
+      - 'vulkan-sdk-[0-9]+.[0-9]+.[0-9]+.[0-9]+'
       - '!v[0-9]+.[0-9]+.rc*'
 
 jobs:
   prepare-release-job:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
       - name: Prepare CHANGELOG for version
         run: |
           python utils/generate_changelog.py CHANGES "${{ github.ref_name }}" VERSION_CHANGELOG
diff --git a/third_party/SPIRV-Tools/.github/workflows/scorecard.yml b/third_party/SPIRV-Tools/.github/workflows/scorecard.yml
new file mode 100644
index 0000000..adcfa76
--- /dev/null
+++ b/third_party/SPIRV-Tools/.github/workflows/scorecard.yml
@@ -0,0 +1,53 @@
+name: Scorecard supply-chain security
+on:
+  # For Branch-Protection check. Only the default branch is supported. See
+  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
+  branch_protection_rule:
+  # To guarantee Maintained check is occasionally updated. See
+  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
+  schedule:
+    - cron: '36 17 * * 5'
+  push:
+    branches: [ "main" ]
+
+# Declare default permissions as read only.
+permissions: read-all
+
+jobs:
+  analysis:
+    name: Scorecard analysis
+    runs-on: ubuntu-latest
+    permissions:
+      security-events: write # to upload the results to code-scanning dashboard
+      id-token: write # to publish results and get a badge
+
+    steps:
+      - name: "Checkout code"
+        uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
+        with:
+          persist-credentials: false
+
+      - name: "Run analysis"
+        uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
+        with:
+          results_file: results.sarif
+          results_format: sarif
+          # To enable Branch-Protection uncomment the `repo_token` line below
+          # To create the Fine-grained PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-fine-grained-pat-optional.
+          # repo_token: ${{ secrets.SCORECARD_TOKEN }}
+          publish_results: true # allows the repo to include the Scorecard badge
+
+      # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
+      # format to the repository Actions tab.
+      - name: "Upload artifact"
+        uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2
+        with:
+          name: SARIF file
+          path: results.sarif
+          retention-days: 5
+
+      # Upload the results to GitHub's code scanning dashboard.
+      - name: "Upload to code-scanning"
+        uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
+        with:
+          sarif_file: results.sarif
diff --git a/third_party/SPIRV-Tools/.github/workflows/wasm.yml b/third_party/SPIRV-Tools/.github/workflows/wasm.yml
index 62c9af3..6807b3d 100644
--- a/third_party/SPIRV-Tools/.github/workflows/wasm.yml
+++ b/third_party/SPIRV-Tools/.github/workflows/wasm.yml
@@ -9,7 +9,7 @@
     runs-on: ubuntu-latest
 
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
         with:
           fetch-depth: '0'
       - name: Build web
diff --git a/third_party/SPIRV-Tools/.gitignore b/third_party/SPIRV-Tools/.gitignore
index ec709ba..e85cea9 100644
--- a/third_party/SPIRV-Tools/.gitignore
+++ b/third_party/SPIRV-Tools/.gitignore
@@ -4,6 +4,7 @@
 compile_commands.json
 /build*/
 /buildtools/
+/external/abseil_cpp/
 /external/googletest
 /external/SPIRV-Headers
 /external/spirv-headers
@@ -22,6 +23,7 @@
 bazel-spirv-tools
 bazel-SPIRV-Tools
 bazel-testlogs
+MODULE.bazel.lock
 
 # Vim
 [._]*.s[a-w][a-z]
diff --git a/third_party/SPIRV-Tools/BUILD.bazel b/third_party/SPIRV-Tools/BUILD.bazel
index ae7f35c..48a688e 100644
--- a/third_party/SPIRV-Tools/BUILD.bazel
+++ b/third_party/SPIRV-Tools/BUILD.bazel
@@ -58,6 +58,8 @@
 
 generate_vendor_tables(extension = "nonsemantic.clspvreflection")
 
+generate_vendor_tables(extension = "nonsemantic.vkspreflection")
+
 generate_vendor_tables(
     extension = "opencl.debuginfo.100",
     operand_kind_prefix = "CLDEBUG100_",
@@ -94,7 +96,7 @@
     outs = ["generators.inc"],
     cmd = "$(location :generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)",
     cmd_bat = "$(location :generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)",
-    exec_tools = [":generate_registry_tables"],
+    tools = [":generate_registry_tables"],
 )
 
 py_binary(
@@ -108,10 +110,8 @@
     outs = ["build-version.inc"],
     cmd = "SOURCE_DATE_EPOCH=0 $(location :update_build_version) $(location CHANGES) $(location build-version.inc)",
     cmd_bat = "set SOURCE_DATE_EPOCH=0  && $(location :update_build_version) $(location CHANGES) $(location build-version.inc)",
-    # This is explicitly tools and not exec_tools because we run it locally (on the host platform) instead of
-    # (potentially remotely) on the execution platform.
-    tools = [":update_build_version"],
     local = True,
+    tools = [":update_build_version"],
 )
 
 # Libraries
@@ -146,15 +146,16 @@
         ":gen_extinst_lang_headers_OpenCLDebugInfo100",
         ":gen_glsl_tables_unified1",
         ":gen_opencl_tables_unified1",
-        ":generators_inc",
         ":gen_vendor_tables_debuginfo",
         ":gen_vendor_tables_nonsemantic_clspvreflection",
+        ":gen_vendor_tables_nonsemantic_vkspreflection",
         ":gen_vendor_tables_nonsemantic_shader_debuginfo_100",
         ":gen_vendor_tables_opencl_debuginfo_100",
         ":gen_vendor_tables_spv_amd_gcn_shader",
         ":gen_vendor_tables_spv_amd_shader_ballot",
         ":gen_vendor_tables_spv_amd_shader_explicit_vertex_parameter",
         ":gen_vendor_tables_spv_amd_shader_trinary_minmax",
+        ":generators_inc",
     ],
     hdrs = [
         "include/spirv-tools/libspirv.h",
@@ -307,17 +308,17 @@
 cc_binary(
     name = "spirv-objdump",
     srcs = [
-        "tools/objdump/objdump.cpp",
         "tools/objdump/extract_source.cpp",
         "tools/objdump/extract_source.h",
+        "tools/objdump/objdump.cpp",
     ],
     copts = COMMON_COPTS,
     visibility = ["//visibility:public"],
     deps = [
-        ":tools_io",
-        ":tools_util",
         ":spirv_tools_internal",
         ":spirv_tools_opt_internal",
+        ":tools_io",
+        ":tools_util",
         "@spirv_headers//:spirv_cpp_headers",
     ],
 )
@@ -428,7 +429,7 @@
     copts = TEST_COPTS,
     deps = [
         ":spirv_tools_internal",
-        "@com_google_googletest//:gtest",
+        "@googletest//:gtest",
     ],
 )
 
@@ -439,23 +440,25 @@
     name = "base_{testcase}_test".format(testcase = f[len("test/"):-len("_test.cpp")]),
     size = "small",
     srcs = [f],
-    copts = TEST_COPTS + ['-DTESTING'],
+    copts = TEST_COPTS + ["-DTESTING"],
     linkstatic = 1,
     target_compatible_with = {
         "test/timer_test.cpp": incompatible_with(["@bazel_tools//src/conditions:windows"]),
     }.get(f, []),
     deps = [
+        "tools_util",
         ":spirv_tools_internal",
         ":test_lib",
-        "tools_util",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 ) for f in glob(
-    ["test/*_test.cpp", "test/tools/*_test.cpp"],
+    [
+        "test/*_test.cpp",
+        "test/tools/*_test.cpp",
+    ],
     exclude = [
         "test/cpp_interface_test.cpp",
-        "test/log_test.cpp",
         "test/pch_test.cpp",
     ],
 )]
@@ -467,8 +470,8 @@
     linkstatic = 1,
     deps = [
         ":spirv_tools_opt_internal",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
         "@spirv_headers//:spirv_cpp11_headers",
     ],
 )
@@ -481,21 +484,8 @@
     linkstatic = 1,
     deps = [
         ":spirv_tools_internal",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
-    ],
-)
-
-cc_test(
-    name = "base_log_test",
-    size = "small",
-    srcs = ["test/log_test.cpp"],
-    copts = TEST_COPTS,
-    linkstatic = 1,
-    deps = [
-        ":spirv_tools_opt_internal",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 )
 
@@ -521,8 +511,8 @@
     linkstatic = 1,
     deps = [
         ":link_test_lib",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 ) for f in glob(
     ["test/link/*_test.cpp"],
@@ -538,8 +528,8 @@
         ":spirv_tools",
         ":spirv_tools_lint_internal",
         ":spirv_tools_opt_internal",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 ) for f in glob(
     ["test/lint/*_test.cpp"],
@@ -563,7 +553,7 @@
         ":spirv_tools_internal",
         ":spirv_tools_opt_internal",
         "@com_google_effcee//:effcee",
-        "@com_google_googletest//:gtest",
+        "@googletest//:gtest",
     ],
 )
 
@@ -579,8 +569,8 @@
         ":spirv_tools_opt_internal",
         ":test_lib",
         "@com_google_effcee//:effcee",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 ) for f in glob(["test/opt/*_test.cpp"])]
 
@@ -593,8 +583,8 @@
     deps = [
         ":opt_test_lib",
         ":spirv_tools_opt_internal",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 ) for f in glob(
     ["test/opt/dominator_tree/*.cpp"],
@@ -612,8 +602,8 @@
         ":spirv_tools",
         ":spirv_tools_opt_internal",
         "@com_google_effcee//:effcee",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 ) for f in glob(
     ["test/opt/loop_optimizations/*.cpp"],
@@ -634,7 +624,7 @@
         ":spirv_tools_reduce",
         ":test_lib",
         ":tools_io",
-        "@com_google_googletest//:gtest",
+        "@googletest//:gtest",
     ],
 )
 
@@ -649,7 +639,7 @@
         ":spirv_tools_internal",
         ":spirv_tools_opt_internal",
         ":spirv_tools_reduce",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest_main",
     ],
 ) for f in glob(["test/reduce/*_test.cpp"])]
 
@@ -661,8 +651,8 @@
     linkstatic = 1,
     deps = [
         ":spirv_tools_internal",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 ) for f in glob(["test/util/*_test.cpp"])]
 
@@ -693,8 +683,8 @@
         ":spirv_tools_internal",
         ":test_lib",
         ":val_test_lib",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 ) for f in glob(
     ["test/val/val_*_test.cpp"],
@@ -715,8 +705,8 @@
         ":spirv_tools_internal",
         ":test_lib",
         ":val_test_lib",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 )
 
@@ -732,7 +722,7 @@
     deps = [
         ":test_lib",
         ":val_test_lib",
-        "@com_google_googletest//:gtest",
-        "@com_google_googletest//:gtest_main",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
     ],
 )
diff --git a/third_party/SPIRV-Tools/BUILD.gn b/third_party/SPIRV-Tools/BUILD.gn
index e8622a1..4848fdd 100644
--- a/third_party/SPIRV-Tools/BUILD.gn
+++ b/third_party/SPIRV-Tools/BUILD.gn
@@ -331,6 +331,10 @@
     "...nil...",
   ],
   [
+    "nonsemantic.vkspreflection",
+    "...nil...",
+  ],
+  [
     "nonsemantic.shader.debuginfo.100",
     "SHDEBUG100_",
   ],
@@ -696,6 +700,8 @@
     "source/opt/interface_var_sroa.h",
     "source/opt/interp_fixup_pass.cpp",
     "source/opt/interp_fixup_pass.h",
+    "source/opt/invocation_interlock_placement_pass.cpp",
+    "source/opt/invocation_interlock_placement_pass.h",
     "source/opt/ir_builder.h",
     "source/opt/ir_context.cpp",
     "source/opt/ir_context.h",
@@ -738,6 +744,8 @@
     "source/opt/mem_pass.h",
     "source/opt/merge_return_pass.cpp",
     "source/opt/merge_return_pass.h",
+    "source/opt/modify_maximal_reconvergence.cpp",
+    "source/opt/modify_maximal_reconvergence.h",
     "source/opt/module.cpp",
     "source/opt/module.h",
     "source/opt/null_pass.h",
@@ -792,7 +800,11 @@
     "source/opt/strip_nonsemantic_info_pass.h",
     "source/opt/struct_cfg_analysis.cpp",
     "source/opt/struct_cfg_analysis.h",
+    "source/opt/switch_descriptorset_pass.cpp",
+    "source/opt/switch_descriptorset_pass.h",
     "source/opt/tree_iterator.h",
+    "source/opt/trim_capabilities_pass.cpp",
+    "source/opt/trim_capabilities_pass.h",
     "source/opt/type_manager.cpp",
     "source/opt/type_manager.h",
     "source/opt/types.cpp",
diff --git a/third_party/SPIRV-Tools/CHANGES b/third_party/SPIRV-Tools/CHANGES
index dbe31a0..102703a 100644
--- a/third_party/SPIRV-Tools/CHANGES
+++ b/third_party/SPIRV-Tools/CHANGES
@@ -1,5 +1,150 @@
 Revision history for SPIRV-Tools
 
+v2024.2 2024-04-22
+  - General
+    - Add SPIRV_TOOLS_EXPORT to public C++ API (#5591)
+    - Use bazel 7 and bzlmod (#5601)
+  - Optimizer
+    - opt: add GroupNonUniformPartitionedNV capability to trim pass (#5648)
+    - Fix rebuilding types with circular references. (#5637)
+    - Add AliasedPointer decoration (#5635)
+    - add support for vulkan-shader-profiler external passes (#5512)
+  - Validator
+    - A fix to support of SPV_QCOM_image_processing2 (#5646)
+    - spirv-val: Add Vulkan check for Rect Dim in OpTypeImage (#5644)
+    - Validate duplicate decorations and execution modes (#5641)
+    - Validator: Support SPV_NV_raw_access_chains (#5568)
+
+v2024.1 2024-03-06
+  - General
+    - Add tooling support for SPV_KHR_maximal_reconvergence (#5542)
+    - Add support for SPV_KHR_float_controls2 (#5543)
+    - SPV_KHR_quad_control (#5547)
+    - Fold 64-bit int operations (#5561)
+    - update image enum tests to remove Kernel capability (#5562)
+    - Support operand kind for SPV_INTEL_maximum_registers (#5580)
+    - SPV_NV_shader_atomic_fp16_vector (#5581)
+    - Support for SPV_QCOM_image_processing2 (#5582)
+    - Fix access chain struct checks (#5592)
+  - Optimizer
+    - opt: add Int16 and Float16 to capability trim pass (#5519)
+    - Add preserver-interface option to spirv-opt (#5524)
+    - spirv-opt: Fix OpCompositeExtract relaxation with struct operands (#5536)
+    - opt: Add VulkanMemoryModelDeviceScope to trim (#5544)
+    - opt: Add TrimCapabilities pass to spirv-opt tool (#5545)
+    - Add modify-maximal-reconvergence to spirv-opt help (#5546)
+    - opt: add SPV_EXT_mesh_shader to opt allowlist (#5551)
+    - opt: Add OpEntryPoint to DescriptorScalarReplacement pass (#5553)
+    - opt: prevent meld to merge block with MaximalReconvergence (#5557)
+    - [OPT] Use new instruction folder for for all opcodes in spec consti folding (#5569)
+    - [OPT] Identify arrays with unknown length in copy prop arrays (#5570)
+    - [OPT] Add removed unused interface var pass to legalization passes (#5579)
+  - Validator
+    - spirv-val: Re-enable OpControlBarrier VU (#5527)
+    - spirv-val: Add Mesh Primitive Built-In validaiton (#5529)
+    - spirv-val: Validate PhysicalStorageBuffer Stage Interface (#5539)
+    - spirv-val: Multiple interface var with same SC (#5528)
+    - spirv-val: Revert Validate PhysicalStorageBuffer Stage Interface (#5575)
+    - spirv-val: Make Constant evaluation consistent (#5587)
+
+v2023.6 2023-12-18
+  - General
+    - update_build_version.py produce deterministic header. (#5426)
+    - Support missing git in update_build_version.py (#5473)
+  - Optimizer
+    - Add ComputeDerivativeGroup*NV capabilities to trim capabilities pass. (#5430)
+    - Do not crash when tryingto fold unsupported spec constant (#5496)
+    - instrument: Fix handling of gl_InvocationID (#5493)
+    - Fix nullptr argument in MarkInsertChain (#5465)
+    - opt: support 64-bit OpAccessChain index in FixStorageClass (#5446)
+    - opt: add StorageImageReadWithoutFormat to cap trim (#5475)
+    - opt: add PhysicalStorageBufferAddresses to trim (#5476)
+    - Fix array size calculation (#5463
+  - Validator
+    - spirv-val: Loosen restriction on base type of DebugTypePointer and DebugTypeQualifier (#5479)
+    - spirv-val: Add WorkgroupMemoryExplicitLayoutKHR check for Block (#5461)
+
+v2023.5 2023-10-15
+  - General
+    - Support 2 Intel extensions (#5357)
+    - SPV_QCOM_image_processing support (#5223)
+  - Optimizer
+    - opt: fix StorageInputOutput16 trimming. (#5359)
+    - opt: add StoragePushConstant16 to trim pass (#5366)
+    - opt: enable StorageUniform16 (#5371)
+    - opt: add bitmask support for capability trimming (#5372)
+    - opt: Add SwitchDescriptorSetPass (#5375)
+    - opt: add FragmentShader*InterlockEXT to capability trim pass (#5390)
+    - opt: add Int64 capability to trim pass (#5398)
+    - opt: add Float64 capability to trim pass (#5428)
+    - opt: add raytracing/rayquery to trim pass (#5397)
+    - opt: add ImageMSArray capability to trim pass. (#5395)
+    - Add SPV_KHR_physical_storage_buffer to allowlists (#5402)
+    - Add SPV_EXT_fragment_shader_interlock to allow lists (#5393)
+    - Make sure that fragment shader interlock instructions are not removed by DCE (#5400)
+    - instrument: Use Import linkage for instrumentation functions (#5355)
+    - Add a new legalization pass to dedupe invocation interlock instructions (#5409)
+    - instrument: Ensure linking works even of nothing is changed (#5419)
+  - Validator
+    - Move token version/cap/ext checks from parsing to validation (#5370)
+    - val: re-add ImageMSArray validation (#5394)
+  - Linker
+    - linker: Add --use-highest-version option
+
+v2023.4 2023-07-17
+  - General
+    - Set cmake_policy CMP0128 (#5341)
+    - Add python3 requirement for the script (#5326)
+    - Add support for LiteralFloat type (#5323)
+    - SPV_KHR_cooperative_matrix (#5286)
+    - Allow OpTypeBool in UniformConstant (#5237)
+    - Allow physical storage buffer pointer in IO (#5251)
+    - Remove const zero image operands (#5232)
+  - Optimizer
+    - Enable vector constant folding (#4913) (#5272)
+    - Fold negation of integer vectors (#5269)
+    - Add folding rule for OpTranspose (#5241)
+    - Add SPV_NV_bindless_texture to spirv optimizations (#5231)
+    - Fix incorrect half float conversion (#5349)
+    - Add SPV_EXT_shader_atomic_float_add to allow lists (#5348)
+  - Instrument
+    - instrument: Cast gl_VertexIndex and InstanceIndex to uint (#5319)
+    - instrument: Fix buffer address length calculations (#5257)
+    - instrument: Reduce number of inst_bindless_stream_write_6 calls (#5327)
+  - Validator
+    - Validate GroupNonUniform instructions (#5296)
+    - spirv-val: Label SPV_KHR_cooperative_matrix VUID (#5301)
+    - Validate layouts for PhysicalStorageBuffer pointers (#5291)
+    - spirv-val: Remove VUID from 1.3.251 spec (#5244)
+  - Diff
+    - spirv-diff: Update test expectations (#5264)
+    - spirv-diff: Leave undefined ids unpaired. (#5262)
+    - spirv-diff: Properly match SPV_KHR_ray_query types. (#5259)
+    - diff: Don't give up entry point matching too early. (#5224)
+
+v2023.3 2023-05-15
+  - General
+    - Update spirv_headers to include SPV_KHR_ray_tracing_position_fetch (#5205)
+    - spirv-tools: Add support for QNX (#5211)
+    - build: set std=c++17 for BUILD.gn (#5162)
+  - Optimizer
+    - Run ADCE when the printf extension is used. (#5215)
+    - Don't convert struct members to half (#5201)
+    - Apply scalar replacement on vars with Pointer decorations (#5208)
+    - opt: Fix null deref in OpMatrixTimesVector and OpVectorTimesMatrix (#5199)
+    - instrument: Add set and binding to bindless error records (#5204)
+    - instrument: Change descriptor state storage format (#5178)
+    - Fix LICMPass (#5087)
+    - Add Vulkan memory model to allow lists (#5173)
+    - Do not remove control barrier after spv1.3 (#5174)
+  - Validator
+    - spirv-val: Label Interface Location/Component VUIDs (#5221)
+    - Add support for SPV_EXT_shader_tile_image (#5188)
+    - Fix vector OpConstantComposite type validation (#5191)
+    - spirv-val: Label new Vulkan VUID 07951 (#5154)
+  - Fuzz
+    - Do not define GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE if it is already defined. (#5200)
+
 v2023.2 2023-03-10
   - General
     - build: move from c++11 to c++17 (#4983)
diff --git a/third_party/SPIRV-Tools/CMakeLists.txt b/third_party/SPIRV-Tools/CMakeLists.txt
index 71cdc00..0ba173f 100644
--- a/third_party/SPIRV-Tools/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/CMakeLists.txt
@@ -16,6 +16,16 @@
 
 project(spirv-tools)
 
+# Avoid a bug in CMake 3.22.1. By default it will set -std=c++11 for
+# targets in test/*, when those tests need -std=c++17.
+# https://github.com/KhronosGroup/SPIRV-Tools/issues/5340
+# The bug is fixed in CMake 3.22.2
+if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.22.1")
+  if (${CMAKE_VERSION} VERSION_LESS "3.22.2")
+    cmake_policy(SET CMP0128 NEW)
+  endif()
+endif()
+
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 enable_testing()
@@ -53,6 +63,8 @@
   add_definitions(-DSPIRV_IOS)
 elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "tvOS")
   add_definitions(-DSPIRV_TVOS)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "visionOS")
+  add_definitions(-DSPIRV_VISIONOS)
 elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
   add_definitions(-DSPIRV_ANDROID)
   set(SPIRV_TIMER_ENABLED ${SPIRV_ALLOW_TIMERS})
@@ -231,7 +243,7 @@
   # For MinGW cross compile, statically link to the C++ runtime.
   # But it still depends on MSVCRT.dll.
   if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
-    if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
+    if (NOT MSVC)
       set_target_properties(${TARGET} PROPERTIES
         LINK_FLAGS -static -static-libgcc -static-libstdc++)
     endif()
@@ -250,7 +262,7 @@
 endif()
 
 # Tests require Python3
-find_host_package(PythonInterp 3 REQUIRED)
+find_host_package(Python3 REQUIRED)
 
 # Check for symbol exports on Linux.
 # At the moment, this check will fail on the OSX build machines for the Android NDK.
@@ -259,7 +271,7 @@
   macro(spvtools_check_symbol_exports TARGET)
     if (NOT "${SPIRV_SKIP_TESTS}")
       add_test(NAME spirv-tools-symbol-exports-${TARGET}
-               COMMAND ${PYTHON_EXECUTABLE}
+               COMMAND Python3::Interpreter
                ${spirv-tools_SOURCE_DIR}/utils/check_symbol_exports.py "$<TARGET_FILE:${TARGET}>")
     endif()
   endmacro()
@@ -292,15 +304,23 @@
   endmacro()
 endif()
 
-# Defaults to OFF if the user didn't set it.
-option(SPIRV_SKIP_EXECUTABLES
-  "Skip building the executable and tests along with the library"
-  ${SPIRV_SKIP_EXECUTABLES})
-option(SPIRV_SKIP_TESTS
-  "Skip building tests along with the library" ${SPIRV_SKIP_TESTS})
-if ("${SPIRV_SKIP_EXECUTABLES}")
+# Currently iOS and Android are very similar.
+# They both have their own packaging (APP/APK).
+# Which makes regular executables/testing problematic.
+#
+# Currently the only deliverables for these platforms are
+# libraries (either STATIC or SHARED).
+#
+# Furthermore testing is equally problematic.
+if (IOS OR ANDROID)
+  set(SPIRV_SKIP_EXECUTABLES ON)
+endif()
+
+option(SPIRV_SKIP_EXECUTABLES "Skip building the executable and tests along with the library")
+if (SPIRV_SKIP_EXECUTABLES)
   set(SPIRV_SKIP_TESTS ON)
 endif()
+option(SPIRV_SKIP_TESTS "Skip building tests along with the library")
 
 # Defaults to ON.  The checks can be time consuming.
 # Turn off if they take too long.
@@ -358,7 +378,7 @@
 
 if (NOT "${SPIRV_SKIP_TESTS}")
   add_test(NAME spirv-tools-copyrights
-           COMMAND ${PYTHON_EXECUTABLE} utils/check_copyright.py
+           COMMAND Python3::Interpreter utils/check_copyright.py
            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 endif()
 
@@ -367,7 +387,8 @@
 
 # Build pkg-config file
 # Use a first-class target so it's regenerated when relevant files are updated.
-add_custom_target(spirv-tools-pkg-config ALL
+add_custom_command(
+        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools.pc
         COMMAND ${CMAKE_COMMAND}
                       -DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES
                       -DTEMPLATE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools.pc.in
@@ -377,8 +398,9 @@
                       -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR}
                       -DSPIRV_LIBRARIES=${SPIRV_LIBRARIES}
                       -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake
-        DEPENDS "CHANGES" "cmake/SPIRV-Tools.pc.in" "cmake/write_pkg_config.cmake")
-add_custom_target(spirv-tools-shared-pkg-config ALL
+        DEPENDS "CHANGES" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools.pc.in" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake")
+add_custom_command(
+        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc
         COMMAND ${CMAKE_COMMAND}
                       -DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES
                       -DTEMPLATE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools-shared.pc.in
@@ -388,7 +410,10 @@
                       -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR}
                       -DSPIRV_SHARED_LIBRARIES=${SPIRV_SHARED_LIBRARIES}
                       -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake
-        DEPENDS "CHANGES" "cmake/SPIRV-Tools-shared.pc.in" "cmake/write_pkg_config.cmake")
+        DEPENDS "CHANGES" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools-shared.pc.in" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake")
+add_custom_target(spirv-tools-pkg-config 
+        ALL 
+        DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools.pc)
 
 # Install pkg-config file
 if (ENABLE_SPIRV_TOOLS_INSTALL)
diff --git a/third_party/SPIRV-Tools/CONTRIBUTING.md b/third_party/SPIRV-Tools/CONTRIBUTING.md
index 893998e..11fb4e2 100644
--- a/third_party/SPIRV-Tools/CONTRIBUTING.md
+++ b/third_party/SPIRV-Tools/CONTRIBUTING.md
@@ -3,7 +3,7 @@
 ## For users: Reporting bugs and requesting features
 
 We organize known future work in GitHub projects. See
-[Tracking SPIRV-Tools work with GitHub projects](https://github.com/KhronosGroup/SPIRV-Tools/blob/master/docs/projects.md)
+[Tracking SPIRV-Tools work with GitHub projects](https://github.com/KhronosGroup/SPIRV-Tools/blob/main/docs/projects.md)
 for more.
 
 To report a new bug or request a new feature, please file a GitHub issue. Please
@@ -46,7 +46,7 @@
 approved it, but you must do it before we can put your code into our codebase.
 
 See
-[README.md](https://github.com/KhronosGroup/SPIRV-Tools/blob/master/README.md)
+[README.md](https://github.com/KhronosGroup/SPIRV-Tools/blob/main/README.md)
 for instruction on how to get, build, and test the source. Once you have made
 your changes:
 
@@ -59,7 +59,7 @@
 *   If your patch completely fixes bug 1234, the commit message should say
     `Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1234` When you do
     this, the issue will be closed automatically when the commit goes into
-    master. Also, this helps us update the [CHANGES](CHANGES) file.
+    main. Also, this helps us update the [CHANGES](CHANGES) file.
 *   Watch the continuous builds to make sure they pass.
 *   Request a code review.
 
@@ -107,7 +107,7 @@
 
 ## For maintainers: Merging a PR
 
-We intend to maintain a linear history on the GitHub master branch, and the
+We intend to maintain a linear history on the GitHub main branch, and the
 build and its tests should pass at each commit in that history. A linear
 always-working history is easier to understand and to bisect in case we want to
 find which commit introduced a bug. The
diff --git a/third_party/SPIRV-Tools/DEPS b/third_party/SPIRV-Tools/DEPS
index 9b6039e..8413d1b 100644
--- a/third_party/SPIRV-Tools/DEPS
+++ b/third_party/SPIRV-Tools/DEPS
@@ -3,18 +3,23 @@
 vars = {
   'github': 'https://github.com',
 
-  'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28',
+  'abseil_revision': '79ca5d7aad63973c83a4962a66ab07cd623131ea',
 
-  'googletest_revision': 'bc860af08783b8113005ca7697da5f5d49a8056f',
+  'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c',
+
+  'googletest_revision': '5a37b517ad4ab6738556f0284c256cae1466c5b4',
 
   # Use protobufs before they gained the dependency on abseil
   'protobuf_revision': 'v21.12',
 
-  're2_revision': 'c9cba76063cf4235c1a15dd14a24a4ef8d623761',
-  'spirv_headers_revision': '268a061764ee69f09a477a695bf6a11ffe311b8d',
+  're2_revision': '917047f3606d3ba9e2de0d383c3cd80c94ed732c',
+  'spirv_headers_revision': '4f7b471f1a66b6d06462cd4ba57628cc0cd087d7',
 }
 
 deps = {
+  'external/abseil_cpp':
+      Var('github') + '/abseil/abseil-cpp.git@' + Var('abseil_revision'),
+
   'external/effcee':
       Var('github') + '/google/effcee.git@' + Var('effcee_revision'),
 
diff --git a/third_party/SPIRV-Tools/MODULE.bazel b/third_party/SPIRV-Tools/MODULE.bazel
new file mode 100644
index 0000000..c36fe45
--- /dev/null
+++ b/third_party/SPIRV-Tools/MODULE.bazel
@@ -0,0 +1,7 @@
+bazel_dep(name = "bazel_skylib", version = "1.5.0")
+
+bazel_dep(name = "googletest", dev_dependency = True)
+local_path_override(
+    module_name = "googletest",
+    path = "external/googletest",
+)
diff --git a/third_party/SPIRV-Tools/README.md b/third_party/SPIRV-Tools/README.md
index 92e4d3c..7db5bd4 100644
--- a/third_party/SPIRV-Tools/README.md
+++ b/third_party/SPIRV-Tools/README.md
@@ -1,4 +1,5 @@
 # SPIR-V Tools
+[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/KhronosGroup/SPIRV-Tools/badge)](https://securityscorecards.dev/viewer/?uri=github.com/KhronosGroup/SPIRV-Tools)
 
 NEWS 2023-01-11: Development occurs on the `main` branch.
 
@@ -23,6 +24,13 @@
 
 ## Downloads
 
+The official releases for SPIRV-Tools can be found on LunarG's
+[SDK download page](https://vulkan.lunarg.com/sdk/home).
+
+For convenience, here are also links to the latest builds (HEAD).
+Those are untested automated builds. Those are not official releases, nor
+are guaranteed to work. Official releases builds are in the Vulkan SDK.
+
 <img alt="Linux" src="kokoro/img/linux.png" width="20px" height="20px" hspace="2px"/>[![Linux Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_linux_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_release.html)
 <img alt="MacOS" src="kokoro/img/macos.png" width="20px" height="20px" hspace="2px"/>[![MacOS Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_macos_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html)
 <img alt="Windows" src="kokoro/img/windows.png" width="20px" height="20px" hspace="2px"/>[![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2019_release.html)
@@ -48,17 +56,14 @@
 
 ## Releases
 
-Some versions of SPIRV-Tools are tagged as stable releases (see
-[tags](https://github.com/KhronosGroup/SPIRV-Tools/tags) on github).
-These versions undergo extra testing.
-Releases are not directly related to releases (or versions) of
-[SPIRV-Headers][spirv-headers].
-Releases of SPIRV-Tools are tested against the version of SPIRV-Headers listed
-in the [DEPS](DEPS) file.
-The release generally uses the most recent compatible version of SPIRV-Headers
-available at the time of release.
-No version of SPIRV-Headers other than the one listed in the DEPS file is
-guaranteed to work with the SPIRV-Tools release.
+The official releases for SPIRV-Tools can be found on LunarG's
+[SDK download page](https://vulkan.lunarg.com/sdk/home).
+
+You can find either the prebuilt, and QA tested binaries, or download the
+SDK Config, which lists the commits to use to build the release from scratch.
+
+GitHub releases are deprecated, and we will not publish new releases until
+further notice.
 
 ## Supported features
 
@@ -292,16 +297,18 @@
     git clone https://github.com/google/googletest.git          spirv-tools/external/googletest
     git clone https://github.com/google/effcee.git              spirv-tools/external/effcee
     git clone https://github.com/google/re2.git                 spirv-tools/external/re2
+    git clone https://github.com/abseil/abseil-cpp.git          spirv-tools/external/abseil_cpp
 
 #### Dependency on Effcee
 
 Some tests depend on the [Effcee][effcee] library for stateful matching.
-Effcee itself depends on [RE2][re2].
+Effcee itself depends on [RE2][re2], and RE2 depends on [Abseil][abseil-cpp].
 
 * If SPIRV-Tools is configured as part of a larger project that already uses
   Effcee, then that project should include Effcee before SPIRV-Tools.
-* Otherwise, SPIRV-Tools expects Effcee sources to appear in `external/effcee`
-  and RE2 sources to appear in `external/re2`.
+* Otherwise, SPIRV-Tools expects Effcee sources to appear in `external/effcee`,
+  RE2 sources to appear in `external/re2`, and Abseil sources to appear in 
+  `external/abseil_cpp`.
 
 ### Source code organization
 
@@ -313,6 +320,9 @@
 * `external/re2`: Location of [RE2][re2] sources, if the `re2` library is not already
   configured by an enclosing project.
   (The Effcee project already requires RE2.)
+* `external/abseil_cpp`: Location of [Abseil][abseil-cpp] sources, if Abseil is
+   not already configured by an enclosing project.
+  (The RE2 project already requires Abseil.)
 * `include/`: API clients should add this directory to the include search path
 * `external/spirv-headers`: Intended location for
   [SPIR-V headers][spirv-headers], not provided
@@ -381,15 +391,8 @@
 ### Build using Bazel
 You can also use [Bazel](https://bazel.build/) to build the project.
 
-On linux:
 ```sh
-cd <spirv-dir>
-bazel build --cxxopt=-std=c++17 :all
-```
-
-On windows:
-```sh
-bazel build --cxxopt=/std:c++17 :all
+bazel build :all
 ```
 
 ### Build a node.js package using Emscripten
@@ -427,7 +430,7 @@
 - [Python 3](http://www.python.org/): for utility scripts and running the test
 suite.
 - [Bazel](https://bazel.build/) (optional): if building the source with Bazel,
-you need to install Bazel Version 5.0.0 on your machine. Other versions may
+you need to install Bazel Version 7.0.2 on your machine. Other versions may
 also work, but are not verified.
 - [Emscripten SDK](https://emscripten.org) (optional): if building the
   WebAssembly module.
@@ -480,12 +483,12 @@
 ### Android ndk-build
 
 SPIR-V Tools supports building static libraries `libSPIRV-Tools.a` and
-`libSPIRV-Tools-opt.a` for Android:
+`libSPIRV-Tools-opt.a` for Android.  Using the Android NDK r25c or later:
 
 ```
 cd <spirv-dir>
 
-export ANDROID_NDK=/path/to/your/ndk
+export ANDROID_NDK=/path/to/your/ndk   # NDK r25c or later
 
 mkdir build && cd build
 mkdir libs
@@ -798,6 +801,7 @@
 [googletest-issue-610]: https://github.com/google/googletest/issues/610
 [effcee]: https://github.com/google/effcee
 [re2]: https://github.com/google/re2
+[abseil-cpp]: https://github.com/abseil/abseil-cpp
 [CMake]: https://cmake.org/
 [cpp-style-guide]: https://google.github.io/styleguide/cppguide.html
 [clang-sanitizers]: http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation
diff --git a/third_party/SPIRV-Tools/SECURITY.md b/third_party/SPIRV-Tools/SECURITY.md
new file mode 100644
index 0000000..99c5f44
--- /dev/null
+++ b/third_party/SPIRV-Tools/SECURITY.md
@@ -0,0 +1,13 @@
+# Security Policy
+
+## Supported Versions
+
+Security updates are applied only to the latest release.
+
+## Reporting a Vulnerability
+
+If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
+
+Please disclose it at [security advisory](https://github.com/KhronosGroup/SPIRV-Tools/security/advisories/new).
+
+This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.
diff --git a/third_party/SPIRV-Tools/WORKSPACE b/third_party/SPIRV-Tools/WORKSPACE
index 5abfc98..6e78059 100644
--- a/third_party/SPIRV-Tools/WORKSPACE
+++ b/third_party/SPIRV-Tools/WORKSPACE
@@ -4,11 +4,6 @@
 )
 
 local_repository(
-    name = "com_google_googletest",
-    path = "external/googletest",
-)
-
-local_repository(
     name = "com_googlesource_code_re2",
     path = "external/re2",
 )
@@ -17,3 +12,8 @@
     name = "com_google_effcee",
     path = "external/effcee",
 )
+
+local_repository(
+    name = "abseil-cpp",
+    path = "external/abseil_cpp",
+)
diff --git a/third_party/SPIRV-Tools/build_defs.bzl b/third_party/SPIRV-Tools/build_defs.bzl
index 4d6f15c..76bf3e7 100644
--- a/third_party/SPIRV-Tools/build_defs.bzl
+++ b/third_party/SPIRV-Tools/build_defs.bzl
@@ -88,7 +88,7 @@
         outs = outs.values(),
         cmd = cmd,
         cmd_bat = cmd,
-        exec_tools = [":generate_grammar_tables"],
+        tools = [":generate_grammar_tables"],
         visibility = ["//visibility:private"],
     )
 
@@ -123,7 +123,7 @@
         outs = outs.values(),
         cmd = cmd,
         cmd_bat = cmd,
-        exec_tools = [":generate_grammar_tables"],
+        tools = [":generate_grammar_tables"],
         visibility = ["//visibility:private"],
     )
 
@@ -151,7 +151,7 @@
         outs = outs.values(),
         cmd = cmd,
         cmd_bat = cmd,
-        exec_tools = [":generate_grammar_tables"],
+        tools = [":generate_grammar_tables"],
         visibility = ["//visibility:private"],
     )
 
@@ -179,7 +179,7 @@
         outs = outs.values(),
         cmd = cmd,
         cmd_bat = cmd,
-        exec_tools = [":generate_grammar_tables"],
+        tools = [":generate_grammar_tables"],
         visibility = ["//visibility:private"],
     )
 
@@ -207,7 +207,7 @@
         outs = outs.values(),
         cmd = cmd,
         cmd_bat = cmd,
-        exec_tools = [":generate_grammar_tables"],
+        tools = [":generate_grammar_tables"],
         visibility = ["//visibility:private"],
     )
 
@@ -229,6 +229,6 @@
         outs = outs.values(),
         cmd = cmd,
         cmd_bat = cmd,
-        exec_tools = [":generate_language_headers"],
+        tools = [":generate_language_headers"],
         visibility = ["//visibility:private"],
     )
diff --git a/third_party/SPIRV-Tools/docs/downloads.md b/third_party/SPIRV-Tools/docs/downloads.md
index 168937a..0454b9e 100644
--- a/third_party/SPIRV-Tools/docs/downloads.md
+++ b/third_party/SPIRV-Tools/docs/downloads.md
@@ -1,8 +1,24 @@
 # Downloads
 
-## Latest builds
+## Vulkan SDK
 
-Download the latest builds of the [master](https://github.com/KhronosGroup/SPIRV-Tools/tree/master) branch.
+The official releases for SPIRV-Tools can be found on LunarG's
+[SDK download page](https://vulkan.lunarg.com/sdk/home).
+The Vulkan SDK is updated approximately every six weeks.
+
+## Android NDK
+
+SPIRV-Tools host executables, and library sources are published as
+part of the [Android NDK](https://developer.android.com/ndk/downloads).
+
+## Automated builds
+
+For convenience, here are also links to the latest builds (HEAD).
+Those are untested automated builds. Those are not official releases, nor
+are guaranteed to work. Official releases builds are in the Android NDK or
+Vulkan SDK.
+
+Download the latest builds of the [main](https://github.com/KhronosGroup/SPIRV-Tools/tree/main) branch.
 
 ### Release build
 | Windows | Linux | MacOS |
@@ -15,14 +31,3 @@
 | --- | --- | --- |
 | [MSVC 2017](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_debug.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_debug.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_debug.html) |
 | | [gcc](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_gcc_debug.html) | |
-
-
-## Vulkan SDK
-
-SPIRV-Tools is published as part of the [LunarG Vulkan SDK](https://www.lunarg.com/vulkan-sdk/).
-The Vulkan SDK is updated approximately every six weeks.
-
-## Android NDK
-
-SPIRV-Tools host executables, and library sources are published as
-part of the [Android NDK](https://developer.android.com/ndk/downloads).
diff --git a/third_party/SPIRV-Tools/docs/projects.md b/third_party/SPIRV-Tools/docs/projects.md
index 8f7f0bc..cc88cb3 100644
--- a/third_party/SPIRV-Tools/docs/projects.md
+++ b/third_party/SPIRV-Tools/docs/projects.md
@@ -34,7 +34,7 @@
   ones.
 * They determine if the work for a card has been completed.
 * Normally they are the person (or persons) who can approve and merge a pull
-  request into the `master` branch.
+  request into the `main` branch.
 
 Our projects organize cards into the following columns:
 * `Ideas`: Work which could be done, captured either as Cards or Notes.
@@ -51,7 +51,7 @@
   claimed by someone.
 * `Done`: Issues which have been resolved, by completing their work.
   * The changes have been applied to the repository, typically by being pushed
-  into the `master` branch.
+  into the `main` branch.
   * Other kinds of work could update repository settings, for example.
 * `Rejected ideas`: Work which has been considered, but which we don't want
   implemented.
diff --git a/third_party/SPIRV-Tools/external/CMakeLists.txt b/third_party/SPIRV-Tools/external/CMakeLists.txt
index 6ee37d9..5d8a3da 100644
--- a/third_party/SPIRV-Tools/external/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/external/CMakeLists.txt
@@ -41,8 +41,6 @@
   # Do this so enclosing projects can use SPIRV-Headers_SOURCE_DIR to find
   # headers to include.
   if (NOT DEFINED SPIRV-Headers_SOURCE_DIR)
-    set(SPIRV_HEADERS_SKIP_INSTALL ON)
-    set(SPIRV_HEADERS_SKIP_EXAMPLES ON)
     add_subdirectory(${SPIRV_HEADER_DIR})
   endif()
 else()
@@ -93,10 +91,22 @@
 
   # Find Effcee and RE2, for testing.
 
+  # RE2 depends on Abseil. We set absl_SOURCE_DIR if it is not already set, so
+  # that effcee can find abseil.
+  if(NOT TARGET absl::base)
+    if (NOT absl_SOURCE_DIR)
+      if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/abseil_cpp)
+        set(absl_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/abseil_cpp" CACHE STRING "Abseil source dir" )
+      endif()
+    endif()
+  endif()
+
   # First find RE2, since Effcee depends on it.
   # If already configured, then use that.  Otherwise, prefer to find it under 're2'
   # in this directory.
   if (NOT TARGET re2)
+
+
     # If we are configuring RE2, then turn off its testing.  It takes a long time and
     # does not add much value for us.  If an enclosing project configured RE2, then it
     # has already chosen whether to enable RE2 testing.
diff --git a/third_party/SPIRV-Tools/include/spirv-tools/instrument.hpp b/third_party/SPIRV-Tools/include/spirv-tools/instrument.hpp
index 448cf8a..0a6e630 100644
--- a/third_party/SPIRV-Tools/include/spirv-tools/instrument.hpp
+++ b/third_party/SPIRV-Tools/include/spirv-tools/instrument.hpp
@@ -73,213 +73,14 @@
 // which generated the validation error.
 static const int kInstCommonOutInstructionIdx = 2;
 
-// This is the stage which generated the validation error. This word is used
-// to determine the contents of the next two words in the record.
-// 0:Vert, 1:TessCtrl, 2:TessEval, 3:Geom, 4:Frag, 5:Compute
-static const int kInstCommonOutStageIdx = 3;
-static const int kInstCommonOutCnt = 4;
-
-// Stage-specific Stream Record Offsets
-//
-// Each stage will contain different values in the next set of words of the
-// record used to identify which instantiation of the shader generated the
-// validation error.
-//
-// Vertex Shader Output Record Offsets
-static const int kInstVertOutVertexIndex = kInstCommonOutCnt;
-static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1;
-static const int kInstVertOutUnused = kInstCommonOutCnt + 2;
-
-// Frag Shader Output Record Offsets
-static const int kInstFragOutFragCoordX = kInstCommonOutCnt;
-static const int kInstFragOutFragCoordY = kInstCommonOutCnt + 1;
-static const int kInstFragOutUnused = kInstCommonOutCnt + 2;
-
-// Compute Shader Output Record Offsets
-static const int kInstCompOutGlobalInvocationIdX = kInstCommonOutCnt;
-static const int kInstCompOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
-static const int kInstCompOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;
-
-// Tessellation Control Shader Output Record Offsets
-static const int kInstTessCtlOutInvocationId = kInstCommonOutCnt;
-static const int kInstTessCtlOutPrimitiveId = kInstCommonOutCnt + 1;
-static const int kInstTessCtlOutUnused = kInstCommonOutCnt + 2;
-
-// Tessellation Eval Shader Output Record Offsets
-static const int kInstTessEvalOutPrimitiveId = kInstCommonOutCnt;
-static const int kInstTessEvalOutTessCoordU = kInstCommonOutCnt + 1;
-static const int kInstTessEvalOutTessCoordV = kInstCommonOutCnt + 2;
-
-// Geometry Shader Output Record Offsets
-static const int kInstGeomOutPrimitiveId = kInstCommonOutCnt;
-static const int kInstGeomOutInvocationId = kInstCommonOutCnt + 1;
-static const int kInstGeomOutUnused = kInstCommonOutCnt + 2;
-
-// Ray Tracing Shader Output Record Offsets
-static const int kInstRayTracingOutLaunchIdX = kInstCommonOutCnt;
-static const int kInstRayTracingOutLaunchIdY = kInstCommonOutCnt + 1;
-static const int kInstRayTracingOutLaunchIdZ = kInstCommonOutCnt + 2;
-
-// Mesh Shader Output Record Offsets
-static const int kInstMeshOutGlobalInvocationIdX = kInstCommonOutCnt;
-static const int kInstMeshOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
-static const int kInstMeshOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;
-
-// Task Shader Output Record Offsets
-static const int kInstTaskOutGlobalInvocationIdX = kInstCommonOutCnt;
-static const int kInstTaskOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
-static const int kInstTaskOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;
-
-// Size of Common and Stage-specific Members
-static const int kInstStageOutCnt = kInstCommonOutCnt + 3;
-
-// Validation Error Code Offset
-//
-// This identifies the validation error. It also helps to identify
-// how many words follow in the record and their meaning.
-static const int kInstValidationOutError = kInstStageOutCnt;
-
-// Validation-specific Output Record Offsets
-//
-// Each different validation will generate a potentially different
-// number of words at the end of the record giving more specifics
-// about the validation error.
-//
-// A bindless bounds error will output the index and the bound.
-static const int kInstBindlessBoundsOutDescSet = kInstStageOutCnt + 1;
-static const int kInstBindlessBoundsOutDescBinding = kInstStageOutCnt + 2;
-static const int kInstBindlessBoundsOutDescIndex = kInstStageOutCnt + 3;
-static const int kInstBindlessBoundsOutDescBound = kInstStageOutCnt + 4;
-static const int kInstBindlessBoundsOutUnused = kInstStageOutCnt + 5;
-static const int kInstBindlessBoundsOutCnt = kInstStageOutCnt + 6;
-
-// A descriptor uninitialized error will output the index.
-static const int kInstBindlessUninitOutDescSet = kInstStageOutCnt + 1;
-static const int kInstBindlessUninitOutBinding = kInstStageOutCnt + 2;
-static const int kInstBindlessUninitOutDescIndex = kInstStageOutCnt + 3;
-static const int kInstBindlessUninitOutUnused = kInstStageOutCnt + 4;
-static const int kInstBindlessUninitOutUnused2 = kInstStageOutCnt + 5;
-static const int kInstBindlessUninitOutCnt = kInstStageOutCnt + 6;
-
-// A buffer out-of-bounds error will output the descriptor
-// index, the buffer offset and the buffer size
-static const int kInstBindlessBuffOOBOutDescSet = kInstStageOutCnt + 1;
-static const int kInstBindlessBuffOOBOutDescBinding = kInstStageOutCnt + 2;
-static const int kInstBindlessBuffOOBOutDescIndex = kInstStageOutCnt + 3;
-static const int kInstBindlessBuffOOBOutBuffOff = kInstStageOutCnt + 4;
-static const int kInstBindlessBuffOOBOutBuffSize = kInstStageOutCnt + 5;
-static const int kInstBindlessBuffOOBOutCnt = kInstStageOutCnt + 6;
-
-// A buffer address unalloc error will output the 64-bit pointer in
-// two 32-bit pieces, lower bits first.
-static const int kInstBuffAddrUnallocOutDescPtrLo = kInstStageOutCnt + 1;
-static const int kInstBuffAddrUnallocOutDescPtrHi = kInstStageOutCnt + 2;
-static const int kInstBuffAddrUnallocOutCnt = kInstStageOutCnt + 3;
-
-// Maximum Output Record Member Count
-static const int kInstMaxOutCnt = kInstStageOutCnt + 6;
-
-// Validation Error Codes
-//
-// These are the possible validation error codes.
-static const int kInstErrorBindlessBounds = 0;
-static const int kInstErrorBindlessUninit = 1;
-static const int kInstErrorBuffAddrUnallocRef = 2;
-// Deleted: static const int kInstErrorBindlessBuffOOB = 3;
-// This comment will will remain for 2 releases to allow
-// for the transition of all builds. Buffer OOB is
-// generating the following four differentiated codes instead:
-static const int kInstErrorBuffOOBUniform = 4;
-static const int kInstErrorBuffOOBStorage = 5;
-static const int kInstErrorBuffOOBUniformTexel = 6;
-static const int kInstErrorBuffOOBStorageTexel = 7;
-static const int kInstErrorMax = kInstErrorBuffOOBStorageTexel;
-
-// Direct Input Buffer Offsets
-//
-// The following values provide member offsets into the input buffers
-// consumed by InstrumentPass::GenDebugDirectRead(). This method is utilized
-// by InstBindlessCheckPass.
-//
-// The only object in an input buffer is a runtime array of unsigned
-// integers. Each validation will have its own formatting of this array.
-static const int kDebugInputDataOffset = 0;
-
 // Debug Buffer Bindings
 //
 // These are the bindings for the different buffers which are
 // read or written by the instrumentation passes.
 //
-// This is the output buffer written by InstBindlessCheckPass,
-// InstBuffAddrCheckPass, and possibly other future validations.
-static const int kDebugOutputBindingStream = 0;
-
-// The binding for the input buffer read by InstBindlessCheckPass.
-static const int kDebugInputBindingBindless = 1;
-
-// The binding for the input buffer read by InstBuffAddrCheckPass.
-static const int kDebugInputBindingBuffAddr = 2;
-
 // This is the output buffer written by InstDebugPrintfPass.
 static const int kDebugOutputPrintfStream = 3;
 
-// clang-format off
-// Bindless Validation Input Buffer Format
-//
-// An input buffer for bindless validation has this structure:
-// GLSL:
-// layout(buffer_reference, std430, buffer_reference_align = 8) buffer DescriptorSetData {
-//     uint num_bindings;
-//     uint data[];
-// };
-//
-// layout(set = 7, binding = 1, std430) buffer inst_bindless_InputBuffer
-// {
-//     DescriptorSetData desc_sets[32];
-// } inst_bindless_input_buffer;
-//
-//
-// To look up the length of a binding:
-//   uint length = inst_bindless_input_buffer[set].data[binding];
-// Scalar bindings have a length of 1.
-//
-// To look up the initialization state of a descriptor in a binding:
-//   uint num_bindings = inst_bindless_input_buffer[set].num_bindings;
-//   uint binding_state_start = inst_bindless_input_buffer[set].data[num_bindings + binding];
-//   uint init_state = inst_bindless_input_buffer[set].data[binding_state_start + index];
-//
-// For scalar bindings, use 0 for the index.
-// clang-format on
-//
-// The size of the inst_bindless_input_buffer array, regardless of how many
-// descriptor sets the device supports.
-static const int kDebugInputBindlessMaxDescSets = 32;
-
-// Buffer Device Address Input Buffer Format
-//
-// An input buffer for buffer device address validation consists of a single
-// array of unsigned 64-bit integers we will call Data[]. This array is
-// formatted as follows:
-//
-// At offset kDebugInputBuffAddrPtrOffset is a list of sorted valid buffer
-// addresses. The list is terminated with the address 0xffffffffffffffff.
-// If 0x0 is not a valid buffer address, this address is inserted at the
-// start of the list.
-//
-static const int kDebugInputBuffAddrPtrOffset = 1;
-//
-// At offset kDebugInputBuffAddrLengthOffset in Data[] is a single uint64 which
-// gives an offset to the start of the buffer length data. More
-// specifically, for a buffer whose pointer is located at input buffer offset
-// i, the length is located at:
-//
-// Data[ i - kDebugInputBuffAddrPtrOffset
-//         + Data[ kDebugInputBuffAddrLengthOffset ] ]
-//
-// The length associated with the 0xffffffffffffffff address is zero. If
-// not a valid buffer, the length associated with the 0x0 address is zero.
-static const int kDebugInputBuffAddrLengthOffset = 0;
-
 }  // namespace spvtools
 
 #endif  // INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_
diff --git a/third_party/SPIRV-Tools/include/spirv-tools/libspirv.h b/third_party/SPIRV-Tools/include/spirv-tools/libspirv.h
index 542b745..83b1a8e 100644
--- a/third_party/SPIRV-Tools/include/spirv-tools/libspirv.h
+++ b/third_party/SPIRV-Tools/include/spirv-tools/libspirv.h
@@ -33,15 +33,19 @@
 #else
 #define SPIRV_TOOLS_EXPORT __declspec(dllimport)
 #endif
+#define SPIRV_TOOLS_LOCAL
 #else
 #if defined(SPIRV_TOOLS_IMPLEMENTATION)
 #define SPIRV_TOOLS_EXPORT __attribute__((visibility("default")))
+#define SPIRV_TOOLS_LOCAL __attribute__((visibility("hidden")))
 #else
 #define SPIRV_TOOLS_EXPORT
+#define SPIRV_TOOLS_LOCAL
 #endif
 #endif
 #else
 #define SPIRV_TOOLS_EXPORT
+#define SPIRV_TOOLS_LOCAL
 #endif
 
 // Helpers
@@ -143,6 +147,7 @@
   // may be larger than 32, which would require such a typed literal value to
   // occupy multiple SPIR-V words.
   SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
+  SPV_OPERAND_TYPE_LITERAL_FLOAT,  // Always 32-bit float.
 
   // Set 3:  The literal string operand type.
   SPV_OPERAND_TYPE_LITERAL_STRING,
@@ -285,6 +290,28 @@
   // An optional packed vector format
   SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT,
 
+  // Concrete operand types for cooperative matrix.
+  SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS,
+  // An optional cooperative matrix operands
+  SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS,
+  SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT,
+  SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE,
+
+  // Enum type from SPV_INTEL_global_variable_fpga_decorations
+  SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER,
+  // Enum type from SPV_INTEL_global_variable_host_access
+  SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER,
+  // Enum type from SPV_INTEL_cache_controls
+  SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL,
+  // Enum type from SPV_INTEL_cache_controls
+  SPV_OPERAND_TYPE_STORE_CACHE_CONTROL,
+  // Enum type from SPV_INTEL_maximum_registers
+  SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS,
+  // Enum type from SPV_NV_raw_access_chains
+  SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS,
+  // Optional enum type from SPV_NV_raw_access_chains
+  SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS,
+
   // This is a sentinel value, and does not represent an operand type.
   // It should come last.
   SPV_OPERAND_TYPE_NUM_OPERAND_TYPES,
@@ -310,6 +337,7 @@
   SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100,
   SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION,
   SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100,
+  SPV_EXT_INST_TYPE_NONSEMANTIC_VKSPREFLECTION,
 
   // Multiple distinct extended instruction set types could return this
   // value, if they are prefixed with NonSemantic. and are otherwise
@@ -949,9 +977,16 @@
     spv_optimizer_t* optimizer, const char* flag);
 
 // Registers passes specified by length number of flags in an optimizer object.
+// Passes may remove interface variables that are unused.
 SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags(
     spv_optimizer_t* optimizer, const char** flags, const size_t flag_count);
 
+// Registers passes specified by length number of flags in an optimizer object.
+// Passes will not remove interface variables.
+SPIRV_TOOLS_EXPORT bool
+spvOptimizerRegisterPassesFromFlagsWhilePreservingTheInterface(
+    spv_optimizer_t* optimizer, const char** flags, const size_t flag_count);
+
 // Optimizes the SPIR-V code of size |word_count| pointed to by |binary| and
 // returns an optimized spv_binary in |optimized_binary|.
 //
diff --git a/third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp b/third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp
index ee6c846..59ff82b 100644
--- a/third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp
+++ b/third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp
@@ -37,7 +37,7 @@
     std::function<spv_result_t(const spv_parsed_instruction_t& instruction)>;
 
 // C++ RAII wrapper around the C context object spv_context.
-class Context {
+class SPIRV_TOOLS_EXPORT Context {
  public:
   // Constructs a context targeting the given environment |env|.
   //
@@ -73,7 +73,7 @@
 };
 
 // A RAII wrapper around a validator options object.
-class ValidatorOptions {
+class SPIRV_TOOLS_EXPORT ValidatorOptions {
  public:
   ValidatorOptions() : options_(spvValidatorOptionsCreate()) {}
   ~ValidatorOptions() { spvValidatorOptionsDestroy(options_); }
@@ -163,7 +163,7 @@
 };
 
 // A C++ wrapper around an optimization options object.
-class OptimizerOptions {
+class SPIRV_TOOLS_EXPORT OptimizerOptions {
  public:
   OptimizerOptions() : options_(spvOptimizerOptionsCreate()) {}
   ~OptimizerOptions() { spvOptimizerOptionsDestroy(options_); }
@@ -205,7 +205,7 @@
 };
 
 // A C++ wrapper around a reducer options object.
-class ReducerOptions {
+class SPIRV_TOOLS_EXPORT ReducerOptions {
  public:
   ReducerOptions() : options_(spvReducerOptionsCreate()) {}
   ~ReducerOptions() { spvReducerOptionsDestroy(options_); }
@@ -236,7 +236,7 @@
 };
 
 // A C++ wrapper around a fuzzer options object.
-class FuzzerOptions {
+class SPIRV_TOOLS_EXPORT FuzzerOptions {
  public:
   FuzzerOptions() : options_(spvFuzzerOptionsCreate()) {}
   ~FuzzerOptions() { spvFuzzerOptionsDestroy(options_); }
@@ -283,7 +283,7 @@
 // provides methods for assembling, disassembling, and validating.
 //
 // Instances of this class provide basic thread-safety guarantee.
-class SpirvTools {
+class SPIRV_TOOLS_EXPORT SpirvTools {
  public:
   enum {
     // Default assembling option used by assemble():
@@ -388,7 +388,8 @@
   bool IsValid() const;
 
  private:
-  struct Impl;  // Opaque struct for holding the data fields used by this class.
+  struct SPIRV_TOOLS_LOCAL
+      Impl;  // Opaque struct for holding the data fields used by this class.
   std::unique_ptr<Impl> impl_;  // Unique pointer to implementation data.
 };
 
diff --git a/third_party/SPIRV-Tools/include/spirv-tools/linker.hpp b/third_party/SPIRV-Tools/include/spirv-tools/linker.hpp
index d2f3e72..6ba6e96 100644
--- a/third_party/SPIRV-Tools/include/spirv-tools/linker.hpp
+++ b/third_party/SPIRV-Tools/include/spirv-tools/linker.hpp
@@ -24,13 +24,8 @@
 
 namespace spvtools {
 
-class LinkerOptions {
+class SPIRV_TOOLS_EXPORT LinkerOptions {
  public:
-  LinkerOptions()
-      : create_library_(false),
-        verify_ids_(false),
-        allow_partial_linkage_(false) {}
-
   // Returns whether a library or an executable should be produced by the
   // linking phase.
   //
@@ -63,10 +58,16 @@
     allow_partial_linkage_ = allow_partial_linkage;
   }
 
+  bool GetUseHighestVersion() const { return use_highest_version_; }
+  void SetUseHighestVersion(bool use_highest_vers) {
+    use_highest_version_ = use_highest_vers;
+  }
+
  private:
-  bool create_library_;
-  bool verify_ids_;
-  bool allow_partial_linkage_;
+  bool create_library_{false};
+  bool verify_ids_{false};
+  bool allow_partial_linkage_{false};
+  bool use_highest_version_{false};
 };
 
 // Links one or more SPIR-V modules into a new SPIR-V module. That is, combine
@@ -83,14 +84,15 @@
 // * Some entry points were defined multiple times;
 // * Some imported symbols did not have an exported counterpart;
 // * Possibly other reasons.
-spv_result_t Link(const Context& context,
-                  const std::vector<std::vector<uint32_t>>& binaries,
-                  std::vector<uint32_t>* linked_binary,
-                  const LinkerOptions& options = LinkerOptions());
-spv_result_t Link(const Context& context, const uint32_t* const* binaries,
-                  const size_t* binary_sizes, size_t num_binaries,
-                  std::vector<uint32_t>* linked_binary,
-                  const LinkerOptions& options = LinkerOptions());
+SPIRV_TOOLS_EXPORT spv_result_t
+Link(const Context& context, const std::vector<std::vector<uint32_t>>& binaries,
+     std::vector<uint32_t>* linked_binary,
+     const LinkerOptions& options = LinkerOptions());
+SPIRV_TOOLS_EXPORT spv_result_t
+Link(const Context& context, const uint32_t* const* binaries,
+     const size_t* binary_sizes, size_t num_binaries,
+     std::vector<uint32_t>* linked_binary,
+     const LinkerOptions& options = LinkerOptions());
 
 }  // namespace spvtools
 
diff --git a/third_party/SPIRV-Tools/include/spirv-tools/linter.hpp b/third_party/SPIRV-Tools/include/spirv-tools/linter.hpp
index 52ed5a4..ccbcf0c 100644
--- a/third_party/SPIRV-Tools/include/spirv-tools/linter.hpp
+++ b/third_party/SPIRV-Tools/include/spirv-tools/linter.hpp
@@ -24,7 +24,7 @@
 // provides a method for linting.
 //
 // Instances of this class provides basic thread-safety guarantee.
-class Linter {
+class SPIRV_TOOLS_EXPORT Linter {
  public:
   explicit Linter(spv_target_env env);
 
@@ -40,7 +40,7 @@
   bool Run(const uint32_t* binary, size_t binary_size);
 
  private:
-  struct Impl;
+  struct SPIRV_TOOLS_LOCAL Impl;
   std::unique_ptr<Impl> impl_;
 };
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/include/spirv-tools/optimizer.hpp b/third_party/SPIRV-Tools/include/spirv-tools/optimizer.hpp
index 8bdd4e8..a3119d9 100644
--- a/third_party/SPIRV-Tools/include/spirv-tools/optimizer.hpp
+++ b/third_party/SPIRV-Tools/include/spirv-tools/optimizer.hpp
@@ -37,14 +37,14 @@
 // provides methods for registering optimization passes and optimizing.
 //
 // Instances of this class provides basic thread-safety guarantee.
-class Optimizer {
+class SPIRV_TOOLS_EXPORT Optimizer {
  public:
   // The token for an optimization pass. It is returned via one of the
   // Create*Pass() standalone functions at the end of this header file and
   // consumed by the RegisterPass() method. Tokens are one-time objects that
   // only support move; copying is not allowed.
   struct PassToken {
-    struct Impl;  // Opaque struct for holding internal data.
+    struct SPIRV_TOOLS_LOCAL Impl;  // Opaque struct for holding internal data.
 
     PassToken(std::unique_ptr<Impl>);
 
@@ -97,12 +97,20 @@
   // Registers passes that attempt to improve performance of generated code.
   // This sequence of passes is subject to constant review and will change
   // from time to time.
+  //
+  // If |preserve_interface| is true, all non-io variables in the entry point
+  // interface are considered live and are not eliminated.
   Optimizer& RegisterPerformancePasses();
+  Optimizer& RegisterPerformancePasses(bool preserve_interface);
 
   // Registers passes that attempt to improve the size of generated code.
   // This sequence of passes is subject to constant review and will change
   // from time to time.
+  //
+  // If |preserve_interface| is true, all non-io variables in the entry point
+  // interface are considered live and are not eliminated.
   Optimizer& RegisterSizePasses();
+  Optimizer& RegisterSizePasses(bool preserve_interface);
 
   // Registers passes that attempt to legalize the generated code.
   //
@@ -112,7 +120,11 @@
   //
   // This sequence of passes is subject to constant review and will change
   // from time to time.
+  //
+  // If |preserve_interface| is true, all non-io variables in the entry point
+  // interface are considered live and are not eliminated.
   Optimizer& RegisterLegalizationPasses();
+  Optimizer& RegisterLegalizationPasses(bool preserve_interface);
 
   // Register passes specified in the list of |flags|.  Each flag must be a
   // string of a form accepted by Optimizer::FlagHasValidForm().
@@ -121,8 +133,13 @@
   // error message is emitted to the MessageConsumer object (use
   // Optimizer::SetMessageConsumer to define a message consumer, if needed).
   //
+  // If |preserve_interface| is true, all non-io variables in the entry point
+  // interface are considered live and are not eliminated.
+  //
   // If all the passes are registered successfully, it returns true.
   bool RegisterPassesFromFlags(const std::vector<std::string>& flags);
+  bool RegisterPassesFromFlags(const std::vector<std::string>& flags,
+                               bool preserve_interface);
 
   // Registers the optimization pass associated with |flag|.  This only accepts
   // |flag| values of the form "--pass_name[=pass_args]".  If no such pass
@@ -139,7 +156,11 @@
   //
   // --legalize-hlsl: Registers all passes that legalize SPIR-V generated by an
   //                  HLSL front-end.
+  //
+  // If |preserve_interface| is true, all non-io variables in the entry point
+  // interface are considered live and are not eliminated.
   bool RegisterPassFromFlag(const std::string& flag);
+  bool RegisterPassFromFlag(const std::string& flag, bool preserve_interface);
 
   // Validates that |flag| has a valid format.  Strings accepted:
   //
@@ -218,7 +239,7 @@
   Optimizer& SetValidateAfterAll(bool validate);
 
  private:
-  struct Impl;                  // Opaque struct for holding internal data.
+  struct SPIRV_TOOLS_LOCAL Impl;  // Opaque struct for holding internal data.
   std::unique_ptr<Impl> impl_;  // Unique pointer to internal data.
 };
 
@@ -748,19 +769,9 @@
 // potentially de-optimizing the instrument code, for example, inlining
 // the debug record output function throughout the module.
 //
-// The instrumentation will read and write buffers in debug
-// descriptor set |desc_set|. It will write |shader_id| in each output record
+// The instrumentation will write |shader_id| in each output record
 // to identify the shader module which generated the record.
-// |desc_length_enable| controls instrumentation of runtime descriptor array
-// references, |desc_init_enable| controls instrumentation of descriptor
-// initialization checking, and |buff_oob_enable| controls instrumentation
-// of storage and uniform buffer bounds checking, all of which require input
-// buffer support. |texbuff_oob_enable| controls instrumentation of texel
-// buffers, which does not require input buffer support.
-Optimizer::PassToken CreateInstBindlessCheckPass(
-    uint32_t desc_set, uint32_t shader_id, bool desc_length_enable = false,
-    bool desc_init_enable = false, bool buff_oob_enable = false,
-    bool texbuff_oob_enable = false);
+Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t shader_id);
 
 // Create a pass to instrument physical buffer address checking
 // This pass instruments all physical buffer address references to check that
@@ -781,8 +792,7 @@
 // The instrumentation will read and write buffers in debug
 // descriptor set |desc_set|. It will write |shader_id| in each output record
 // to identify the shader module which generated the record.
-Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
-                                                 uint32_t shader_id);
+Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t shader_id);
 
 // Create a pass to instrument OpDebugPrintf instructions.
 // This pass replaces all OpDebugPrintf instructions with instructions to write
@@ -971,6 +981,32 @@
 // object, currently the pass would remove accesschain pointer argument passed
 // to the function
 Optimizer::PassToken CreateFixFuncCallArgumentsPass();
+
+// Creates a trim-capabilities pass.
+// This pass removes unused capabilities for a given module, and if possible,
+// associated extensions.
+// See `trim_capabilities.h` for the list of supported capabilities.
+//
+// If the module contains unsupported capabilities, this pass will ignore them.
+// This should be fine in most cases, but could yield to incorrect results if
+// the unknown capability interacts with one of the trimmed capabilities.
+Optimizer::PassToken CreateTrimCapabilitiesPass();
+
+// Creates a switch-descriptorset pass.
+// This pass changes any DescriptorSet decorations with the value |ds_from| to
+// use the new value |ds_to|.
+Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t ds_from,
+                                                   uint32_t ds_to);
+
+// Creates an invocation interlock placement pass.
+// This pass ensures that an entry point will have at most one
+// OpBeginInterlockInvocationEXT and one OpEndInterlockInvocationEXT, in that
+// order.
+Optimizer::PassToken CreateInvocationInterlockPlacementPass();
+
+// Creates a pass to add/remove maximal reconvergence execution mode.
+// This pass either adds or removes maximal reconvergence from all entry points.
+Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add);
 }  // namespace spvtools
 
 #endif  // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_
diff --git a/third_party/SPIRV-Tools/kokoro/macos-clang-release-bazel/build.sh b/third_party/SPIRV-Tools/kokoro/macos-clang-release-bazel/build.sh
index 2465d9c..4bb889a 100644
--- a/third_party/SPIRV-Tools/kokoro/macos-clang-release-bazel/build.sh
+++ b/third_party/SPIRV-Tools/kokoro/macos-clang-release-bazel/build.sh
@@ -30,20 +30,16 @@
 git config --global --add safe.directory $SRC
 
 cd $SRC
-git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers
-git clone https://github.com/google/googletest          external/googletest
-cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd ..
-git clone --depth=1 https://github.com/google/effcee              external/effcee
-git clone --depth=1 https://github.com/google/re2                 external/re2
+/usr/bin/python3 utils/git-sync-deps --treeless
 
-# Get bazel 5.0.0
-gsutil cp gs://bazel/5.0.0/release/bazel-5.0.0-darwin-x86_64 .
-chmod +x bazel-5.0.0-darwin-x86_64
+# Get bazel 7.0.2
+gsutil cp gs://bazel/7.0.2/release/bazel-7.0.2-darwin-x86_64 .
+chmod +x bazel-7.0.2-darwin-x86_64
 
 echo $(date): Build everything...
-./bazel-5.0.0-darwin-x86_64 build --cxxopt=-std=c++17 :all
+./bazel-7.0.2-darwin-x86_64 build --cxxopt=-std=c++17 :all
 echo $(date): Build completed.
 
 echo $(date): Starting bazel test...
-./bazel-5.0.0-darwin-x86_64 test --cxxopt=-std=c++17 :all
+./bazel-7.0.2-darwin-x86_64 test --cxxopt=-std=c++17 :all
 echo $(date): Bazel test completed.
diff --git a/third_party/SPIRV-Tools/kokoro/scripts/linux/build-docker.sh b/third_party/SPIRV-Tools/kokoro/scripts/linux/build-docker.sh
index f2a06e0..e47037d 100755
--- a/third_party/SPIRV-Tools/kokoro/scripts/linux/build-docker.sh
+++ b/third_party/SPIRV-Tools/kokoro/scripts/linux/build-docker.sh
@@ -131,6 +131,7 @@
   git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-headers
   git clone https://github.com/google/re2
   git clone https://github.com/google/effcee
+  git clone https://github.com/abseil/abseil-cpp abseil_cpp
 
   cd $SHADERC_DIR
   mkdir build
@@ -141,7 +142,7 @@
   cmake -GNinja -DRE2_BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE="Release" ..
 
   echo $(date): Build glslang...
-  ninja glslangValidator
+  ninja glslang-standalone
 
   echo $(date): Build everything...
   ninja
@@ -155,7 +156,7 @@
   echo $(date): ctest completed.
 elif [ $TOOL = "cmake-android-ndk" ]; then
   using cmake-3.17.2
-  using ndk-r21d
+  using ndk-r25c
   using ninja-1.10.0
 
   clean_dir "$ROOT_DIR/build"
@@ -163,7 +164,7 @@
 
   echo $(date): Starting build...
   cmake -DCMAKE_BUILD_TYPE=Release \
-        -DANDROID_NATIVE_API_LEVEL=android-16 \
+        -DANDROID_NATIVE_API_LEVEL=android-24 \
         -DANDROID_ABI="armeabi-v7a with NEON" \
         -DSPIRV_SKIP_TESTS=ON \
         -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \
@@ -175,7 +176,7 @@
   ninja
   echo $(date): Build completed.
 elif [ $TOOL = "android-ndk-build" ]; then
-  using ndk-r21d
+  using ndk-r25c
 
   clean_dir "$ROOT_DIR/build"
   cd "$ROOT_DIR/build"
@@ -190,7 +191,7 @@
 
   echo $(date): ndk-build completed.
 elif [ $TOOL = "bazel" ]; then
-  using bazel-5.0.0
+  using bazel-7.0.2
 
   echo $(date): Build everything...
   bazel build --cxxopt=-std=c++17 :all
diff --git a/third_party/SPIRV-Tools/kokoro/scripts/windows/build.bat b/third_party/SPIRV-Tools/kokoro/scripts/windows/build.bat
index bb14da3..fe15f2d 100644
--- a/third_party/SPIRV-Tools/kokoro/scripts/windows/build.bat
+++ b/third_party/SPIRV-Tools/kokoro/scripts/windows/build.bat
@@ -30,6 +30,9 @@
 if %VS_VERSION% == 2017 (
   call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
   echo "Using VS 2017..."
+
+  :: RE2 does not support VS2017, we we must disable tests.
+  set BUILD_TESTS=NO
 ) else if %VS_VERSION% == 2019 (
   call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
   echo "Using VS 2019..."
@@ -56,6 +59,10 @@
 :: Build spirv-fuzz
 set CMAKE_FLAGS=%CMAKE_FLAGS% -DSPIRV_BUILD_FUZZER=ON
 
+if "%BUILD_TESTS%" == "NO" (
+  set CMAKE_FLAGS=-DSPIRV_SKIP_TESTS=ON %CMAKE_FLAGS%
+) 
+
 cmake %CMAKE_FLAGS% ..
 
 if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
@@ -71,10 +78,12 @@
 :: ################################################
 :: Run the tests
 :: ################################################
-echo "Running Tests... %DATE% %TIME%"
-ctest -C %BUILD_TYPE% --output-on-failure --timeout 300
-if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL!
-echo "Tests Completed %DATE% %TIME%"
+if "%BUILD_TESTS%" NEQ "NO" (
+  echo "Running Tests... %DATE% %TIME%"
+  ctest -C %BUILD_TYPE% --output-on-failure --timeout 300
+  if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL!
+  echo "Tests Completed %DATE% %TIME%"
+)
 
 :: ################################################
 :: Install and package.
diff --git a/third_party/SPIRV-Tools/source/CMakeLists.txt b/third_party/SPIRV-Tools/source/CMakeLists.txt
index acfa0c1..d0454c6c 100644
--- a/third_party/SPIRV-Tools/source/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/source/CMakeLists.txt
@@ -31,7 +31,7 @@
   set(GRAMMAR_INSTS_INC_FILE "${spirv-tools_BINARY_DIR}/core.insts-${CONFIG_VERSION}.inc")
   set(GRAMMAR_KINDS_INC_FILE "${spirv-tools_BINARY_DIR}/operand.kinds-${CONFIG_VERSION}.inc")
   add_custom_command(OUTPUT ${GRAMMAR_INSTS_INC_FILE} ${GRAMMAR_KINDS_INC_FILE}
-    COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
+    COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT}
       --spirv-core-grammar=${GRAMMAR_JSON_FILE}
       --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE}
       --extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE}
@@ -53,7 +53,7 @@
   set(GRAMMAR_ENUM_STRING_MAPPING_INC_FILE "${spirv-tools_BINARY_DIR}/enum_string_mapping.inc")
   add_custom_command(OUTPUT ${GRAMMAR_EXTENSION_ENUM_INC_FILE}
      ${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE}
-    COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
+    COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT}
       --spirv-core-grammar=${GRAMMAR_JSON_FILE}
       --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE}
       --extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE}
@@ -75,7 +75,7 @@
   set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json")
   set(VIMSYNTAX_FILE "${spirv-tools_BINARY_DIR}/spvasm.vim")
   add_custom_command(OUTPUT ${VIMSYNTAX_FILE}
-      COMMAND ${PYTHON_EXECUTABLE} ${VIMSYNTAX_PROCESSING_SCRIPT}
+      COMMAND Python3::Interpreter ${VIMSYNTAX_PROCESSING_SCRIPT}
       --spirv-core-grammar=${GRAMMAR_JSON_FILE}
       --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE}
       --extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE}
@@ -91,7 +91,7 @@
   set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.glsl.std.450.grammar.json")
   set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/glsl.std.450.insts.inc")
   add_custom_command(OUTPUT ${GRAMMAR_INC_FILE}
-    COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
+    COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT}
       --extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE}
       --glsl-insts-output=${GRAMMAR_INC_FILE}
       --output-language=c++
@@ -105,7 +105,7 @@
   set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json")
   set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/opencl.std.insts.inc")
   add_custom_command(OUTPUT ${GRAMMAR_INC_FILE}
-    COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
+    COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT}
       --extinst-opencl-grammar=${OPENCL_GRAMMAR_JSON_FILE}
       --opencl-insts-output=${GRAMMAR_INC_FILE}
     DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${CORE_GRAMMAR_JSON_FILE} ${OPENCL_GRAMMAR_JSON_FILE}
@@ -120,7 +120,7 @@
     set(GRAMMAR_FILE "${spirv-tools_SOURCE_DIR}/source/extinst.${VENDOR_TABLE}.grammar.json")
   endif()
   add_custom_command(OUTPUT ${INSTS_FILE}
-    COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
+    COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT}
       --extinst-vendor-grammar=${GRAMMAR_FILE}
       --vendor-insts-output=${INSTS_FILE}
       --vendor-operand-kind-prefix=${OPERAND_KIND_PREFIX}
@@ -134,7 +134,7 @@
 macro(spvtools_extinst_lang_headers NAME GRAMMAR_FILE)
   set(OUT_H ${spirv-tools_BINARY_DIR}/${NAME}.h)
   add_custom_command(OUTPUT ${OUT_H}
-    COMMAND ${PYTHON_EXECUTABLE} ${LANG_HEADER_PROCESSING_SCRIPT}
+    COMMAND Python3::Interpreter ${LANG_HEADER_PROCESSING_SCRIPT}
       --extinst-grammar=${GRAMMAR_FILE}
       --extinst-output-path=${OUT_H}
     DEPENDS ${LANG_HEADER_PROCESSING_SCRIPT} ${GRAMMAR_FILE}
@@ -156,6 +156,7 @@
 spvtools_vendor_tables("opencl.debuginfo.100" "cldi100" "CLDEBUG100_")
 spvtools_vendor_tables("nonsemantic.shader.debuginfo.100" "shdi100" "SHDEBUG100_")
 spvtools_vendor_tables("nonsemantic.clspvreflection" "clspvreflection" "")
+spvtools_vendor_tables("nonsemantic.vkspreflection" "vkspreflection" "")
 spvtools_extinst_lang_headers("DebugInfo" ${DEBUGINFO_GRAMMAR_JSON_FILE})
 spvtools_extinst_lang_headers("OpenCLDebugInfo100" ${CLDEBUGINFO100_GRAMMAR_JSON_FILE})
 spvtools_extinst_lang_headers("NonSemanticShaderDebugInfo100" ${VKDEBUGINFO100_GRAMMAR_JSON_FILE})
@@ -168,7 +169,7 @@
 set(GENERATOR_INC_FILE ${spirv-tools_BINARY_DIR}/generators.inc)
 set(SPIRV_XML_REGISTRY_FILE ${SPIRV_HEADER_INCLUDE_DIR}/spirv/spir-v.xml)
 add_custom_command(OUTPUT ${GENERATOR_INC_FILE}
-  COMMAND ${PYTHON_EXECUTABLE} ${XML_REGISTRY_PROCESSING_SCRIPT}
+  COMMAND Python3::Interpreter ${XML_REGISTRY_PROCESSING_SCRIPT}
     --xml=${SPIRV_XML_REGISTRY_FILE}
     --generator-output=${GENERATOR_INC_FILE}
   DEPENDS ${XML_REGISTRY_PROCESSING_SCRIPT} ${SPIRV_XML_REGISTRY_FILE}
@@ -198,7 +199,7 @@
 set(SPIRV_TOOLS_CHANGES_FILE
   ${spirv-tools_SOURCE_DIR}/CHANGES)
 add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC}
-   COMMAND ${PYTHON_EXECUTABLE}
+   COMMAND Python3::Interpreter
            ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR}
            ${SPIRV_TOOLS_CHANGES_FILE} ${SPIRV_TOOLS_BUILD_VERSION_INC}
    DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR}
@@ -418,12 +419,6 @@
   endif()
 endif()
 
-if (ANDROID)
-    foreach(target ${SPIRV_TOOLS_TARGETS})
-        target_link_libraries(${target} PRIVATE android log)
-    endforeach()
-endif()
-
 if(ENABLE_SPIRV_TOOLS_INSTALL)
   install(TARGETS ${SPIRV_TOOLS_TARGETS} EXPORT ${SPIRV_TOOLS}Targets)
   export(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake)
diff --git a/third_party/SPIRV-Tools/source/assembly_grammar.cpp b/third_party/SPIRV-Tools/source/assembly_grammar.cpp
index 6df823e..0092d01 100644
--- a/third_party/SPIRV-Tools/source/assembly_grammar.cpp
+++ b/third_party/SPIRV-Tools/source/assembly_grammar.cpp
@@ -21,6 +21,7 @@
 #include "source/ext_inst.h"
 #include "source/opcode.h"
 #include "source/operand.h"
+#include "source/spirv_target_env.h"
 #include "source/table.h"
 
 namespace spvtools {
@@ -154,11 +155,12 @@
     CASE(InBoundsAccessChain),
     CASE(PtrAccessChain),
     CASE(InBoundsPtrAccessChain),
-    CASE(CooperativeMatrixLengthNV)
+    CASE(CooperativeMatrixLengthNV),
+    CASE(CooperativeMatrixLengthKHR)
 };
 
 // The 60 is determined by counting the opcodes listed in the spec.
-static_assert(60 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
+static_assert(61 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
               "OpSpecConstantOp opcode table is incomplete");
 #undef CASE
 // clang-format on
@@ -175,15 +177,18 @@
 CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
     const spv::Capability* cap_array, uint32_t count) const {
   CapabilitySet cap_set;
+  const auto version = spvVersionForTargetEnv(target_env_);
   for (uint32_t i = 0; i < count; ++i) {
-    spv_operand_desc cap_desc = {};
+    spv_operand_desc entry = {};
     if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
                                      static_cast<uint32_t>(cap_array[i]),
-                                     &cap_desc)) {
-      // spvOperandTableValueLookup() filters capabilities internally
-      // according to the current target environment by itself. So we
-      // should be safe to add this capability if the lookup succeeds.
-      cap_set.Add(cap_array[i]);
+                                     &entry)) {
+      // This token is visible in this environment if it's in an appropriate
+      // core version, or it is enabled by a capability or an extension.
+      if ((version >= entry->minVersion && version <= entry->lastVersion) ||
+          entry->numExtensions > 0u || entry->numCapabilities > 0u) {
+        cap_set.insert(cap_array[i]);
+      }
     }
   }
   return cap_set;
diff --git a/third_party/SPIRV-Tools/source/binary.cpp b/third_party/SPIRV-Tools/source/binary.cpp
index beb56be..cf1f0b7 100644
--- a/third_party/SPIRV-Tools/source/binary.cpp
+++ b/third_party/SPIRV-Tools/source/binary.cpp
@@ -546,6 +546,13 @@
       parsed_operand.number_bit_width = 32;
       break;
 
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT:
+      // These are regular single-word literal float operands.
+      parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_FLOAT;
+      parsed_operand.number_kind = SPV_NUMBER_FLOATING;
+      parsed_operand.number_bit_width = 32;
+      break;
+
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
       parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
@@ -626,7 +633,6 @@
     } break;
 
     case SPV_OPERAND_TYPE_CAPABILITY:
-    case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
     case SPV_OPERAND_TYPE_EXECUTION_MODEL:
     case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
     case SPV_OPERAND_TYPE_MEMORY_MODEL:
@@ -664,7 +670,8 @@
     case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
     case SPV_OPERAND_TYPE_OVERFLOW_MODES:
     case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
-    case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: {
+    case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT:
+    case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: {
       // A single word that is a plain enum value.
 
       // Map an optional operand type to its corresponding concrete type.
@@ -683,22 +690,44 @@
       spvPushOperandTypes(entry->operandTypes, expected_operands);
     } break;
 
+    case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: {
+      spv_operand_desc entry;
+      if (grammar_.lookupOperand(type, word, &entry)) {
+        return diagnostic()
+               << "Invalid " << spvOperandTypeStr(parsed_operand.type)
+               << " operand: " << word
+               << ", if you are creating a new source language please use "
+                  "value 0 "
+                  "(Unknown) and when ready, add your source language to "
+                  "SPRIV-Headers";
+      }
+      // Prepare to accept operands to this operand, if needed.
+      spvPushOperandTypes(entry->operandTypes, expected_operands);
+    } break;
+
     case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
     case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
     case SPV_OPERAND_TYPE_LOOP_CONTROL:
     case SPV_OPERAND_TYPE_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
+    case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
     case SPV_OPERAND_TYPE_SELECTION_CONTROL:
     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
-    case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: {
+    case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
+    case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
+    case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: {
       // This operand is a mask.
 
       // Map an optional operand type to its corresponding concrete type.
       if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE)
         parsed_operand.type = SPV_OPERAND_TYPE_IMAGE;
-      else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS)
+      if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS)
         parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS;
+      if (type == SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS)
+        parsed_operand.type = SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS;
+      if (type == SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS)
+        parsed_operand.type = SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS;
 
       // Check validity of set mask bits. Also prepare for operands for those
       // masks if they have any.  To get operand order correct, scan from
diff --git a/third_party/SPIRV-Tools/source/diff/diff.cpp b/third_party/SPIRV-Tools/source/diff/diff.cpp
index 6daed32..6269af5 100644
--- a/third_party/SPIRV-Tools/source/diff/diff.cpp
+++ b/third_party/SPIRV-Tools/source/diff/diff.cpp
@@ -101,9 +101,12 @@
     return from < id_map_.size() && id_map_[from] != 0;
   }
 
-  // Map any ids in src and dst that have not been mapped to new ids in dst and
-  // src respectively.
-  void MapUnmatchedIds(IdMap& other_way);
+  bool IsMapped(const opt::Instruction* from_inst) const {
+    assert(from_inst != nullptr);
+    assert(!from_inst->HasResultId());
+
+    return inst_map_.find(from_inst) != inst_map_.end();
+  }
 
   // Some instructions don't have result ids.  Those are mapped by pointer.
   void MapInsts(const opt::Instruction* from_inst,
@@ -117,6 +120,12 @@
 
   uint32_t IdBound() const { return static_cast<uint32_t>(id_map_.size()); }
 
+  // Generate a fresh id in this mapping's domain.
+  uint32_t MakeFreshId() {
+    id_map_.push_back(0);
+    return static_cast<uint32_t>(id_map_.size()) - 1;
+  }
+
  private:
   // Given an id, returns the corresponding id in the other module, or 0 if not
   // matched yet.
@@ -150,10 +159,16 @@
 
   bool IsSrcMapped(uint32_t src) { return src_to_dst_.IsMapped(src); }
   bool IsDstMapped(uint32_t dst) { return dst_to_src_.IsMapped(dst); }
+  bool IsDstMapped(const opt::Instruction* dst_inst) {
+    return dst_to_src_.IsMapped(dst_inst);
+  }
 
   // Map any ids in src and dst that have not been mapped to new ids in dst and
-  // src respectively.
-  void MapUnmatchedIds();
+  // src respectively. Use src_insn_defined and dst_insn_defined to ignore ids
+  // that are simply never defined. (Since we assume the inputs are valid
+  // SPIR-V, this implies they are also never used.)
+  void MapUnmatchedIds(std::function<bool(uint32_t)> src_insn_defined,
+                       std::function<bool(uint32_t)> dst_insn_defined);
 
   // Some instructions don't have result ids.  Those are mapped by pointer.
   void MapInsts(const opt::Instruction* src_inst,
@@ -203,6 +218,11 @@
 
   void MapIdToInstruction(uint32_t id, const opt::Instruction* inst);
 
+  // Return true if id is mapped to any instruction, false otherwise.
+  bool IsDefined(uint32_t id) {
+    return id < inst_map_.size() && inst_map_[id] != nullptr;
+  }
+
   void MapIdsToInstruction(
       opt::IteratorRange<opt::Module::const_inst_iterator> section);
   void MapIdsToInfos(
@@ -338,6 +358,59 @@
       std::function<void(const IdGroup& src_group, const IdGroup& dst_group)>
           match_group);
 
+  // Bucket `src_ids` and `dst_ids` by the key ids returned by `get_group`, and
+  // then call `match_group` on pairs of buckets whose key ids are matched with
+  // each other.
+  //
+  // For example, suppose we want to pair up groups of instructions with the
+  // same type. Naturally, the source instructions refer to their types by their
+  // ids in the source, and the destination instructions use destination type
+  // ids, so simply comparing source and destination type ids as integers, as
+  // `GroupIdsAndMatch` would do, is meaningless. But if a prior call to
+  // `MatchTypeIds` has established type matches between the two modules, then
+  // we can consult those to pair source and destination buckets whose types are
+  // equivalent.
+  //
+  // Suppose our input groups are as follows:
+  //
+  // - src_ids: { 1 -> 100, 2 -> 300, 3 -> 100, 4 -> 200 }
+  // - dst_ids: { 5 -> 10, 6 -> 20, 7 -> 10, 8 -> 300 }
+  //
+  // Here, `X -> Y` means that the instruction with SPIR-V id `X` is a member of
+  // the group, and `Y` is the id of its type. If we use
+  // `Differ::GroupIdsHelperGetTypeId` for `get_group`, then
+  // `get_group(X) == Y`.
+  //
+  // These instructions are bucketed by type as follows:
+  //
+  // - source:      [1, 3] -> 100
+  //                [4] -> 200
+  //                [2] -> 300
+  //
+  // - destination: [5, 7] -> 10
+  //                [6] -> 20
+  //                [8] -> 300
+  //
+  // Now suppose that we have previously matched up src type 100 with dst type
+  // 10, and src type 200 with dst type 20, but no other types are matched.
+  //
+  // Then `match_group` is called twice:
+  // - Once with ([1,3], [5, 7]), corresponding to 100/10
+  // - Once with ([4],[6]), corresponding to 200/20
+  //
+  // The source type 300 isn't matched with anything, so the fact that there's a
+  // destination type 300 is irrelevant, and thus 2 and 8 are never passed to
+  // `match_group`.
+  //
+  // This function isn't specific to types; it simply buckets by the ids
+  // returned from `get_group`, and consults existing matches to pair up the
+  // resulting buckets.
+  void GroupIdsAndMatchByMappedId(
+      const IdGroup& src_ids, const IdGroup& dst_ids,
+      uint32_t (Differ::*get_group)(const IdInstructions&, uint32_t),
+      std::function<void(const IdGroup& src_group, const IdGroup& dst_group)>
+          match_group);
+
   // Helper functions that determine if two instructions match
   bool DoIdsMatch(uint32_t src_id, uint32_t dst_id);
   bool DoesOperandMatch(const opt::Operand& src_operand,
@@ -504,36 +577,27 @@
   FunctionMap dst_funcs_;
 };
 
-void IdMap::MapUnmatchedIds(IdMap& other_way) {
-  const uint32_t src_id_bound = static_cast<uint32_t>(id_map_.size());
-  const uint32_t dst_id_bound = static_cast<uint32_t>(other_way.id_map_.size());
-
-  uint32_t next_src_id = src_id_bound;
-  uint32_t next_dst_id = dst_id_bound;
+void SrcDstIdMap::MapUnmatchedIds(
+    std::function<bool(uint32_t)> src_insn_defined,
+    std::function<bool(uint32_t)> dst_insn_defined) {
+  const uint32_t src_id_bound = static_cast<uint32_t>(src_to_dst_.IdBound());
+  const uint32_t dst_id_bound = static_cast<uint32_t>(dst_to_src_.IdBound());
 
   for (uint32_t src_id = 1; src_id < src_id_bound; ++src_id) {
-    if (!IsMapped(src_id)) {
-      MapIds(src_id, next_dst_id);
-
-      other_way.id_map_.push_back(0);
-      other_way.MapIds(next_dst_id++, src_id);
+    if (!src_to_dst_.IsMapped(src_id) && src_insn_defined(src_id)) {
+      uint32_t fresh_dst_id = dst_to_src_.MakeFreshId();
+      MapIds(src_id, fresh_dst_id);
     }
   }
 
   for (uint32_t dst_id = 1; dst_id < dst_id_bound; ++dst_id) {
-    if (!other_way.IsMapped(dst_id)) {
-      id_map_.push_back(0);
-      MapIds(next_src_id, dst_id);
-
-      other_way.MapIds(dst_id, next_src_id++);
+    if (!dst_to_src_.IsMapped(dst_id) && dst_insn_defined(dst_id)) {
+      uint32_t fresh_src_id = src_to_dst_.MakeFreshId();
+      MapIds(fresh_src_id, dst_id);
     }
   }
 }
 
-void SrcDstIdMap::MapUnmatchedIds() {
-  src_to_dst_.MapUnmatchedIds(dst_to_src_);
-}
-
 void IdInstructions::MapIdToInstruction(uint32_t id,
                                         const opt::Instruction* inst) {
   assert(id != 0);
@@ -889,6 +953,37 @@
   }
 }
 
+void Differ::GroupIdsAndMatchByMappedId(
+    const IdGroup& src_ids, const IdGroup& dst_ids,
+    uint32_t (Differ::*get_group)(const IdInstructions&, uint32_t),
+    std::function<void(const IdGroup& src_group, const IdGroup& dst_group)>
+        match_group) {
+  // Group the ids based on a key (get_group)
+  std::map<uint32_t, IdGroup> src_groups;
+  std::map<uint32_t, IdGroup> dst_groups;
+
+  GroupIds<uint32_t>(src_ids, true, &src_groups, get_group);
+  GroupIds<uint32_t>(dst_ids, false, &dst_groups, get_group);
+
+  // Iterate over pairs of groups whose keys map to each other.
+  for (const auto& iter : src_groups) {
+    const uint32_t& src_key = iter.first;
+    const IdGroup& src_group = iter.second;
+
+    if (src_key == 0) {
+      continue;
+    }
+
+    if (id_map_.IsSrcMapped(src_key)) {
+      const uint32_t& dst_key = id_map_.MappedDstId(src_key);
+      const IdGroup& dst_group = dst_groups[dst_key];
+
+      // Let the caller match the groups as appropriate.
+      match_group(src_group, dst_group);
+    }
+  }
+}
+
 bool Differ::DoIdsMatch(uint32_t src_id, uint32_t dst_id) {
   assert(dst_id != 0);
   return id_map_.MappedDstId(src_id) == dst_id;
@@ -1419,7 +1514,6 @@
   GroupIdsAndMatch<std::string>(
       src, dst, "", &Differ::GetSanitizedName,
       [this](const IdGroup& src_group, const IdGroup& dst_group) {
-
         // Match only if there's a unique forward declaration with this debug
         // name.
         if (src_group.size() == 1 && dst_group.size() == 1) {
@@ -1574,6 +1668,8 @@
 
     id_map_.MapIds(match_result.src_id, match_result.dst_id);
 
+    MatchFunctionParamIds(src_funcs_[match_result.src_id],
+                          dst_funcs_[match_result.dst_id]);
     MatchIdsInFunctionBodies(src_func_insts.at(match_result.src_id),
                              dst_func_insts.at(match_result.dst_id),
                              match_result.src_match, match_result.dst_match, 0);
@@ -1598,7 +1694,6 @@
   GroupIdsAndMatch<std::string>(
       src_params, dst_params, "", &Differ::GetSanitizedName,
       [this](const IdGroup& src_group, const IdGroup& dst_group) {
-
         // There shouldn't be two parameters with the same name, so the ids
         // should match. There is nothing restricting the SPIR-V however to have
         // two parameters with the same name, so be resilient against that.
@@ -1609,17 +1704,17 @@
 
   // Then match the parameters by their type.  If there are multiple of them,
   // match them by their order.
-  GroupIdsAndMatch<uint32_t>(
-      src_params, dst_params, 0, &Differ::GroupIdsHelperGetTypeId,
+  GroupIdsAndMatchByMappedId(
+      src_params, dst_params, &Differ::GroupIdsHelperGetTypeId,
       [this](const IdGroup& src_group_by_type_id,
              const IdGroup& dst_group_by_type_id) {
-
         const size_t shared_param_count =
             std::min(src_group_by_type_id.size(), dst_group_by_type_id.size());
 
         for (size_t param_index = 0; param_index < shared_param_count;
              ++param_index) {
-          id_map_.MapIds(src_group_by_type_id[0], dst_group_by_type_id[0]);
+          id_map_.MapIds(src_group_by_type_id[param_index],
+                         dst_group_by_type_id[param_index]);
         }
       });
 }
@@ -1943,6 +2038,10 @@
       // Always unsigned integers.
       *number_bit_width = 32;
       return SPV_NUMBER_UNSIGNED_INT;
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT:
+      // Always float.
+      *number_bit_width = 32;
+      return SPV_NUMBER_FLOATING;
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
       switch (inst.opcode()) {
@@ -2064,9 +2163,10 @@
     }
 
     // Otherwise match them by name.
-    bool matched = false;
     for (const opt::Instruction* src_inst : src_insts) {
       for (const opt::Instruction* dst_inst : dst_insts) {
+        if (id_map_.IsDstMapped(dst_inst)) continue;
+
         const opt::Operand& src_name = src_inst->GetOperand(2);
         const opt::Operand& dst_name = dst_inst->GetOperand(2);
 
@@ -2075,13 +2175,9 @@
           uint32_t dst_id = dst_inst->GetSingleWordOperand(1);
           id_map_.MapIds(src_id, dst_id);
           id_map_.MapInsts(src_inst, dst_inst);
-          matched = true;
           break;
         }
       }
-      if (matched) {
-        break;
-      }
     }
   }
 }
@@ -2126,7 +2222,6 @@
       spv::StorageClass::Max, &Differ::GroupIdsHelperGetTypePointerStorageClass,
       [this](const IdGroup& src_group_by_storage_class,
              const IdGroup& dst_group_by_storage_class) {
-
         // Group them further by the type they are pointing to and loop over
         // them.
         GroupIdsAndMatch<spv::Op>(
@@ -2134,7 +2229,6 @@
             spv::Op::Max, &Differ::GroupIdsHelperGetTypePointerTypeOp,
             [this](const IdGroup& src_group_by_type_op,
                    const IdGroup& dst_group_by_type_op) {
-
               // Group them even further by debug info, if possible and match by
               // debug name.
               MatchTypeForwardPointersByName(src_group_by_type_op,
@@ -2199,7 +2293,9 @@
         case spv::Op::OpTypeVoid:
         case spv::Op::OpTypeBool:
         case spv::Op::OpTypeSampler:
-          // void, bool and sampler are unique, match them.
+        case spv::Op::OpTypeAccelerationStructureNV:
+        case spv::Op::OpTypeRayQueryKHR:
+          // the above types have no operands and are unique, match them.
           return true;
         case spv::Op::OpTypeInt:
         case spv::Op::OpTypeFloat:
@@ -2378,7 +2474,6 @@
   GroupIdsAndMatch<std::string>(
       src_func_ids, dst_func_ids, "", &Differ::GetSanitizedName,
       [this](const IdGroup& src_group, const IdGroup& dst_group) {
-
         // If there is a single function with this name in src and dst, it's a
         // definite match.
         if (src_group.size() == 1 && dst_group.size() == 1) {
@@ -2392,7 +2487,6 @@
                                    &Differ::GroupIdsHelperGetTypeId,
                                    [this](const IdGroup& src_group_by_type_id,
                                           const IdGroup& dst_group_by_type_id) {
-
                                      if (src_group_by_type_id.size() == 1 &&
                                          dst_group_by_type_id.size() == 1) {
                                        id_map_.MapIds(src_group_by_type_id[0],
@@ -2437,7 +2531,6 @@
       src_func_ids, dst_func_ids, 0, &Differ::GroupIdsHelperGetTypeId,
       [this](const IdGroup& src_group_by_type_id,
              const IdGroup& dst_group_by_type_id) {
-
         BestEffortMatchFunctions(src_group_by_type_id, dst_group_by_type_id,
                                  src_func_insts_, dst_func_insts_);
       });
@@ -2647,7 +2740,9 @@
 }
 
 spv_result_t Differ::Output() {
-  id_map_.MapUnmatchedIds();
+  id_map_.MapUnmatchedIds(
+      [this](uint32_t src_id) { return src_id_to_.IsDefined(src_id); },
+      [this](uint32_t dst_id) { return dst_id_to_.IsDefined(dst_id); });
   src_id_to_.inst_map_.resize(id_map_.SrcToDstMap().IdBound(), nullptr);
   dst_id_to_.inst_map_.resize(id_map_.DstToSrcMap().IdBound(), nullptr);
 
diff --git a/third_party/SPIRV-Tools/source/disassemble.cpp b/third_party/SPIRV-Tools/source/disassemble.cpp
index f862efd..f8f6f44 100644
--- a/third_party/SPIRV-Tools/source/disassemble.cpp
+++ b/third_party/SPIRV-Tools/source/disassemble.cpp
@@ -357,7 +357,8 @@
       stream_ << opcode_desc->name;
     } break;
     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
-    case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: {
+    case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT: {
       SetRed();
       EmitNumericLiteral(&stream_, inst, operand);
       ResetColor();
@@ -424,6 +425,7 @@
     case SPV_OPERAND_TYPE_SELECTION_CONTROL:
     case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
+    case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS:
       EmitMaskOperand(operand.type, word);
       break;
     default:
diff --git a/third_party/SPIRV-Tools/source/enum_set.h b/third_party/SPIRV-Tools/source/enum_set.h
index 28ee5fe..a375138 100644
--- a/third_party/SPIRV-Tools/source/enum_set.h
+++ b/third_party/SPIRV-Tools/source/enum_set.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 Google Inc.
+// Copyright (c) 2023 Google Inc.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,195 +12,456 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <functional>
+#include <initializer_list>
+#include <limits>
+#include <type_traits>
+#include <vector>
+
 #ifndef SOURCE_ENUM_SET_H_
 #define SOURCE_ENUM_SET_H_
 
-#include <cstdint>
-#include <functional>
-#include <memory>
-#include <set>
-#include <utility>
-
 #include "source/latest_version_spirv_header.h"
-#include "source/util/make_unique.h"
 
 namespace spvtools {
 
-// A set of values of a 32-bit enum type.
-// It is fast and compact for the common case, where enum values
-// are at most 63.  But it can represent enums with larger values,
-// as may appear in extensions.
-template <typename EnumType>
+// This container is optimized to store and retrieve unsigned enum values.
+// The base model for this implementation is an open-addressing hashtable with
+// linear probing. For small enums (max index < 64), all operations are O(1).
+//
+// - Enums are stored in buckets (64 contiguous values max per bucket)
+// - Buckets ranges don't overlap, but don't have to be contiguous.
+// - Enums are packed into 64-bits buckets, using 1 bit per enum value.
+//
+// Example:
+//  - MyEnum { A = 0, B = 1, C = 64, D = 65 }
+//  - 2 buckets are required:
+//      - bucket 0, storing values in the range [ 0;  64[
+//      - bucket 1, storing values in the range [64; 128[
+//
+// - Buckets are stored in a sorted vector (sorted by bucket range).
+// - Retrieval is done by computing the theoretical bucket index using the enum
+// value, and
+//   doing a linear scan from this position.
+// - Insertion is done by retrieving the bucket and either:
+//   - inserting a new bucket in the sorted vector when no buckets has a
+//   compatible range.
+//   - setting the corresponding bit in the bucket.
+//   This means insertion in the middle/beginning can cause a memmove when no
+//   bucket is available. In our case, this happens at most 23 times for the
+//   largest enum we have (Opcodes).
+template <typename T>
 class EnumSet {
  private:
-  // The ForEach method will call the functor on enum values in
-  // enum value order (lowest to highest).  To make that easier, use
-  // an ordered set for the overflow values.
-  using OverflowSetType = std::set<uint32_t>;
+  using BucketType = uint64_t;
+  using ElementType = std::underlying_type_t<T>;
+  static_assert(std::is_enum_v<T>, "EnumSets only works with enums.");
+  static_assert(std::is_signed_v<ElementType> == false,
+                "EnumSet doesn't supports signed enums.");
+
+  // Each bucket can hold up to `kBucketSize` distinct, contiguous enum values.
+  // The first value a bucket can hold must be aligned on `kBucketSize`.
+  struct Bucket {
+    // bit mask to store `kBucketSize` enums.
+    BucketType data;
+    // 1st enum this bucket can represent.
+    T start;
+
+    friend bool operator==(const Bucket& lhs, const Bucket& rhs) {
+      return lhs.start == rhs.start && lhs.data == rhs.data;
+    }
+  };
+
+  // How many distinct values can a bucket hold? 1 bit per value.
+  static constexpr size_t kBucketSize = sizeof(BucketType) * 8ULL;
 
  public:
-  // Construct an empty set.
-  EnumSet() {}
-  // Construct an set with just the given enum value.
-  explicit EnumSet(EnumType c) { Add(c); }
-  // Construct an set from an initializer list of enum values.
-  EnumSet(std::initializer_list<EnumType> cs) {
-    for (auto c : cs) Add(c);
-  }
-  EnumSet(uint32_t count, const EnumType* ptr) {
-    for (uint32_t i = 0; i < count; ++i) Add(ptr[i]);
-  }
-  // Copy constructor.
-  EnumSet(const EnumSet& other) { *this = other; }
-  // Move constructor.  The moved-from set is emptied.
-  EnumSet(EnumSet&& other) {
-    mask_ = other.mask_;
-    overflow_ = std::move(other.overflow_);
-    other.mask_ = 0;
-    other.overflow_.reset(nullptr);
-  }
-  // Assignment operator.
-  EnumSet& operator=(const EnumSet& other) {
-    if (&other != this) {
-      mask_ = other.mask_;
-      overflow_.reset(other.overflow_ ? new OverflowSetType(*other.overflow_)
-                                      : nullptr);
+  class Iterator {
+   public:
+    typedef Iterator self_type;
+    typedef T value_type;
+    typedef T& reference;
+    typedef T* pointer;
+    typedef std::forward_iterator_tag iterator_category;
+    typedef size_t difference_type;
+
+    Iterator(const Iterator& other)
+        : set_(other.set_),
+          bucketIndex_(other.bucketIndex_),
+          bucketOffset_(other.bucketOffset_) {}
+
+    Iterator& operator++() {
+      do {
+        if (bucketIndex_ >= set_->buckets_.size()) {
+          bucketIndex_ = set_->buckets_.size();
+          bucketOffset_ = 0;
+          break;
+        }
+
+        if (bucketOffset_ + 1 == kBucketSize) {
+          bucketOffset_ = 0;
+          ++bucketIndex_;
+        } else {
+          ++bucketOffset_;
+        }
+
+      } while (bucketIndex_ < set_->buckets_.size() &&
+               !set_->HasEnumAt(bucketIndex_, bucketOffset_));
+      return *this;
     }
+
+    Iterator operator++(int) {
+      Iterator old = *this;
+      operator++();
+      return old;
+    }
+
+    T operator*() const {
+      assert(set_->HasEnumAt(bucketIndex_, bucketOffset_) &&
+             "operator*() called on an invalid iterator.");
+      return GetValueFromBucket(set_->buckets_[bucketIndex_], bucketOffset_);
+    }
+
+    bool operator!=(const Iterator& other) const {
+      return set_ != other.set_ || bucketOffset_ != other.bucketOffset_ ||
+             bucketIndex_ != other.bucketIndex_;
+    }
+
+    bool operator==(const Iterator& other) const {
+      return !(operator!=(other));
+    }
+
+    Iterator& operator=(const Iterator& other) {
+      set_ = other.set_;
+      bucketIndex_ = other.bucketIndex_;
+      bucketOffset_ = other.bucketOffset_;
+      return *this;
+    }
+
+   private:
+    Iterator(const EnumSet* set, size_t bucketIndex, ElementType bucketOffset)
+        : set_(set), bucketIndex_(bucketIndex), bucketOffset_(bucketOffset) {}
+
+   private:
+    const EnumSet* set_ = nullptr;
+    // Index of the bucket in the vector.
+    size_t bucketIndex_ = 0;
+    // Offset in bits in the current bucket.
+    ElementType bucketOffset_ = 0;
+
+    friend class EnumSet;
+  };
+
+  // Required to allow the use of std::inserter.
+  using value_type = T;
+  using const_iterator = Iterator;
+  using iterator = Iterator;
+
+ public:
+  iterator cbegin() const noexcept {
+    auto it = iterator(this, /* bucketIndex= */ 0, /* bucketOffset= */ 0);
+    if (buckets_.size() == 0) {
+      return it;
+    }
+
+    // The iterator has the logic to find the next valid bit. If the value 0
+    // is not stored, use it to find the next valid bit.
+    if (!HasEnumAt(it.bucketIndex_, it.bucketOffset_)) {
+      ++it;
+    }
+
+    return it;
+  }
+
+  iterator begin() const noexcept { return cbegin(); }
+
+  iterator cend() const noexcept {
+    return iterator(this, buckets_.size(), /* bucketOffset= */ 0);
+  }
+
+  iterator end() const noexcept { return cend(); }
+
+  // Creates an empty set.
+  EnumSet() : buckets_(0), size_(0) {}
+
+  // Creates a set and store `value` in it.
+  EnumSet(T value) : EnumSet() { insert(value); }
+
+  // Creates a set and stores each `values` in it.
+  EnumSet(std::initializer_list<T> values) : EnumSet() {
+    for (auto item : values) {
+      insert(item);
+    }
+  }
+
+  // Creates a set, and insert `count` enum values pointed by `array` in it.
+  EnumSet(ElementType count, const T* array) : EnumSet() {
+    for (ElementType i = 0; i < count; i++) {
+      insert(array[i]);
+    }
+  }
+
+  // Creates a set initialized with the content of the range [begin; end[.
+  template <class InputIt>
+  EnumSet(InputIt begin, InputIt end) : EnumSet() {
+    for (; begin != end; ++begin) {
+      insert(*begin);
+    }
+  }
+
+  // Copies the EnumSet `other` into a new EnumSet.
+  EnumSet(const EnumSet& other)
+      : buckets_(other.buckets_), size_(other.size_) {}
+
+  // Moves the EnumSet `other` into a new EnumSet.
+  EnumSet(EnumSet&& other)
+      : buckets_(std::move(other.buckets_)), size_(other.size_) {}
+
+  // Deep-copies the EnumSet `other` into this EnumSet.
+  EnumSet& operator=(const EnumSet& other) {
+    buckets_ = other.buckets_;
+    size_ = other.size_;
     return *this;
   }
 
-  friend bool operator==(const EnumSet& a, const EnumSet& b) {
-    if (a.mask_ != b.mask_) {
-      return false;
+  // Matches std::unordered_set::insert behavior.
+  std::pair<iterator, bool> insert(const T& value) {
+    const size_t index = FindBucketForValue(value);
+    const ElementType offset = ComputeBucketOffset(value);
+
+    if (index >= buckets_.size() ||
+        buckets_[index].start != ComputeBucketStart(value)) {
+      size_ += 1;
+      InsertBucketFor(index, value);
+      return std::make_pair(Iterator(this, index, offset), true);
     }
 
-    if (a.overflow_ == nullptr && b.overflow_ == nullptr) {
+    auto& bucket = buckets_[index];
+    const auto mask = ComputeMaskForValue(value);
+    if (bucket.data & mask) {
+      return std::make_pair(Iterator(this, index, offset), false);
+    }
+
+    size_ += 1;
+    bucket.data |= ComputeMaskForValue(value);
+    return std::make_pair(Iterator(this, index, offset), true);
+  }
+
+  // Inserts `value` in the set if possible.
+  // Similar to `std::unordered_set::insert`, except the hint is ignored.
+  // Returns an iterator to the inserted element, or the element preventing
+  // insertion.
+  iterator insert(const_iterator, const T& value) {
+    return insert(value).first;
+  }
+
+  // Inserts `value` in the set if possible.
+  // Similar to `std::unordered_set::insert`, except the hint is ignored.
+  // Returns an iterator to the inserted element, or the element preventing
+  // insertion.
+  iterator insert(const_iterator, T&& value) { return insert(value).first; }
+
+  // Inserts all the values in the range [`first`; `last[.
+  // Similar to `std::unordered_set::insert`.
+  template <class InputIt>
+  void insert(InputIt first, InputIt last) {
+    for (auto it = first; it != last; ++it) {
+      insert(*it);
+    }
+  }
+
+  // Removes the value `value` into the set.
+  // Similar to `std::unordered_set::erase`.
+  // Returns the number of erased elements.
+  size_t erase(const T& value) {
+    const size_t index = FindBucketForValue(value);
+    if (index >= buckets_.size() ||
+        buckets_[index].start != ComputeBucketStart(value)) {
+      return 0;
+    }
+
+    auto& bucket = buckets_[index];
+    const auto mask = ComputeMaskForValue(value);
+    if (!(bucket.data & mask)) {
+      return 0;
+    }
+
+    size_ -= 1;
+    bucket.data &= ~mask;
+    if (bucket.data == 0) {
+      buckets_.erase(buckets_.cbegin() + index);
+    }
+    return 1;
+  }
+
+  // Returns true if `value` is present in the set.
+  bool contains(T value) const {
+    const size_t index = FindBucketForValue(value);
+    if (index >= buckets_.size() ||
+        buckets_[index].start != ComputeBucketStart(value)) {
+      return false;
+    }
+    auto& bucket = buckets_[index];
+    return bucket.data & ComputeMaskForValue(value);
+  }
+
+  // Returns the 1 if `value` is present in the set, `0` otherwise.
+  inline size_t count(T value) const { return contains(value) ? 1 : 0; }
+
+  // Returns true if the set is holds no values.
+  inline bool empty() const { return size_ == 0; }
+
+  // Returns the number of enums stored in this set.
+  size_t size() const { return size_; }
+
+  // Returns true if this set contains at least one value contained in `in_set`.
+  // Note: If `in_set` is empty, this function returns true.
+  bool HasAnyOf(const EnumSet<T>& in_set) const {
+    if (in_set.empty()) {
       return true;
     }
 
-    if (a.overflow_ == nullptr || b.overflow_ == nullptr) {
-      return false;
-    }
+    auto lhs = buckets_.cbegin();
+    auto rhs = in_set.buckets_.cbegin();
 
-    return *a.overflow_ == *b.overflow_;
-  }
+    while (lhs != buckets_.cend() && rhs != in_set.buckets_.cend()) {
+      if (lhs->start == rhs->start) {
+        if (lhs->data & rhs->data) {
+          // At least 1 bit is shared. Early return.
+          return true;
+        }
 
-  friend bool operator!=(const EnumSet& a, const EnumSet& b) {
-    return !(a == b);
-  }
+        lhs++;
+        rhs++;
+        continue;
+      }
 
-  // Adds the given enum value to the set.  This has no effect if the
-  // enum value is already in the set.
-  void Add(EnumType c) { AddWord(ToWord(c)); }
+      // LHS bucket is smaller than the current RHS bucket. Catching up on RHS.
+      if (lhs->start < rhs->start) {
+        lhs++;
+        continue;
+      }
 
-  // Removes the given enum value from the set.  This has no effect if the
-  // enum value is not in the set.
-  void Remove(EnumType c) { RemoveWord(ToWord(c)); }
-
-  // Returns true if this enum value is in the set.
-  bool Contains(EnumType c) const { return ContainsWord(ToWord(c)); }
-
-  // Applies f to each enum in the set, in order from smallest enum
-  // value to largest.
-  void ForEach(std::function<void(EnumType)> f) const {
-    for (uint32_t i = 0; i < 64; ++i) {
-      if (mask_ & AsMask(i)) f(static_cast<EnumType>(i));
-    }
-    if (overflow_) {
-      for (uint32_t c : *overflow_) f(static_cast<EnumType>(c));
-    }
-  }
-
-  // Returns true if the set is empty.
-  bool IsEmpty() const {
-    if (mask_) return false;
-    if (overflow_ && !overflow_->empty()) return false;
-    return true;
-  }
-
-  // Returns true if the set contains ANY of the elements of |in_set|,
-  // or if |in_set| is empty.
-  bool HasAnyOf(const EnumSet<EnumType>& in_set) const {
-    if (in_set.IsEmpty()) return true;
-
-    if (mask_ & in_set.mask_) return true;
-
-    if (!overflow_ || !in_set.overflow_) return false;
-
-    for (uint32_t item : *in_set.overflow_) {
-      if (overflow_->find(item) != overflow_->end()) return true;
+      // Otherwise, RHS needs to catch up on LHS.
+      rhs++;
     }
 
     return false;
   }
 
  private:
-  // Adds the given enum value (as a 32-bit word) to the set.  This has no
-  // effect if the enum value is already in the set.
-  void AddWord(uint32_t word) {
-    if (auto new_bits = AsMask(word)) {
-      mask_ |= new_bits;
-    } else {
-      Overflow().insert(word);
+  // Returns the index of the last bucket in which `value` could be stored.
+  static constexpr inline size_t ComputeLargestPossibleBucketIndexFor(T value) {
+    return static_cast<size_t>(value) / kBucketSize;
+  }
+
+  // Returns the smallest enum value that could be contained in the same bucket
+  // as `value`.
+  static constexpr inline T ComputeBucketStart(T value) {
+    return static_cast<T>(kBucketSize *
+                          ComputeLargestPossibleBucketIndexFor(value));
+  }
+
+  //  Returns the index of the bit that corresponds to `value` in the bucket.
+  static constexpr inline ElementType ComputeBucketOffset(T value) {
+    return static_cast<ElementType>(value) % kBucketSize;
+  }
+
+  // Returns the bitmask used to represent the enum `value` in its bucket.
+  static constexpr inline BucketType ComputeMaskForValue(T value) {
+    return 1ULL << ComputeBucketOffset(value);
+  }
+
+  // Returns the `enum` stored in `bucket` at `offset`.
+  // `offset` is the bit-offset in the bucket storage.
+  static constexpr inline T GetValueFromBucket(const Bucket& bucket,
+                                               BucketType offset) {
+    return static_cast<T>(static_cast<ElementType>(bucket.start) + offset);
+  }
+
+  // For a given enum `value`, finds the bucket index that could contain this
+  // value. If no such bucket is found, the index at which the new bucket should
+  // be inserted is returned.
+  size_t FindBucketForValue(T value) const {
+    // Set is empty, insert at 0.
+    if (buckets_.size() == 0) {
+      return 0;
     }
-  }
 
-  // Removes the given enum value (as a 32-bit word) from the set.  This has no
-  // effect if the enum value is not in the set.
-  void RemoveWord(uint32_t word) {
-    if (auto new_bits = AsMask(word)) {
-      mask_ &= ~new_bits;
-    } else {
-      auto itr = Overflow().find(word);
-      if (itr != Overflow().end()) Overflow().erase(itr);
+    const T wanted_start = ComputeBucketStart(value);
+    assert(buckets_.size() > 0 &&
+           "Size must not be 0 here. Has the code above changed?");
+    size_t index = std::min(buckets_.size() - 1,
+                            ComputeLargestPossibleBucketIndexFor(value));
+
+    // This loops behaves like std::upper_bound with a reverse iterator.
+    // Buckets are sorted. 3 main cases:
+    //  - The bucket matches
+    //    => returns the bucket index.
+    //  - The found bucket is larger
+    //    => scans left until it finds the correct bucket, or insertion point.
+    //  - The found bucket is smaller
+    //    => We are at the end, so we return past-end index for insertion.
+    for (; buckets_[index].start >= wanted_start; index--) {
+      if (index == 0) {
+        return 0;
+      }
     }
+
+    return index + 1;
   }
 
-  // Returns true if the enum represented as a 32-bit word is in the set.
-  bool ContainsWord(uint32_t word) const {
-    // We shouldn't call Overflow() since this is a const method.
-    if (auto bits = AsMask(word)) {
-      return (mask_ & bits) != 0;
-    } else if (auto overflow = overflow_.get()) {
-      return overflow->find(word) != overflow->end();
+  // Creates a new bucket to store `value` and inserts it at `index`.
+  // If the `index` is past the end, the bucket is inserted at the end of the
+  // vector.
+  void InsertBucketFor(size_t index, T value) {
+    const T bucket_start = ComputeBucketStart(value);
+    Bucket bucket = {1ULL << ComputeBucketOffset(value), bucket_start};
+    auto it = buckets_.emplace(buckets_.begin() + index, std::move(bucket));
+#if defined(NDEBUG)
+    (void)it;  // Silencing unused variable warning.
+#else
+    assert(std::next(it) == buckets_.end() ||
+           std::next(it)->start > bucket_start);
+    assert(it == buckets_.begin() || std::prev(it)->start < bucket_start);
+#endif
+  }
+
+  // Returns true if the bucket at `bucketIndex/ stores the enum at
+  // `bucketOffset`, false otherwise.
+  bool HasEnumAt(size_t bucketIndex, BucketType bucketOffset) const {
+    assert(bucketIndex < buckets_.size());
+    assert(bucketOffset < kBucketSize);
+    return buckets_[bucketIndex].data & (1ULL << bucketOffset);
+  }
+
+  // Returns true if `lhs` and `rhs` hold the exact same values.
+  friend bool operator==(const EnumSet& lhs, const EnumSet& rhs) {
+    if (lhs.size_ != rhs.size_) {
+      return false;
     }
-    // The word is large, but the set doesn't have large members, so
-    // it doesn't have an overflow set.
-    return false;
-  }
 
-  // Returns the enum value as a uint32_t.
-  uint32_t ToWord(EnumType value) const {
-    static_assert(sizeof(EnumType) <= sizeof(uint32_t),
-                  "EnumType must statically castable to uint32_t");
-    return static_cast<uint32_t>(value);
-  }
-
-  // Determines whether the given enum value can be represented
-  // as a bit in a uint64_t mask. If so, then returns that mask bit.
-  // Otherwise, returns 0.
-  uint64_t AsMask(uint32_t word) const {
-    if (word > 63) return 0;
-    return uint64_t(1) << word;
-  }
-
-  // Ensures that overflow_set_ references a set.  A new empty set is
-  // allocated if one doesn't exist yet.  Returns overflow_set_.
-  OverflowSetType& Overflow() {
-    if (overflow_.get() == nullptr) {
-      overflow_ = MakeUnique<OverflowSetType>();
+    if (lhs.buckets_.size() != rhs.buckets_.size()) {
+      return false;
     }
-    return *overflow_;
+    return lhs.buckets_ == rhs.buckets_;
   }
 
-  // Enums with values up to 63 are stored as bits in this mask.
-  uint64_t mask_ = 0;
-  // Enums with values larger than 63 are stored in this set.
-  // This set should normally be empty or very small.
-  std::unique_ptr<OverflowSetType> overflow_ = {};
+  // Returns true if `lhs` and `rhs` hold at least 1 different value.
+  friend bool operator!=(const EnumSet& lhs, const EnumSet& rhs) {
+    return !(lhs == rhs);
+  }
+
+  // Storage for the buckets.
+  std::vector<Bucket> buckets_;
+  // How many enums is this set storing.
+  size_t size_ = 0;
 };
 
-// A set of spv::Capability, optimized for small capability values.
+// A set of spv::Capability.
 using CapabilitySet = EnumSet<spv::Capability>;
 
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/ext_inst.cpp b/third_party/SPIRV-Tools/source/ext_inst.cpp
index 4e27954..9a5ba84 100644
--- a/third_party/SPIRV-Tools/source/ext_inst.cpp
+++ b/third_party/SPIRV-Tools/source/ext_inst.cpp
@@ -30,6 +30,7 @@
 #include "glsl.std.450.insts.inc"
 #include "nonsemantic.clspvreflection.insts.inc"
 #include "nonsemantic.shader.debuginfo.100.insts.inc"
+#include "nonsemantic.vkspreflection.insts.inc"
 #include "opencl.debuginfo.100.insts.inc"
 #include "opencl.std.insts.inc"
 
@@ -62,6 +63,9 @@
     {SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION,
      ARRAY_SIZE(nonsemantic_clspvreflection_entries),
      nonsemantic_clspvreflection_entries},
+    {SPV_EXT_INST_TYPE_NONSEMANTIC_VKSPREFLECTION,
+     ARRAY_SIZE(nonsemantic_vkspreflection_entries),
+     nonsemantic_vkspreflection_entries},
 };
 
 static const spv_ext_inst_table_t kTable_1_0 = {ARRAY_SIZE(kGroups_1_0),
@@ -138,6 +142,9 @@
   if (!strncmp("NonSemantic.ClspvReflection.", name, 28)) {
     return SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION;
   }
+  if (!strncmp("NonSemantic.VkspReflection.", name, 27)) {
+    return SPV_EXT_INST_TYPE_NONSEMANTIC_VKSPREFLECTION;
+  }
   // ensure to add any known non-semantic extended instruction sets
   // above this point, and update spvExtInstIsNonSemantic()
   if (!strncmp("NonSemantic.", name, 12)) {
@@ -149,7 +156,8 @@
 bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type) {
   if (type == SPV_EXT_INST_TYPE_NONSEMANTIC_UNKNOWN ||
       type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100 ||
-      type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) {
+      type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION ||
+      type == SPV_EXT_INST_TYPE_NONSEMANTIC_VKSPREFLECTION) {
     return true;
   }
   return false;
diff --git a/third_party/SPIRV-Tools/source/extensions.cpp b/third_party/SPIRV-Tools/source/extensions.cpp
index ebf6bec..ac987fc 100644
--- a/third_party/SPIRV-Tools/source/extensions.cpp
+++ b/third_party/SPIRV-Tools/source/extensions.cpp
@@ -40,8 +40,9 @@
 
 std::string ExtensionSetToString(const ExtensionSet& extensions) {
   std::stringstream ss;
-  extensions.ForEach(
-      [&ss](Extension ext) { ss << ExtensionToString(ext) << " "; });
+  for (auto extension : extensions) {
+    ss << ExtensionToString(extension) << " ";
+  }
   return ss.str();
 }
 
diff --git a/third_party/SPIRV-Tools/source/extensions.h b/third_party/SPIRV-Tools/source/extensions.h
index 8023444..cda4924 100644
--- a/third_party/SPIRV-Tools/source/extensions.h
+++ b/third_party/SPIRV-Tools/source/extensions.h
@@ -15,6 +15,7 @@
 #ifndef SOURCE_EXTENSIONS_H_
 #define SOURCE_EXTENSIONS_H_
 
+#include <cstdint>
 #include <string>
 
 #include "source/enum_set.h"
@@ -23,7 +24,7 @@
 namespace spvtools {
 
 // The known SPIR-V extensions.
-enum Extension {
+enum Extension : uint32_t {
 #include "extension_enum.inc"
 };
 
diff --git a/third_party/SPIRV-Tools/source/fuzz/transformation_add_no_contraction_decoration.cpp b/third_party/SPIRV-Tools/source/fuzz/transformation_add_no_contraction_decoration.cpp
index 07a31e5..87393e9 100644
--- a/third_party/SPIRV-Tools/source/fuzz/transformation_add_no_contraction_decoration.cpp
+++ b/third_party/SPIRV-Tools/source/fuzz/transformation_add_no_contraction_decoration.cpp
@@ -36,6 +36,11 @@
   if (!instr) {
     return false;
   }
+  // |instr| must not be decorated with NoContraction.
+  if (ir_context->get_decoration_mgr()->HasDecoration(
+          message_.result_id(), spv::Decoration::NoContraction)) {
+    return false;
+  }
   // The instruction must be arithmetic.
   return IsArithmetic(instr->opcode());
 }
diff --git a/third_party/SPIRV-Tools/source/fuzz/transformation_add_relaxed_decoration.cpp b/third_party/SPIRV-Tools/source/fuzz/transformation_add_relaxed_decoration.cpp
index 6cd4ecb..601546c 100644
--- a/third_party/SPIRV-Tools/source/fuzz/transformation_add_relaxed_decoration.cpp
+++ b/third_party/SPIRV-Tools/source/fuzz/transformation_add_relaxed_decoration.cpp
@@ -36,6 +36,11 @@
   if (!instr) {
     return false;
   }
+  // |instr| must not be decorated with RelaxedPrecision.
+  if (ir_context->get_decoration_mgr()->HasDecoration(
+          message_.result_id(), spv::Decoration::RelaxedPrecision)) {
+    return false;
+  }
   opt::BasicBlock* cur_block = ir_context->get_instr_block(instr);
   // The instruction must have a block.
   if (cur_block == nullptr) {
@@ -46,6 +51,7 @@
           cur_block->id()))) {
     return false;
   }
+
   // The instruction must be numeric.
   return IsNumeric(instr->opcode());
 }
diff --git a/third_party/SPIRV-Tools/source/link/linker.cpp b/third_party/SPIRV-Tools/source/link/linker.cpp
index e50391a..58930e4 100644
--- a/third_party/SPIRV-Tools/source/link/linker.cpp
+++ b/third_party/SPIRV-Tools/source/link/linker.cpp
@@ -91,7 +91,8 @@
 // should be non-null. |max_id_bound| should be strictly greater than 0.
 spv_result_t GenerateHeader(const MessageConsumer& consumer,
                             const std::vector<opt::Module*>& modules,
-                            uint32_t max_id_bound, opt::ModuleHeader* header);
+                            uint32_t max_id_bound, opt::ModuleHeader* header,
+                            const LinkerOptions& options);
 
 // Merge all the modules from |in_modules| into a single module owned by
 // |linked_context|.
@@ -202,7 +203,8 @@
 
 spv_result_t GenerateHeader(const MessageConsumer& consumer,
                             const std::vector<opt::Module*>& modules,
-                            uint32_t max_id_bound, opt::ModuleHeader* header) {
+                            uint32_t max_id_bound, opt::ModuleHeader* header,
+                            const LinkerOptions& options) {
   spv_position_t position = {};
 
   if (modules.empty())
@@ -212,10 +214,12 @@
     return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
            << "|max_id_bound| of GenerateHeader should not be null.";
 
-  const uint32_t linked_version = modules.front()->version();
+  uint32_t linked_version = modules.front()->version();
   for (std::size_t i = 1; i < modules.size(); ++i) {
     const uint32_t module_version = modules[i]->version();
-    if (module_version != linked_version)
+    if (options.GetUseHighestVersion()) {
+      linked_version = std::max(linked_version, module_version);
+    } else if (module_version != linked_version) {
       return DiagnosticStream({0, 0, 1}, consumer, "", SPV_ERROR_INTERNAL)
              << "Conflicting SPIR-V versions: "
              << SPV_SPIRV_VERSION_MAJOR_PART(linked_version) << "."
@@ -224,6 +228,7 @@
              << SPV_SPIRV_VERSION_MAJOR_PART(module_version) << "."
              << SPV_SPIRV_VERSION_MINOR_PART(module_version)
              << " (input module " << (i + 1) << ").";
+    }
   }
 
   header->magic_number = spv::MagicNumber;
@@ -753,7 +758,7 @@
 
   // Phase 2: Generate the header
   opt::ModuleHeader header;
-  res = GenerateHeader(consumer, modules, max_id_bound, &header);
+  res = GenerateHeader(consumer, modules, max_id_bound, &header, options);
   if (res != SPV_SUCCESS) return res;
   IRContext linked_context(c_context->target_env, consumer);
   linked_context.module()->SetHeader(header);
diff --git a/third_party/SPIRV-Tools/source/opcode.cpp b/third_party/SPIRV-Tools/source/opcode.cpp
index d26024a..787dbb3 100644
--- a/third_party/SPIRV-Tools/source/opcode.cpp
+++ b/third_party/SPIRV-Tools/source/opcode.cpp
@@ -274,6 +274,7 @@
     case spv::Op::OpTypeArray:
     case spv::Op::OpTypeStruct:
     case spv::Op::OpTypeCooperativeMatrixNV:
+    case spv::Op::OpTypeCooperativeMatrixKHR:
       return true;
     default:
       return false;
@@ -294,6 +295,7 @@
     case spv::Op::OpPtrAccessChain:
     case spv::Op::OpLoad:
     case spv::Op::OpConstantNull:
+    case spv::Op::OpRawAccessChainNV:
       return true;
     default:
       return false;
@@ -308,6 +310,7 @@
     case spv::Op::OpFunctionParameter:
     case spv::Op::OpImageTexelPointer:
     case spv::Op::OpCopyObject:
+    case spv::Op::OpRawAccessChainNV:
       return true;
     default:
       return false;
@@ -340,6 +343,7 @@
     case spv::Op::OpTypeNamedBarrier:
     case spv::Op::OpTypeAccelerationStructureNV:
     case spv::Op::OpTypeCooperativeMatrixNV:
+    case spv::Op::OpTypeCooperativeMatrixKHR:
     // case spv::Op::OpTypeAccelerationStructureKHR: covered by
     // spv::Op::OpTypeAccelerationStructureNV
     case spv::Op::OpTypeRayQueryKHR:
@@ -532,6 +536,8 @@
     case spv::Op::OpGroupNonUniformQuadBroadcast:
     case spv::Op::OpGroupNonUniformQuadSwap:
     case spv::Op::OpGroupNonUniformRotateKHR:
+    case spv::Op::OpGroupNonUniformQuadAllKHR:
+    case spv::Op::OpGroupNonUniformQuadAnyKHR:
       return true;
     default:
       return false;
@@ -750,6 +756,7 @@
     case spv::Op::OpInBoundsAccessChain:
     case spv::Op::OpPtrAccessChain:
     case spv::Op::OpInBoundsPtrAccessChain:
+    case spv::Op::OpRawAccessChainNV:
       return true;
     default:
       return false;
diff --git a/third_party/SPIRV-Tools/source/operand.cpp b/third_party/SPIRV-Tools/source/operand.cpp
index 31a6c59..7848846 100644
--- a/third_party/SPIRV-Tools/source/operand.cpp
+++ b/third_party/SPIRV-Tools/source/operand.cpp
@@ -26,7 +26,6 @@
 #include "source/macro.h"
 #include "source/opcode.h"
 #include "source/spirv_constant.h"
-#include "source/spirv_target_env.h"
 
 // For now, assume unified1 contains up to SPIR-V 1.3 and no later
 // SPIR-V version.
@@ -48,7 +47,7 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t spvOperandTableNameLookup(spv_target_env env,
+spv_result_t spvOperandTableNameLookup(spv_target_env,
                                        const spv_operand_table table,
                                        const spv_operand_type_t type,
                                        const char* name,
@@ -57,31 +56,18 @@
   if (!table) return SPV_ERROR_INVALID_TABLE;
   if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
 
-  const auto version = spvVersionForTargetEnv(env);
   for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) {
     const auto& group = table->types[typeIndex];
     if (type != group.type) continue;
     for (uint64_t index = 0; index < group.count; ++index) {
       const auto& entry = group.entries[index];
       // We consider the current operand as available as long as
-      // 1. The target environment satisfies the minimal requirement of the
-      //    operand; or
-      // 2. There is at least one extension enabling this operand; or
-      // 3. There is at least one capability enabling this operand.
-      //
-      // Note that the second rule assumes the extension enabling this operand
-      // is indeed requested in the SPIR-V code; checking that should be
-      // validator's work.
+      // it is in the grammar.  It might not be *valid* to use,
+      // but that should be checked by the validator, not by parsing.
       if (nameLength == strlen(entry.name) &&
           !strncmp(entry.name, name, nameLength)) {
-        if ((version >= entry.minVersion && version <= entry.lastVersion) ||
-            entry.numExtensions > 0u || entry.numCapabilities > 0u) {
-          *pEntry = &entry;
-          return SPV_SUCCESS;
-        } else {
-          // if there is no extension/capability then the version is wrong
-          return SPV_ERROR_WRONG_VERSION;
-        }
+        *pEntry = &entry;
+        return SPV_SUCCESS;
       }
     }
   }
@@ -89,7 +75,7 @@
   return SPV_ERROR_INVALID_LOOKUP;
 }
 
-spv_result_t spvOperandTableValueLookup(spv_target_env env,
+spv_result_t spvOperandTableValueLookup(spv_target_env,
                                         const spv_operand_table table,
                                         const spv_operand_type_t type,
                                         const uint32_t value,
@@ -110,33 +96,15 @@
     const auto beg = group.entries;
     const auto end = group.entries + group.count;
 
-    // We need to loop here because there can exist multiple symbols for the
-    // same operand value, and they can be introduced in different target
-    // environments, which means they can have different minimal version
-    // requirements. For example, SubgroupEqMaskKHR can exist in any SPIR-V
-    // version as long as the SPV_KHR_shader_ballot extension is there; but
-    // starting from SPIR-V 1.3, SubgroupEqMask, which has the same numeric
-    // value as SubgroupEqMaskKHR, is available in core SPIR-V without extension
-    // requirements.
     // Assumes the underlying table is already sorted ascendingly according to
     // opcode value.
-    const auto version = spvVersionForTargetEnv(env);
-    for (auto it = std::lower_bound(beg, end, needle, comp);
-         it != end && it->value == value; ++it) {
-      // We consider the current operand as available as long as
-      // 1. The target environment satisfies the minimal requirement of the
-      //    operand; or
-      // 2. There is at least one extension enabling this operand; or
-      // 3. There is at least one capability enabling this operand.
-      //
-      // Note that the second rule assumes the extension enabling this operand
-      // is indeed requested in the SPIR-V code; checking that should be
-      // validator's work.
-      if ((version >= it->minVersion && version <= it->lastVersion) ||
-          it->numExtensions > 0u || it->numCapabilities > 0u) {
-        *pEntry = it;
-        return SPV_SUCCESS;
-      }
+    auto it = std::lower_bound(beg, end, needle, comp);
+    if (it != end && it->value == value) {
+      // The current operand is considered available as long as
+      // it is in the grammar.  It might not be *valid* to use,
+      // but that should be checked by the validator, not by parsing.
+      *pEntry = it;
+      return SPV_SUCCESS;
     }
   }
 
@@ -155,6 +123,7 @@
     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT:
       return "literal number";
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
       return "possibly multi-word literal integer";
@@ -236,6 +205,26 @@
     case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
     case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT:
       return "packed vector format";
+    case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
+    case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS:
+      return "cooperative matrix operands";
+    case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT:
+      return "cooperative matrix layout";
+    case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE:
+      return "cooperative matrix use";
+    case SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER:
+      return "initialization mode qualifier";
+    case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER:
+      return "host access qualifier";
+    case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL:
+      return "load cache control";
+    case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL:
+      return "store cache control";
+    case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS:
+      return "named maximum number of registers";
+    case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS:
+    case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
+      return "raw access chain operands";
     case SPV_OPERAND_TYPE_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
       return "image";
@@ -325,6 +314,7 @@
   }
   switch (type) {
     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT:
     case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER:
     case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER:
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
@@ -369,6 +359,13 @@
     case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
     case SPV_OPERAND_TYPE_OVERFLOW_MODES:
     case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
+    case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT:
+    case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE:
+    case SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER:
+    case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER:
+    case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL:
+    case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL:
+    case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS:
       return true;
     default:
       break;
@@ -387,6 +384,8 @@
     case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE:
     case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
+    case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
+    case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS:
       return true;
     default:
       break;
@@ -405,7 +404,9 @@
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING:
     case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
     case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT:
+    case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS:
     case SPV_OPERAND_TYPE_OPTIONAL_CIV:
+    case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
       return true;
     default:
       break;
diff --git a/third_party/SPIRV-Tools/source/operand.h b/third_party/SPIRV-Tools/source/operand.h
index a3010d9..f74c933 100644
--- a/third_party/SPIRV-Tools/source/operand.h
+++ b/third_party/SPIRV-Tools/source/operand.h
@@ -57,12 +57,6 @@
 // Gets the name string of the non-variable operand type.
 const char* spvOperandTypeStr(spv_operand_type_t type);
 
-// Returns true if the given type is concrete.
-bool spvOperandIsConcrete(spv_operand_type_t type);
-
-// Returns true if the given type is concrete and also a mask.
-bool spvOperandIsConcreteMask(spv_operand_type_t type);
-
 // Returns true if an operand of the given type is optional.
 bool spvOperandIsOptional(spv_operand_type_t type);
 
diff --git a/third_party/SPIRV-Tools/source/opt/CMakeLists.txt b/third_party/SPIRV-Tools/source/opt/CMakeLists.txt
index eea3c47..4e7d92d 100644
--- a/third_party/SPIRV-Tools/source/opt/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/source/opt/CMakeLists.txt
@@ -71,6 +71,7 @@
   instruction_list.h
   instrument_pass.h
   interface_var_sroa.h
+  invocation_interlock_placement_pass.h
   interp_fixup_pass.h
   ir_builder.h
   ir_context.h
@@ -93,6 +94,7 @@
   loop_unswitch_pass.h
   mem_pass.h
   merge_return_pass.h
+  modify_maximal_reconvergence.h
   module.h
   null_pass.h
   passes.h
@@ -121,7 +123,9 @@
   strip_debug_info_pass.h
   strip_nonsemantic_info_pass.h
   struct_cfg_analysis.h
+  switch_descriptorset_pass.h
   tree_iterator.h
+  trim_capabilities_pass.h
   type_manager.h
   types.h
   unify_const_pass.h
@@ -189,6 +193,7 @@
   instruction_list.cpp
   instrument_pass.cpp
   interface_var_sroa.cpp
+  invocation_interlock_placement_pass.cpp
   interp_fixup_pass.cpp
   ir_context.cpp
   ir_loader.cpp
@@ -210,6 +215,7 @@
   loop_unswitch_pass.cpp
   mem_pass.cpp
   merge_return_pass.cpp
+  modify_maximal_reconvergence.cpp
   module.cpp
   optimizer.cpp
   pass.cpp
@@ -236,6 +242,8 @@
   strip_debug_info_pass.cpp
   strip_nonsemantic_info_pass.cpp
   struct_cfg_analysis.cpp
+  switch_descriptorset_pass.cpp
+  trim_capabilities_pass.cpp
   type_manager.cpp
   types.cpp
   unify_const_pass.cpp
diff --git a/third_party/SPIRV-Tools/source/opt/aggressive_dead_code_elim_pass.cpp b/third_party/SPIRV-Tools/source/opt/aggressive_dead_code_elim_pass.cpp
index 1645638..4737da5 100644
--- a/third_party/SPIRV-Tools/source/opt/aggressive_dead_code_elim_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/aggressive_dead_code_elim_pass.cpp
@@ -438,6 +438,9 @@
     const Instruction* inst) {
   assert(inst->opcode() == spv::Op::OpFunctionCall);
   std::vector<uint32_t> live_variables;
+  // NOTE: we should only be checking function call parameters here, not the
+  // function itself, however, `IsPtr` will trivially return false for
+  // OpFunction
   inst->ForEachInId([this, &live_variables](const uint32_t* operand_id) {
     if (!IsPtr(*operand_id)) return;
     uint32_t var_id = GetVariableId(*operand_id);
@@ -938,6 +941,8 @@
 
 void AggressiveDCEPass::InitExtensions() {
   extensions_allowlist_.clear();
+
+  // clang-format off
   extensions_allowlist_.insert({
       "SPV_AMD_shader_explicit_vertex_parameter",
       "SPV_AMD_shader_trinary_minmax",
@@ -980,11 +985,13 @@
       "SPV_NV_shader_image_footprint",
       "SPV_NV_shading_rate",
       "SPV_NV_mesh_shader",
+      "SPV_EXT_mesh_shader",
       "SPV_NV_ray_tracing",
       "SPV_KHR_ray_tracing",
       "SPV_KHR_ray_query",
       "SPV_EXT_fragment_invocation_density",
       "SPV_EXT_physical_storage_buffer",
+      "SPV_KHR_physical_storage_buffer",
       "SPV_KHR_terminate_invocation",
       "SPV_KHR_shader_clock",
       "SPV_KHR_vulkan_memory_model",
@@ -994,7 +1001,12 @@
       "SPV_KHR_non_semantic_info",
       "SPV_KHR_uniform_group_instructions",
       "SPV_KHR_fragment_shader_barycentric",
+      "SPV_NV_bindless_texture",
+      "SPV_EXT_shader_atomic_float_add",
+      "SPV_EXT_fragment_shader_interlock",
+      "SPV_NV_compute_shader_derivatives"
   });
+  // clang-format on
 }
 
 Instruction* AggressiveDCEPass::GetHeaderBranch(BasicBlock* blk) {
diff --git a/third_party/SPIRV-Tools/source/opt/block_merge_util.cpp b/third_party/SPIRV-Tools/source/opt/block_merge_util.cpp
index fe23e36..42f695f 100644
--- a/third_party/SPIRV-Tools/source/opt/block_merge_util.cpp
+++ b/third_party/SPIRV-Tools/source/opt/block_merge_util.cpp
@@ -98,6 +98,17 @@
     return false;
   }
 
+  // Note: This means that the instructions in a break block will execute as if
+  // they were still diverged according to the loop iteration. This restricts
+  // potential transformations an implementation may perform on the IR to match
+  // shader author expectations. Similarly, instructions in the loop construct
+  // cannot be moved into the continue construct unless it can be proven that
+  // invocations are always converged.
+  if (succ_is_merge && context->get_feature_mgr()->HasExtension(
+                           kSPV_KHR_maximal_reconvergence)) {
+    return false;
+  }
+
   if (pred_is_merge && IsContinue(context, lab_id)) {
     // Cannot merge a continue target with a merge block.
     return false;
diff --git a/third_party/SPIRV-Tools/source/opt/const_folding_rules.cpp b/third_party/SPIRV-Tools/source/opt/const_folding_rules.cpp
index 2610808..17900af 100644
--- a/third_party/SPIRV-Tools/source/opt/const_folding_rules.cpp
+++ b/third_party/SPIRV-Tools/source/opt/const_folding_rules.cpp
@@ -21,6 +21,59 @@
 namespace {
 constexpr uint32_t kExtractCompositeIdInIdx = 0;
 
+// Returns the value obtained by extracting the |number_of_bits| least
+// significant bits from |value|, and sign-extending it to 64-bits.
+uint64_t SignExtendValue(uint64_t value, uint32_t number_of_bits) {
+  if (number_of_bits == 64) return value;
+
+  uint64_t mask_for_sign_bit = 1ull << (number_of_bits - 1);
+  uint64_t mask_for_significant_bits = (mask_for_sign_bit << 1) - 1ull;
+  if (value & mask_for_sign_bit) {
+    // Set upper bits to 1
+    value |= ~mask_for_significant_bits;
+  } else {
+    // Clear the upper bits
+    value &= mask_for_significant_bits;
+  }
+  return value;
+}
+
+// Returns the value obtained by extracting the |number_of_bits| least
+// significant bits from |value|, and zero-extending it to 64-bits.
+uint64_t ZeroExtendValue(uint64_t value, uint32_t number_of_bits) {
+  if (number_of_bits == 64) return value;
+
+  uint64_t mask_for_first_bit_to_clear = 1ull << (number_of_bits);
+  uint64_t mask_for_bits_to_keep = mask_for_first_bit_to_clear - 1;
+  value &= mask_for_bits_to_keep;
+  return value;
+}
+
+// Returns a constant whose value is `value` and type is `type`. This constant
+// will be generated by `const_mgr`. The type must be a scalar integer type.
+const analysis::Constant* GenerateIntegerConstant(
+    const analysis::Integer* integer_type, uint64_t result,
+    analysis::ConstantManager* const_mgr) {
+  assert(integer_type != nullptr);
+
+  std::vector<uint32_t> words;
+  if (integer_type->width() == 64) {
+    // In the 64-bit case, two words are needed to represent the value.
+    words = {static_cast<uint32_t>(result),
+             static_cast<uint32_t>(result >> 32)};
+  } else {
+    // In all other cases, only a single word is needed.
+    assert(integer_type->width() <= 32);
+    if (integer_type->IsSigned()) {
+      result = SignExtendValue(result, integer_type->width());
+    } else {
+      result = ZeroExtendValue(result, integer_type->width());
+    }
+    words = {static_cast<uint32_t>(result)};
+  }
+  return const_mgr->GetConstant(integer_type, words);
+}
+
 // Returns a constants with the value NaN of the given type.  Only works for
 // 32-bit and 64-bit float point types.  Returns |nullptr| if an error occurs.
 const analysis::Constant* GetNan(const analysis::Type* type,
@@ -88,6 +141,22 @@
   return nullptr;
 }
 
+// Returns a constants with the value |-val| of the given type.
+const analysis::Constant* NegateIntConst(const analysis::Type* result_type,
+                                         const analysis::Constant* val,
+                                         analysis::ConstantManager* const_mgr) {
+  const analysis::Integer* int_type = result_type->AsInteger();
+  assert(int_type != nullptr);
+
+  if (val->AsNullConstant()) {
+    return val;
+  }
+
+  uint64_t new_value = static_cast<uint64_t>(-val->GetSignExtendedValue());
+  return const_mgr->GetIntConst(new_value, int_type->width(),
+                                int_type->IsSigned());
+}
+
 // Folds an OpcompositeExtract where input is a composite constant.
 ConstantFoldingRule FoldExtractWithConstants() {
   return [](IRContext* context, Instruction* inst,
@@ -341,6 +410,69 @@
   };
 }
 
+// Returns to the constant that results from tranposing |matrix|. The result
+// will have type |result_type|, and |matrix| must exist in |context|. The
+// result constant will also exist in |context|.
+const analysis::Constant* TransposeMatrix(const analysis::Constant* matrix,
+                                          analysis::Matrix* result_type,
+                                          IRContext* context) {
+  analysis::ConstantManager* const_mgr = context->get_constant_mgr();
+  if (matrix->AsNullConstant() != nullptr) {
+    return const_mgr->GetNullCompositeConstant(result_type);
+  }
+
+  const auto& columns = matrix->AsMatrixConstant()->GetComponents();
+  uint32_t number_of_rows = columns[0]->type()->AsVector()->element_count();
+
+  // Collect the ids of the elements in their new positions.
+  std::vector<std::vector<uint32_t>> result_elements(number_of_rows);
+  for (const analysis::Constant* column : columns) {
+    if (column->AsNullConstant()) {
+      column = const_mgr->GetNullCompositeConstant(column->type());
+    }
+    const auto& column_components = column->AsVectorConstant()->GetComponents();
+
+    for (uint32_t row = 0; row < number_of_rows; ++row) {
+      result_elements[row].push_back(
+          const_mgr->GetDefiningInstruction(column_components[row])
+              ->result_id());
+    }
+  }
+
+  // Create the constant for each row in the result, and collect the ids.
+  std::vector<uint32_t> result_columns(number_of_rows);
+  for (uint32_t col = 0; col < number_of_rows; ++col) {
+    auto* element = const_mgr->GetConstant(result_type->element_type(),
+                                           result_elements[col]);
+    result_columns[col] =
+        const_mgr->GetDefiningInstruction(element)->result_id();
+  }
+
+  // Create the matrix constant from the row ids, and return it.
+  return const_mgr->GetConstant(result_type, result_columns);
+}
+
+const analysis::Constant* FoldTranspose(
+    IRContext* context, Instruction* inst,
+    const std::vector<const analysis::Constant*>& constants) {
+  assert(inst->opcode() == spv::Op::OpTranspose);
+
+  analysis::TypeManager* type_mgr = context->get_type_mgr();
+  if (!inst->IsFloatingPointFoldingAllowed()) {
+    if (HasFloatingPoint(type_mgr->GetType(inst->type_id()))) {
+      return nullptr;
+    }
+  }
+
+  const analysis::Constant* matrix = constants[0];
+  if (matrix == nullptr) {
+    return nullptr;
+  }
+
+  auto* result_type = type_mgr->GetType(inst->type_id());
+  return TransposeMatrix(matrix, result_type->AsMatrix(), context);
+}
+
 ConstantFoldingRule FoldVectorTimesMatrix() {
   return [](IRContext* context, Instruction* inst,
             const std::vector<const analysis::Constant*>& constants)
@@ -376,13 +508,7 @@
     assert(c1->type()->AsVector()->element_type() == element_type &&
            c2->type()->AsMatrix()->element_type() == vector_type);
 
-    // Get a float vector that is the result of vector-times-matrix.
-    std::vector<const analysis::Constant*> c1_components =
-        c1->GetVectorComponents(const_mgr);
-    std::vector<const analysis::Constant*> c2_components =
-        c2->AsMatrixConstant()->GetComponents();
     uint32_t resultVectorSize = result_type->AsVector()->element_count();
-
     std::vector<uint32_t> ids;
 
     if ((c1 && c1->IsZero()) || (c2 && c2->IsZero())) {
@@ -395,6 +521,12 @@
       return const_mgr->GetConstant(vector_type, ids);
     }
 
+    // Get a float vector that is the result of vector-times-matrix.
+    std::vector<const analysis::Constant*> c1_components =
+        c1->GetVectorComponents(const_mgr);
+    std::vector<const analysis::Constant*> c2_components =
+        c2->AsMatrixConstant()->GetComponents();
+
     if (float_type->width() == 32) {
       for (uint32_t i = 0; i < resultVectorSize; ++i) {
         float result_scalar = 0.0f;
@@ -472,13 +604,7 @@
     assert(c1->type()->AsMatrix()->element_type() == vector_type);
     assert(c2->type()->AsVector()->element_type() == element_type);
 
-    // Get a float vector that is the result of matrix-times-vector.
-    std::vector<const analysis::Constant*> c1_components =
-        c1->AsMatrixConstant()->GetComponents();
-    std::vector<const analysis::Constant*> c2_components =
-        c2->GetVectorComponents(const_mgr);
     uint32_t resultVectorSize = result_type->AsVector()->element_count();
-
     std::vector<uint32_t> ids;
 
     if ((c1 && c1->IsZero()) || (c2 && c2->IsZero())) {
@@ -491,6 +617,12 @@
       return const_mgr->GetConstant(vector_type, ids);
     }
 
+    // Get a float vector that is the result of matrix-times-vector.
+    std::vector<const analysis::Constant*> c1_components =
+        c1->AsMatrixConstant()->GetComponents();
+    std::vector<const analysis::Constant*> c2_components =
+        c2->GetVectorComponents(const_mgr);
+
     if (float_type->width() == 32) {
       for (uint32_t i = 0; i < resultVectorSize; ++i) {
         float result_scalar = 0.0f;
@@ -587,13 +719,13 @@
     const analysis::Type* result_type, const analysis::Constant* a,
     const analysis::Constant* b, analysis::ConstantManager*)>;
 
-// Returns a |ConstantFoldingRule| that folds unary floating point scalar ops
-// using |scalar_rule| and unary float point vectors ops by applying
+// Returns a |ConstantFoldingRule| that folds unary scalar ops
+// using |scalar_rule| and unary vectors ops by applying
 // |scalar_rule| to the elements of the vector.  The |ConstantFoldingRule|
 // that is returned assumes that |constants| contains 1 entry.  If they are
 // not |nullptr|, then their type is either |Float| or |Integer| or a |Vector|
 // whose element type is |Float| or |Integer|.
-ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) {
+ConstantFoldingRule FoldUnaryOp(UnaryScalarFoldingRule scalar_rule) {
   return [scalar_rule](IRContext* context, Instruction* inst,
                        const std::vector<const analysis::Constant*>& constants)
              -> const analysis::Constant* {
@@ -602,10 +734,6 @@
     const analysis::Type* result_type = type_mgr->GetType(inst->type_id());
     const analysis::Vector* vector_type = result_type->AsVector();
 
-    if (!inst->IsFloatingPointFoldingAllowed()) {
-      return nullptr;
-    }
-
     const analysis::Constant* arg =
         (inst->opcode() == spv::Op::OpExtInst) ? constants[1] : constants[0];
 
@@ -640,6 +768,83 @@
   };
 }
 
+// Returns a |ConstantFoldingRule| that folds binary scalar ops
+// using |scalar_rule| and binary vectors ops by applying
+// |scalar_rule| to the elements of the vector. The folding rule assumes that op
+// has two inputs. For regular instruction, those are in operands 0 and 1. For
+// extended instruction, they are in operands 1 and 2. If an element in
+// |constants| is not nullprt, then the constant's type is |Float|, |Integer|,
+// or |Vector| whose element type is |Float| or |Integer|.
+ConstantFoldingRule FoldBinaryOp(BinaryScalarFoldingRule scalar_rule) {
+  return [scalar_rule](IRContext* context, Instruction* inst,
+                       const std::vector<const analysis::Constant*>& constants)
+             -> const analysis::Constant* {
+    assert(constants.size() == inst->NumInOperands());
+    assert(constants.size() == (inst->opcode() == spv::Op::OpExtInst ? 3 : 2));
+    analysis::ConstantManager* const_mgr = context->get_constant_mgr();
+    analysis::TypeManager* type_mgr = context->get_type_mgr();
+    const analysis::Type* result_type = type_mgr->GetType(inst->type_id());
+    const analysis::Vector* vector_type = result_type->AsVector();
+
+    const analysis::Constant* arg1 =
+        (inst->opcode() == spv::Op::OpExtInst) ? constants[1] : constants[0];
+    const analysis::Constant* arg2 =
+        (inst->opcode() == spv::Op::OpExtInst) ? constants[2] : constants[1];
+
+    if (arg1 == nullptr || arg2 == nullptr) {
+      return nullptr;
+    }
+
+    if (vector_type == nullptr) {
+      return scalar_rule(result_type, arg1, arg2, const_mgr);
+    }
+
+    std::vector<const analysis::Constant*> a_components;
+    std::vector<const analysis::Constant*> b_components;
+    std::vector<const analysis::Constant*> results_components;
+
+    a_components = arg1->GetVectorComponents(const_mgr);
+    b_components = arg2->GetVectorComponents(const_mgr);
+    assert(a_components.size() == b_components.size());
+
+    // Fold each component of the vector.
+    for (uint32_t i = 0; i < a_components.size(); ++i) {
+      results_components.push_back(scalar_rule(vector_type->element_type(),
+                                               a_components[i], b_components[i],
+                                               const_mgr));
+      if (results_components[i] == nullptr) {
+        return nullptr;
+      }
+    }
+
+    // Build the constant object and return it.
+    std::vector<uint32_t> ids;
+    for (const analysis::Constant* member : results_components) {
+      ids.push_back(const_mgr->GetDefiningInstruction(member)->result_id());
+    }
+    return const_mgr->GetConstant(vector_type, ids);
+  };
+}
+
+// Returns a |ConstantFoldingRule| that folds unary floating point scalar ops
+// using |scalar_rule| and unary float point vectors ops by applying
+// |scalar_rule| to the elements of the vector.  The |ConstantFoldingRule|
+// that is returned assumes that |constants| contains 1 entry.  If they are
+// not |nullptr|, then their type is either |Float| or |Integer| or a |Vector|
+// whose element type is |Float| or |Integer|.
+ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) {
+  auto folding_rule = FoldUnaryOp(scalar_rule);
+  return [folding_rule](IRContext* context, Instruction* inst,
+                        const std::vector<const analysis::Constant*>& constants)
+             -> const analysis::Constant* {
+    if (!inst->IsFloatingPointFoldingAllowed()) {
+      return nullptr;
+    }
+
+    return folding_rule(context, inst, constants);
+  };
+}
+
 // Returns the result of folding the constants in |constants| according the
 // |scalar_rule|.  If |result_type| is a vector, then |scalar_rule| is applied
 // per component.
@@ -872,6 +1077,11 @@
     return FoldFPScalarDivideByZero(result_type, numerator, const_mgr);
   }
 
+  uint32_t width = denominator->type()->AsFloat()->width();
+  if (width != 32 && width != 64) {
+    return nullptr;
+  }
+
   const analysis::FloatConstant* denominator_float =
       denominator->AsFloatConstant();
   if (denominator_float && denominator->GetValueAsDouble() == -0.0) {
@@ -1042,18 +1252,8 @@
   };
 }
 
-// This function defines a |UnaryScalarFoldingRule| that subtracts the constant
-// from zero.
-UnaryScalarFoldingRule FoldFNegateOp() {
-  return [](const analysis::Type* result_type, const analysis::Constant* a,
-            analysis::ConstantManager* const_mgr) -> const analysis::Constant* {
-    assert(result_type != nullptr && a != nullptr);
-    assert(result_type == a->type());
-    return NegateFPConst(result_type, a, const_mgr);
-  };
-}
-
-ConstantFoldingRule FoldFNegate() { return FoldFPUnaryOp(FoldFNegateOp()); }
+ConstantFoldingRule FoldFNegate() { return FoldFPUnaryOp(NegateFPConst); }
+ConstantFoldingRule FoldSNegate() { return FoldUnaryOp(NegateIntConst); }
 
 ConstantFoldingRule FoldFClampFeedingCompare(spv::Op cmp_opcode) {
   return [cmp_opcode](IRContext* context, Instruction* inst,
@@ -1497,6 +1697,74 @@
         return nullptr;
       };
 }
+
+enum Sign { Signed, Unsigned };
+
+// Returns a BinaryScalarFoldingRule that applies `op` to the scalars.
+// The `signedness` is used to determine if the operands should be interpreted
+// as signed or unsigned. If the operands are signed, the value will be sign
+// extended before the value is passed to `op`. Otherwise the values will be
+// zero extended.
+template <Sign signedness>
+BinaryScalarFoldingRule FoldBinaryIntegerOperation(uint64_t (*op)(uint64_t,
+                                                                  uint64_t)) {
+  return
+      [op](const analysis::Type* result_type, const analysis::Constant* a,
+           const analysis::Constant* b,
+           analysis::ConstantManager* const_mgr) -> const analysis::Constant* {
+        assert(result_type != nullptr && a != nullptr && b != nullptr);
+        const analysis::Integer* integer_type = result_type->AsInteger();
+        assert(integer_type != nullptr);
+        assert(a->type()->kind() == analysis::Type::kInteger);
+        assert(b->type()->kind() == analysis::Type::kInteger);
+        assert(integer_type->width() == a->type()->AsInteger()->width());
+        assert(integer_type->width() == b->type()->AsInteger()->width());
+
+        // In SPIR-V, all operations support unsigned types, but the way they
+        // are interpreted depends on the opcode. This is why we use the
+        // template argument to determine how to interpret the operands.
+        uint64_t ia = (signedness == Signed ? a->GetSignExtendedValue()
+                                            : a->GetZeroExtendedValue());
+        uint64_t ib = (signedness == Signed ? b->GetSignExtendedValue()
+                                            : b->GetZeroExtendedValue());
+        uint64_t result = op(ia, ib);
+
+        const analysis::Constant* result_constant =
+            GenerateIntegerConstant(integer_type, result, const_mgr);
+        return result_constant;
+      };
+}
+
+// A scalar folding rule that folds OpSConvert.
+const analysis::Constant* FoldScalarSConvert(
+    const analysis::Type* result_type, const analysis::Constant* a,
+    analysis::ConstantManager* const_mgr) {
+  assert(result_type != nullptr);
+  assert(a != nullptr);
+  assert(const_mgr != nullptr);
+  const analysis::Integer* integer_type = result_type->AsInteger();
+  assert(integer_type && "The result type of an SConvert");
+  int64_t value = a->GetSignExtendedValue();
+  return GenerateIntegerConstant(integer_type, value, const_mgr);
+}
+
+// A scalar folding rule that folds OpUConvert.
+const analysis::Constant* FoldScalarUConvert(
+    const analysis::Type* result_type, const analysis::Constant* a,
+    analysis::ConstantManager* const_mgr) {
+  assert(result_type != nullptr);
+  assert(a != nullptr);
+  assert(const_mgr != nullptr);
+  const analysis::Integer* integer_type = result_type->AsInteger();
+  assert(integer_type && "The result type of an UConvert");
+  uint64_t value = a->GetZeroExtendedValue();
+
+  // If the operand was an unsigned value with less than 32-bit, it would have
+  // been sign extended earlier, and we need to clear those bits.
+  auto* operand_type = a->type()->AsInteger();
+  value = ZeroExtendValue(value, operand_type->width());
+  return GenerateIntegerConstant(integer_type, value, const_mgr);
+}
 }  // namespace
 
 void ConstantFoldingRules::AddFoldingRules() {
@@ -1514,6 +1782,8 @@
   rules_[spv::Op::OpConvertFToU].push_back(FoldFToI());
   rules_[spv::Op::OpConvertSToF].push_back(FoldIToF());
   rules_[spv::Op::OpConvertUToF].push_back(FoldIToF());
+  rules_[spv::Op::OpSConvert].push_back(FoldUnaryOp(FoldScalarSConvert));
+  rules_[spv::Op::OpUConvert].push_back(FoldUnaryOp(FoldScalarUConvert));
 
   rules_[spv::Op::OpDot].push_back(FoldOpDotWithConstants());
   rules_[spv::Op::OpFAdd].push_back(FoldFAdd());
@@ -1566,10 +1836,52 @@
   rules_[spv::Op::OpVectorTimesScalar].push_back(FoldVectorTimesScalar());
   rules_[spv::Op::OpVectorTimesMatrix].push_back(FoldVectorTimesMatrix());
   rules_[spv::Op::OpMatrixTimesVector].push_back(FoldMatrixTimesVector());
+  rules_[spv::Op::OpTranspose].push_back(FoldTranspose);
 
   rules_[spv::Op::OpFNegate].push_back(FoldFNegate());
+  rules_[spv::Op::OpSNegate].push_back(FoldSNegate());
   rules_[spv::Op::OpQuantizeToF16].push_back(FoldQuantizeToF16());
 
+  rules_[spv::Op::OpIAdd].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return a + b; })));
+  rules_[spv::Op::OpISub].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return a - b; })));
+  rules_[spv::Op::OpIMul].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return a * b; })));
+  rules_[spv::Op::OpUDiv].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return (b != 0 ? a / b : 0); })));
+  rules_[spv::Op::OpSDiv].push_back(FoldBinaryOp(
+      FoldBinaryIntegerOperation<Signed>([](uint64_t a, uint64_t b) {
+        return (b != 0 ? static_cast<uint64_t>(static_cast<int64_t>(a) /
+                                               static_cast<int64_t>(b))
+                       : 0);
+      })));
+  rules_[spv::Op::OpUMod].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return (b != 0 ? a % b : 0); })));
+
+  rules_[spv::Op::OpSRem].push_back(FoldBinaryOp(
+      FoldBinaryIntegerOperation<Signed>([](uint64_t a, uint64_t b) {
+        return (b != 0 ? static_cast<uint64_t>(static_cast<int64_t>(a) %
+                                               static_cast<int64_t>(b))
+                       : 0);
+      })));
+
+  rules_[spv::Op::OpSMod].push_back(FoldBinaryOp(
+      FoldBinaryIntegerOperation<Signed>([](uint64_t a, uint64_t b) {
+        if (b == 0) return static_cast<uint64_t>(0ull);
+
+        int64_t signed_a = static_cast<int64_t>(a);
+        int64_t signed_b = static_cast<int64_t>(b);
+        int64_t result = signed_a % signed_b;
+        if ((signed_b < 0) != (result < 0)) result += signed_b;
+        return static_cast<uint64_t>(result);
+      })));
+
   // Add rules for GLSLstd450
   FeatureManager* feature_manager = context_->get_feature_mgr();
   uint32_t ext_inst_glslstd450_id =
diff --git a/third_party/SPIRV-Tools/source/opt/constants.cpp b/third_party/SPIRV-Tools/source/opt/constants.cpp
index 9b4c89a..6eebbb5 100644
--- a/third_party/SPIRV-Tools/source/opt/constants.cpp
+++ b/third_party/SPIRV-Tools/source/opt/constants.cpp
@@ -435,6 +435,8 @@
     words_per_element = float_type->width() / 32;
   else if (const auto* int_type = element_type->AsInteger())
     words_per_element = int_type->width() / 32;
+  else if (element_type->AsBool() != nullptr)
+    words_per_element = 1;
 
   if (words_per_element != 1 && words_per_element != 2) return nullptr;
 
@@ -487,6 +489,31 @@
   return GetDefiningInstruction(c)->result_id();
 }
 
+const Constant* ConstantManager::GetIntConst(uint64_t val, int32_t bitWidth,
+                                             bool isSigned) {
+  Type* int_type = context()->get_type_mgr()->GetIntType(bitWidth, isSigned);
+
+  if (isSigned) {
+    // Sign extend the value.
+    int32_t num_of_bit_to_ignore = 64 - bitWidth;
+    val = static_cast<int64_t>(val << num_of_bit_to_ignore) >>
+          num_of_bit_to_ignore;
+  } else if (bitWidth < 64) {
+    // Clear the upper bit that are not used.
+    uint64_t mask = ((1ull << bitWidth) - 1);
+    val &= mask;
+  }
+
+  if (bitWidth <= 32) {
+    return GetConstant(int_type, {static_cast<uint32_t>(val)});
+  }
+
+  // If the value is more than 32-bit, we need to split the operands into two
+  // 32-bit integers.
+  return GetConstant(
+      int_type, {static_cast<uint32_t>(val), static_cast<uint32_t>(val >> 32)});
+}
+
 uint32_t ConstantManager::GetUIntConstId(uint32_t val) {
   Type* uint_type = context()->get_type_mgr()->GetUIntType();
   const Constant* c = GetConstant(uint_type, {val});
diff --git a/third_party/SPIRV-Tools/source/opt/constants.h b/third_party/SPIRV-Tools/source/opt/constants.h
index 410304e..ae8dc62 100644
--- a/third_party/SPIRV-Tools/source/opt/constants.h
+++ b/third_party/SPIRV-Tools/source/opt/constants.h
@@ -659,6 +659,12 @@
   // Returns the id of a 32-bit signed integer constant with value |val|.
   uint32_t GetSIntConstId(int32_t val);
 
+  // Returns an integer constant with `bitWidth` and value |val|. If `isSigned`
+  // is true, the constant will be a signed integer. Otherwise it will be
+  // unsigned. Only the `bitWidth` lower order bits of |val| will be used. The
+  // rest will be ignored.
+  const Constant* GetIntConst(uint64_t val, int32_t bitWidth, bool isSigned);
+
   // Returns the id of a 32-bit unsigned integer constant with value |val|.
   uint32_t GetUIntConstId(uint32_t val);
 
diff --git a/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.cpp b/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.cpp
index 2c4a631..e243bed 100644
--- a/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.cpp
@@ -63,6 +63,10 @@
 
 void ConvertToHalfPass::AddRelaxed(uint32_t id) { relaxed_ids_set_.insert(id); }
 
+bool ConvertToHalfPass::CanRelaxOpOperands(Instruction* inst) {
+  return image_ops_.count(inst->opcode()) == 0;
+}
+
 analysis::Type* ConvertToHalfPass::FloatScalarType(uint32_t width) {
   analysis::Float float_ty(width);
   return context()->get_type_mgr()->GetRegisteredType(&float_ty);
@@ -167,6 +171,19 @@
 
 bool ConvertToHalfPass::GenHalfArith(Instruction* inst) {
   bool modified = false;
+  // If this is a OpCompositeExtract instruction and has a struct operand, we
+  // should not relax this instruction. Doing so could cause a mismatch between
+  // the result type and the struct member type.
+  bool hasStructOperand = false;
+  if (inst->opcode() == spv::Op::OpCompositeExtract) {
+    inst->ForEachInId([&hasStructOperand, this](uint32_t* idp) {
+      Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
+      if (IsStruct(op_inst)) hasStructOperand = true;
+    });
+    if (hasStructOperand) {
+      return false;
+    }
+  }
   // Convert all float32 based operands to float16 equivalent and change
   // instruction type to float16 equivalent.
   inst->ForEachInId([&inst, &modified, this](uint32_t* idp) {
@@ -299,12 +316,19 @@
   if (closure_ops_.count(inst->opcode()) == 0) return false;
   // Can relax if all float operands are relaxed
   bool relax = true;
-  inst->ForEachInId([&relax, this](uint32_t* idp) {
+  bool hasStructOperand = false;
+  inst->ForEachInId([&relax, &hasStructOperand, this](uint32_t* idp) {
     Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
-    if (IsStruct(op_inst)) relax = false;
+    if (IsStruct(op_inst)) hasStructOperand = true;
     if (!IsFloat(op_inst, 32)) return;
     if (!IsRelaxed(*idp)) relax = false;
   });
+  // If the instruction has a struct operand, we should not relax it, even if
+  // all its uses are relaxed. Doing so could cause a mismatch between the
+  // result type and the struct member type.
+  if (hasStructOperand) {
+    return false;
+  }
   if (relax) {
     AddRelaxed(inst->result_id());
     return true;
@@ -313,7 +337,8 @@
   relax = true;
   get_def_use_mgr()->ForEachUser(inst, [&relax, this](Instruction* uinst) {
     if (uinst->result_id() == 0 || !IsFloat(uinst, 32) ||
-        (!IsDecoratedRelaxed(uinst) && !IsRelaxed(uinst->result_id()))) {
+        (!IsDecoratedRelaxed(uinst) && !IsRelaxed(uinst->result_id())) ||
+        !CanRelaxOpOperands(uinst)) {
       relax = false;
       return;
     }
diff --git a/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.h b/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.h
index 24a478f..8e10c4f 100644
--- a/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.h
@@ -56,6 +56,9 @@
   // Add |id| to the relaxed id set
   void AddRelaxed(uint32_t id);
 
+  // Return true if the instruction's operands can be relaxed
+  bool CanRelaxOpOperands(Instruction* inst);
+
   // Return type id for float with |width|
   analysis::Type* FloatScalarType(uint32_t width);
 
@@ -133,13 +136,13 @@
   // Set of 450 extension operations to be processed
   std::unordered_set<uint32_t> target_ops_450_;
 
-  // Set of sample operations
+  // Set of all sample operations, including dref and non-dref operations
   std::unordered_set<spv::Op, hasher> image_ops_;
 
-  // Set of dref sample operations
+  // Set of only dref sample operations
   std::unordered_set<spv::Op, hasher> dref_image_ops_;
 
-  // Set of dref sample operations
+  // Set of operations that can be marked as relaxed
   std::unordered_set<spv::Op, hasher> closure_ops_;
 
   // Set of ids of all relaxed instructions
diff --git a/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.cpp b/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.cpp
index 66a268f..c2bea8a 100644
--- a/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.cpp
+++ b/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.cpp
@@ -35,6 +35,32 @@
          dbg_opcode == CommonDebugInfoDebugValue;
 }
 
+// Returns the number of members in |type|.  If |type| is not a composite type
+// or the number of components is not known at compile time, the return value
+// will be 0.
+uint32_t GetNumberOfMembers(const analysis::Type* type, IRContext* context) {
+  if (const analysis::Struct* struct_type = type->AsStruct()) {
+    return static_cast<uint32_t>(struct_type->element_types().size());
+  } else if (const analysis::Array* array_type = type->AsArray()) {
+    const analysis::Constant* length_const =
+        context->get_constant_mgr()->FindDeclaredConstant(
+            array_type->LengthId());
+
+    if (length_const == nullptr) {
+      // This can happen if the length is an OpSpecConstant.
+      return 0;
+    }
+    assert(length_const->type()->AsInteger());
+    return length_const->GetU32();
+  } else if (const analysis::Vector* vector_type = type->AsVector()) {
+    return vector_type->element_count();
+  } else if (const analysis::Matrix* matrix_type = type->AsMatrix()) {
+    return matrix_type->element_count();
+  } else {
+    return 0;
+  }
+}
+
 }  // namespace
 
 Pass::Status CopyPropagateArrays::Process() {
@@ -357,22 +383,9 @@
 
   analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
   analysis::TypeManager* type_mgr = context()->get_type_mgr();
-  analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
   const analysis::Type* result_type = type_mgr->GetType(insert_inst->type_id());
 
-  uint32_t number_of_elements = 0;
-  if (const analysis::Struct* struct_type = result_type->AsStruct()) {
-    number_of_elements =
-        static_cast<uint32_t>(struct_type->element_types().size());
-  } else if (const analysis::Array* array_type = result_type->AsArray()) {
-    const analysis::Constant* length_const =
-        const_mgr->FindDeclaredConstant(array_type->LengthId());
-    number_of_elements = length_const->GetU32();
-  } else if (const analysis::Vector* vector_type = result_type->AsVector()) {
-    number_of_elements = vector_type->element_count();
-  } else if (const analysis::Matrix* matrix_type = result_type->AsMatrix()) {
-    number_of_elements = matrix_type->element_count();
-  }
+  uint32_t number_of_elements = GetNumberOfMembers(result_type, context());
 
   if (number_of_elements == 0) {
     return nullptr;
@@ -800,23 +813,8 @@
   std::vector<uint32_t> access_indices = GetAccessIds();
   type = type_mgr->GetMemberType(type, access_indices);
 
-  if (const analysis::Struct* struct_type = type->AsStruct()) {
-    return static_cast<uint32_t>(struct_type->element_types().size());
-  } else if (const analysis::Array* array_type = type->AsArray()) {
-    const analysis::Constant* length_const =
-        context->get_constant_mgr()->FindDeclaredConstant(
-            array_type->LengthId());
-    assert(length_const->type()->AsInteger());
-    return length_const->GetU32();
-  } else if (const analysis::Vector* vector_type = type->AsVector()) {
-    return vector_type->element_count();
-  } else if (const analysis::Matrix* matrix_type = type->AsMatrix()) {
-    return matrix_type->element_count();
-  } else {
-    return 0;
-  }
+  return opt::GetNumberOfMembers(type, context);
 }
-
 template <class iterator>
 CopyPropagateArrays::MemoryObject::MemoryObject(Instruction* var_inst,
                                                 iterator begin, iterator end)
diff --git a/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.h b/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.h
index 7486f80..c6ca7d2 100644
--- a/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.h
+++ b/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.h
@@ -101,7 +101,8 @@
     bool IsMember() const { return !access_chain_.empty(); }
 
     // Returns the number of members in the object represented by |this|.  If
-    // |this| does not represent a composite type, the return value will be 0.
+    // |this| does not represent a composite type or the number of components is
+    // not known at compile time, the return value will be 0.
     uint32_t GetNumberOfMembers();
 
     // Returns the owning variable that the memory object is contained in.
@@ -207,7 +208,7 @@
 
   // Returns the memory object that at some point was equivalent to the result
   // of |insert_inst|.  If a memory object cannot be identified, the return
-  // value is |nullptr\.  The opcode of |insert_inst| must be
+  // value is |nullptr|.  The opcode of |insert_inst| must be
   // |OpCompositeInsert|.  This function looks for a series of
   // |OpCompositeInsert| instructions that insert the elements one at a time in
   // order from beginning to end.
diff --git a/third_party/SPIRV-Tools/source/opt/dead_insert_elim_pass.cpp b/third_party/SPIRV-Tools/source/opt/dead_insert_elim_pass.cpp
index a486903..f985e4c 100644
--- a/third_party/SPIRV-Tools/source/opt/dead_insert_elim_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/dead_insert_elim_pass.cpp
@@ -213,7 +213,8 @@
           } break;
           default: {
             // Mark inserts in chain for all components
-            MarkInsertChain(&*ii, nullptr, 0, nullptr);
+            std::unordered_set<uint32_t> visited_phis;
+            MarkInsertChain(&*ii, nullptr, 0, &visited_phis);
           } break;
         }
       });
diff --git a/third_party/SPIRV-Tools/source/opt/decoration_manager.cpp b/third_party/SPIRV-Tools/source/opt/decoration_manager.cpp
index 1393d48..3e95dbc 100644
--- a/third_party/SPIRV-Tools/source/opt/decoration_manager.cpp
+++ b/third_party/SPIRV-Tools/source/opt/decoration_manager.cpp
@@ -461,7 +461,7 @@
 
 bool DecorationManager::WhileEachDecoration(
     uint32_t id, uint32_t decoration,
-    std::function<bool(const Instruction&)> f) {
+    std::function<bool(const Instruction&)> f) const {
   for (const Instruction* inst : GetDecorationsFor(id, true)) {
     switch (inst->opcode()) {
       case spv::Op::OpMemberDecorate:
@@ -485,14 +485,19 @@
 
 void DecorationManager::ForEachDecoration(
     uint32_t id, uint32_t decoration,
-    std::function<void(const Instruction&)> f) {
+    std::function<void(const Instruction&)> f) const {
   WhileEachDecoration(id, decoration, [&f](const Instruction& inst) {
     f(inst);
     return true;
   });
 }
 
-bool DecorationManager::HasDecoration(uint32_t id, uint32_t decoration) {
+bool DecorationManager::HasDecoration(uint32_t id,
+                                      spv::Decoration decoration) const {
+  return HasDecoration(id, static_cast<uint32_t>(decoration));
+}
+
+bool DecorationManager::HasDecoration(uint32_t id, uint32_t decoration) const {
   bool has_decoration = false;
   ForEachDecoration(id, decoration, [&has_decoration](const Instruction&) {
     has_decoration = true;
diff --git a/third_party/SPIRV-Tools/source/opt/decoration_manager.h b/third_party/SPIRV-Tools/source/opt/decoration_manager.h
index 1a0d1b1..2be016a 100644
--- a/third_party/SPIRV-Tools/source/opt/decoration_manager.h
+++ b/third_party/SPIRV-Tools/source/opt/decoration_manager.h
@@ -92,20 +92,21 @@
 
   // Returns whether a decoration instruction for |id| with decoration
   // |decoration| exists or not.
-  bool HasDecoration(uint32_t id, uint32_t decoration);
+  bool HasDecoration(uint32_t id, uint32_t decoration) const;
+  bool HasDecoration(uint32_t id, spv::Decoration decoration) const;
 
   // |f| is run on each decoration instruction for |id| with decoration
   // |decoration|. Processed are all decorations which target |id| either
   // directly or indirectly by Decoration Groups.
   void ForEachDecoration(uint32_t id, uint32_t decoration,
-                         std::function<void(const Instruction&)> f);
+                         std::function<void(const Instruction&)> f) const;
 
   // |f| is run on each decoration instruction for |id| with decoration
   // |decoration|. Processes all decoration which target |id| either directly or
   // indirectly through decoration groups. If |f| returns false, iteration is
   // terminated and this function returns false.
   bool WhileEachDecoration(uint32_t id, uint32_t decoration,
-                           std::function<bool(const Instruction&)> f);
+                           std::function<bool(const Instruction&)> f) const;
 
   // |f| is run on each decoration instruction for |id| with decoration
   // |decoration|. Processes all decoration which target |id| either directly or
@@ -141,7 +142,7 @@
                         uint32_t decoration_value);
 
   // Add |decoration, decoration_value| of |inst_id, member| to module.
-  void AddMemberDecoration(uint32_t member, uint32_t inst_id,
+  void AddMemberDecoration(uint32_t inst_id, uint32_t member,
                            uint32_t decoration, uint32_t decoration_value);
 
   friend bool operator==(const DecorationManager&, const DecorationManager&);
diff --git a/third_party/SPIRV-Tools/source/opt/def_use_manager.h b/third_party/SPIRV-Tools/source/opt/def_use_manager.h
index a8dbbc6..13cf9bd 100644
--- a/third_party/SPIRV-Tools/source/opt/def_use_manager.h
+++ b/third_party/SPIRV-Tools/source/opt/def_use_manager.h
@@ -27,28 +27,6 @@
 namespace opt {
 namespace analysis {
 
-// Class for representing a use of id. Note that:
-// * Result type id is a use.
-// * Ids referenced in OpSectionMerge & OpLoopMerge are considered as use.
-// * Ids referenced in OpPhi's in operands are considered as use.
-struct Use {
-  Instruction* inst;       // Instruction using the id.
-  uint32_t operand_index;  // logical operand index of the id use. This can be
-                           // the index of result type id.
-};
-
-inline bool operator==(const Use& lhs, const Use& rhs) {
-  return lhs.inst == rhs.inst && lhs.operand_index == rhs.operand_index;
-}
-
-inline bool operator!=(const Use& lhs, const Use& rhs) { return !(lhs == rhs); }
-
-inline bool operator<(const Use& lhs, const Use& rhs) {
-  if (lhs.inst < rhs.inst) return true;
-  if (lhs.inst > rhs.inst) return false;
-  return lhs.operand_index < rhs.operand_index;
-}
-
 // Definition should never be null. User can be null, however, such an entry
 // should be used only for searching (e.g. all users of a particular definition)
 // and never stored in a container.
diff --git a/third_party/SPIRV-Tools/source/opt/desc_sroa.cpp b/third_party/SPIRV-Tools/source/opt/desc_sroa.cpp
index 8da0c86..2c0f482 100644
--- a/third_party/SPIRV-Tools/source/opt/desc_sroa.cpp
+++ b/third_party/SPIRV-Tools/source/opt/desc_sroa.cpp
@@ -54,9 +54,10 @@
 bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
   std::vector<Instruction*> access_chain_work_list;
   std::vector<Instruction*> load_work_list;
+  std::vector<Instruction*> entry_point_work_list;
   bool failed = !get_def_use_mgr()->WhileEachUser(
-      var->result_id(),
-      [this, &access_chain_work_list, &load_work_list](Instruction* use) {
+      var->result_id(), [this, &access_chain_work_list, &load_work_list,
+                         &entry_point_work_list](Instruction* use) {
         if (use->opcode() == spv::Op::OpName) {
           return true;
         }
@@ -73,6 +74,9 @@
           case spv::Op::OpLoad:
             load_work_list.push_back(use);
             return true;
+          case spv::Op::OpEntryPoint:
+            entry_point_work_list.push_back(use);
+            return true;
           default:
             context()->EmitErrorMessage(
                 "Variable cannot be replaced: invalid instruction", use);
@@ -95,6 +99,11 @@
       return false;
     }
   }
+  for (Instruction* use : entry_point_work_list) {
+    if (!ReplaceEntryPoint(var, use)) {
+      return false;
+    }
+  }
   return true;
 }
 
@@ -147,6 +156,42 @@
   return true;
 }
 
+bool DescriptorScalarReplacement::ReplaceEntryPoint(Instruction* var,
+                                                    Instruction* use) {
+  // Build a new |OperandList| for |use| that removes |var| and adds its
+  // replacement variables.
+  Instruction::OperandList new_operands;
+
+  // Copy all operands except |var|.
+  bool found = false;
+  for (uint32_t idx = 0; idx < use->NumOperands(); idx++) {
+    Operand& op = use->GetOperand(idx);
+    if (op.type == SPV_OPERAND_TYPE_ID && op.words[0] == var->result_id()) {
+      found = true;
+    } else {
+      new_operands.emplace_back(op);
+    }
+  }
+
+  if (!found) {
+    context()->EmitErrorMessage(
+        "Variable cannot be replaced: invalid instruction", use);
+    return false;
+  }
+
+  // Add all new replacement variables.
+  uint32_t num_replacement_vars =
+      descsroautil::GetNumberOfElementsForArrayOrStruct(context(), var);
+  for (uint32_t i = 0; i < num_replacement_vars; i++) {
+    new_operands.push_back(
+        {SPV_OPERAND_TYPE_ID, {GetReplacementVariable(var, i)}});
+  }
+
+  use->ReplaceOperands(new_operands);
+  context()->UpdateDefUse(use);
+  return true;
+}
+
 uint32_t DescriptorScalarReplacement::GetReplacementVariable(Instruction* var,
                                                              uint32_t idx) {
   auto replacement_vars = replacement_variables_.find(var);
diff --git a/third_party/SPIRV-Tools/source/opt/desc_sroa.h b/third_party/SPIRV-Tools/source/opt/desc_sroa.h
index 6a24fd8..901be3e 100644
--- a/third_party/SPIRV-Tools/source/opt/desc_sroa.h
+++ b/third_party/SPIRV-Tools/source/opt/desc_sroa.h
@@ -64,6 +64,11 @@
   // otherwise.
   bool ReplaceLoadedValue(Instruction* var, Instruction* value);
 
+  // Replaces the given composite variable |var| in the OpEntryPoint with the
+  // new replacement variables, one for each element of the array |var|. Returns
+  // |true| if successful, and |false| otherwise.
+  bool ReplaceEntryPoint(Instruction* var, Instruction* use);
+
   // Replaces the given OpCompositeExtract |extract| and all of its references
   // with an OpLoad of a replacement variable. |var| is the variable with
   // composite type whose value is being used by |extract|. Assumes that
diff --git a/third_party/SPIRV-Tools/source/opt/feature_manager.cpp b/third_party/SPIRV-Tools/source/opt/feature_manager.cpp
index 07e053b..5188370 100644
--- a/third_party/SPIRV-Tools/source/opt/feature_manager.cpp
+++ b/third_party/SPIRV-Tools/source/opt/feature_manager.cpp
@@ -40,31 +40,33 @@
   const std::string name = ext->GetInOperand(0u).AsString();
   Extension extension;
   if (GetExtensionFromString(name.c_str(), &extension)) {
-    extensions_.Add(extension);
+    extensions_.insert(extension);
   }
 }
 
 void FeatureManager::RemoveExtension(Extension ext) {
-  if (!extensions_.Contains(ext)) return;
-  extensions_.Remove(ext);
+  if (!extensions_.contains(ext)) return;
+  extensions_.erase(ext);
 }
 
 void FeatureManager::AddCapability(spv::Capability cap) {
-  if (capabilities_.Contains(cap)) return;
+  if (capabilities_.contains(cap)) return;
 
-  capabilities_.Add(cap);
+  capabilities_.insert(cap);
 
   spv_operand_desc desc = {};
   if (SPV_SUCCESS == grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
                                             uint32_t(cap), &desc)) {
-    CapabilitySet(desc->numCapabilities, desc->capabilities)
-        .ForEach([this](spv::Capability c) { AddCapability(c); });
+    for (auto capability :
+         CapabilitySet(desc->numCapabilities, desc->capabilities)) {
+      AddCapability(capability);
+    }
   }
 }
 
 void FeatureManager::RemoveCapability(spv::Capability cap) {
-  if (!capabilities_.Contains(cap)) return;
-  capabilities_.Remove(cap);
+  if (!capabilities_.contains(cap)) return;
+  capabilities_.erase(cap);
 }
 
 void FeatureManager::AddCapabilities(Module* module) {
diff --git a/third_party/SPIRV-Tools/source/opt/feature_manager.h b/third_party/SPIRV-Tools/source/opt/feature_manager.h
index b96988d..d150a2f 100644
--- a/third_party/SPIRV-Tools/source/opt/feature_manager.h
+++ b/third_party/SPIRV-Tools/source/opt/feature_manager.h
@@ -25,27 +25,19 @@
 // Tracks features enabled by a module. The IRContext has a FeatureManager.
 class FeatureManager {
  public:
-  explicit FeatureManager(const AssemblyGrammar& grammar) : grammar_(grammar) {}
-
   // Returns true if |ext| is an enabled extension in the module.
-  bool HasExtension(Extension ext) const { return extensions_.Contains(ext); }
-
-  // Removes the given |extension| from the current FeatureManager.
-  void RemoveExtension(Extension extension);
+  bool HasExtension(Extension ext) const { return extensions_.contains(ext); }
 
   // Returns true if |cap| is an enabled capability in the module.
   bool HasCapability(spv::Capability cap) const {
-    return capabilities_.Contains(cap);
+    return capabilities_.contains(cap);
   }
 
-  // Removes the given |capability| from the current FeatureManager.
-  void RemoveCapability(spv::Capability capability);
+  // Returns the capabilities the module declares.
+  inline const CapabilitySet& GetCapabilities() const { return capabilities_; }
 
-  // Analyzes |module| and records enabled extensions and capabilities.
-  void Analyze(Module* module);
-
-  CapabilitySet* GetCapabilities() { return &capabilities_; }
-  const CapabilitySet* GetCapabilities() const { return &capabilities_; }
+  // Returns the extensions the module imports.
+  inline const ExtensionSet& GetExtensions() const { return extensions_; }
 
   uint32_t GetExtInstImportId_GLSLstd450() const {
     return extinst_importid_GLSLstd450_;
@@ -64,23 +56,34 @@
     return !(a == b);
   }
 
-  // Adds the given |capability| and all implied capabilities into the current
-  // FeatureManager.
-  void AddCapability(spv::Capability capability);
+ private:
+  explicit FeatureManager(const AssemblyGrammar& grammar) : grammar_(grammar) {}
+
+  // Analyzes |module| and records enabled extensions and capabilities.
+  void Analyze(Module* module);
 
   // Add the extension |ext| to the feature manager.
   void AddExtension(Instruction* ext);
 
-  // Analyzes |module| and records imported external instruction sets.
-  void AddExtInstImportIds(Module* module);
-
- private:
   // Analyzes |module| and records enabled extensions.
   void AddExtensions(Module* module);
 
+  // Removes the given |extension| from the current FeatureManager.
+  void RemoveExtension(Extension extension);
+
+  // Adds the given |capability| and all implied capabilities into the current
+  // FeatureManager.
+  void AddCapability(spv::Capability capability);
+
   // Analyzes |module| and records enabled capabilities.
   void AddCapabilities(Module* module);
 
+  // Removes the given |capability| from the current FeatureManager.
+  void RemoveCapability(spv::Capability capability);
+
+  // Analyzes |module| and records imported external instruction sets.
+  void AddExtInstImportIds(Module* module);
+
   // Auxiliary object for querying SPIR-V grammar facts.
   const AssemblyGrammar& grammar_;
 
@@ -100,6 +103,8 @@
   // Common NonSemanticShader100DebugInfo external instruction import ids,
   // cached for performance.
   uint32_t extinst_importid_Shader100DebugInfo_ = 0;
+
+  friend class IRContext;
 };
 
 }  // namespace opt
diff --git a/third_party/SPIRV-Tools/source/opt/fix_storage_class.cpp b/third_party/SPIRV-Tools/source/opt/fix_storage_class.cpp
index 5597e82..564cd1b 100644
--- a/third_party/SPIRV-Tools/source/opt/fix_storage_class.cpp
+++ b/third_party/SPIRV-Tools/source/opt/fix_storage_class.cpp
@@ -318,7 +318,13 @@
         const analysis::Constant* index_const =
             context()->get_constant_mgr()->FindDeclaredConstant(
                 inst->GetSingleWordInOperand(i));
-        uint32_t index = index_const->GetU32();
+        // It is highly unlikely that any type would have more fields than could
+        // be indexed by a 32-bit integer, and GetSingleWordInOperand only takes
+        // a 32-bit value, so we would not be able to handle it anyway. But the
+        // specification does allow any scalar integer type, treated as signed,
+        // so we simply downcast the index to 32-bits.
+        uint32_t index =
+            static_cast<uint32_t>(index_const->GetSignExtendedValue());
         id = type_inst->GetSingleWordInOperand(index);
         break;
       }
diff --git a/third_party/SPIRV-Tools/source/opt/fold.cpp b/third_party/SPIRV-Tools/source/opt/fold.cpp
index 453756f..942da68 100644
--- a/third_party/SPIRV-Tools/source/opt/fold.cpp
+++ b/third_party/SPIRV-Tools/source/opt/fold.cpp
@@ -70,58 +70,6 @@
 uint32_t InstructionFolder::BinaryOperate(spv::Op opcode, uint32_t a,
                                           uint32_t b) const {
   switch (opcode) {
-    // Arthimetics
-    case spv::Op::OpIAdd:
-      return a + b;
-    case spv::Op::OpISub:
-      return a - b;
-    case spv::Op::OpIMul:
-      return a * b;
-    case spv::Op::OpUDiv:
-      if (b != 0) {
-        return a / b;
-      } else {
-        // Dividing by 0 is undefined, so we will just pick 0.
-        return 0;
-      }
-    case spv::Op::OpSDiv:
-      if (b != 0u) {
-        return (static_cast<int32_t>(a)) / (static_cast<int32_t>(b));
-      } else {
-        // Dividing by 0 is undefined, so we will just pick 0.
-        return 0;
-      }
-    case spv::Op::OpSRem: {
-      // The sign of non-zero result comes from the first operand: a. This is
-      // guaranteed by C++11 rules for integer division operator. The division
-      // result is rounded toward zero, so the result of '%' has the sign of
-      // the first operand.
-      if (b != 0u) {
-        return static_cast<int32_t>(a) % static_cast<int32_t>(b);
-      } else {
-        // Remainder when dividing with 0 is undefined, so we will just pick 0.
-        return 0;
-      }
-    }
-    case spv::Op::OpSMod: {
-      // The sign of non-zero result comes from the second operand: b
-      if (b != 0u) {
-        int32_t rem = BinaryOperate(spv::Op::OpSRem, a, b);
-        int32_t b_prim = static_cast<int32_t>(b);
-        return (rem + b_prim) % b_prim;
-      } else {
-        // Mod with 0 is undefined, so we will just pick 0.
-        return 0;
-      }
-    }
-    case spv::Op::OpUMod:
-      if (b != 0u) {
-        return (a % b);
-      } else {
-        // Mod with 0 is undefined, so we will just pick 0.
-        return 0;
-      }
-
     // Shifting
     case spv::Op::OpShiftRightLogical:
       if (b >= 32) {
@@ -627,7 +575,8 @@
     Instruction* inst, std::function<uint32_t(uint32_t)> id_map) const {
   analysis::ConstantManager* const_mgr = context_->get_constant_mgr();
 
-  if (!inst->IsFoldableByFoldScalar() && !HasConstFoldingRule(inst)) {
+  if (!inst->IsFoldableByFoldScalar() && !inst->IsFoldableByFoldVector() &&
+      !GetConstantFoldingRules().HasFoldingRule(inst)) {
     return nullptr;
   }
   // Collect the values of the constant parameters.
@@ -661,29 +610,58 @@
     }
   }
 
-  uint32_t result_val = 0;
   bool successful = false;
+
   // If all parameters are constant, fold the instruction to a constant.
-  if (!missing_constants && inst->IsFoldableByFoldScalar()) {
-    result_val = FoldScalars(inst->opcode(), constants);
-    successful = true;
+  if (inst->IsFoldableByFoldScalar()) {
+    uint32_t result_val = 0;
+
+    if (!missing_constants) {
+      result_val = FoldScalars(inst->opcode(), constants);
+      successful = true;
+    }
+
+    if (!successful) {
+      successful = FoldIntegerOpToConstant(inst, id_map, &result_val);
+    }
+
+    if (successful) {
+      const analysis::Constant* result_const =
+          const_mgr->GetConstant(const_mgr->GetType(inst), {result_val});
+      Instruction* folded_inst =
+          const_mgr->GetDefiningInstruction(result_const, inst->type_id());
+      return folded_inst;
+    }
+  } else if (inst->IsFoldableByFoldVector()) {
+    std::vector<uint32_t> result_val;
+
+    if (!missing_constants) {
+      if (Instruction* inst_type =
+              context_->get_def_use_mgr()->GetDef(inst->type_id())) {
+        result_val = FoldVectors(
+            inst->opcode(), inst_type->GetSingleWordInOperand(1), constants);
+        successful = true;
+      }
+    }
+
+    if (successful) {
+      const analysis::Constant* result_const =
+          const_mgr->GetNumericVectorConstantWithWords(
+              const_mgr->GetType(inst)->AsVector(), result_val);
+      Instruction* folded_inst =
+          const_mgr->GetDefiningInstruction(result_const, inst->type_id());
+      return folded_inst;
+    }
   }
 
-  if (!successful && inst->IsFoldableByFoldScalar()) {
-    successful = FoldIntegerOpToConstant(inst, id_map, &result_val);
-  }
-
-  if (successful) {
-    const analysis::Constant* result_const =
-        const_mgr->GetConstant(const_mgr->GetType(inst), {result_val});
-    Instruction* folded_inst =
-        const_mgr->GetDefiningInstruction(result_const, inst->type_id());
-    return folded_inst;
-  }
   return nullptr;
 }
 
 bool InstructionFolder::IsFoldableType(Instruction* type_inst) const {
+  return IsFoldableScalarType(type_inst) || IsFoldableVectorType(type_inst);
+}
+
+bool InstructionFolder::IsFoldableScalarType(Instruction* type_inst) const {
   // Support 32-bit integers.
   if (type_inst->opcode() == spv::Op::OpTypeInt) {
     return type_inst->GetSingleWordInOperand(0) == 32;
@@ -696,6 +674,19 @@
   return false;
 }
 
+bool InstructionFolder::IsFoldableVectorType(Instruction* type_inst) const {
+  // Support vectors with foldable components
+  if (type_inst->opcode() == spv::Op::OpTypeVector) {
+    uint32_t component_type_id = type_inst->GetSingleWordInOperand(0);
+    Instruction* def_component_type =
+        context_->get_def_use_mgr()->GetDef(component_type_id);
+    return def_component_type != nullptr &&
+           IsFoldableScalarType(def_component_type);
+  }
+  // Nothing else yet.
+  return false;
+}
+
 bool InstructionFolder::FoldInstruction(Instruction* inst) const {
   bool modified = false;
   Instruction* folded_inst(inst);
diff --git a/third_party/SPIRV-Tools/source/opt/fold.h b/third_party/SPIRV-Tools/source/opt/fold.h
index 9a131d0..42da65e 100644
--- a/third_party/SPIRV-Tools/source/opt/fold.h
+++ b/third_party/SPIRV-Tools/source/opt/fold.h
@@ -86,6 +86,14 @@
   // result type is |type_inst|.
   bool IsFoldableType(Instruction* type_inst) const;
 
+  // Returns true if |FoldInstructionToConstant| could fold an instruction whose
+  // result type is |type_inst|.
+  bool IsFoldableScalarType(Instruction* type_inst) const;
+
+  // Returns true if |FoldInstructionToConstant| could fold an instruction whose
+  // result type is |type_inst|.
+  bool IsFoldableVectorType(Instruction* type_inst) const;
+
   // Tries to fold |inst| to a single constant, when the input ids to |inst|
   // have been substituted using |id_map|.  Returns a pointer to the OpConstant*
   // instruction if successful.  If necessary, a new constant instruction is
diff --git a/third_party/SPIRV-Tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp b/third_party/SPIRV-Tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp
index f6d6155..c568027 100644
--- a/third_party/SPIRV-Tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp
@@ -115,20 +115,9 @@
          "The first in-operand of OpSpecConstantOp instruction must be of "
          "SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER type");
 
-  switch (static_cast<spv::Op>(inst->GetSingleWordInOperand(0))) {
-    case spv::Op::OpCompositeExtract:
-    case spv::Op::OpVectorShuffle:
-    case spv::Op::OpCompositeInsert:
-    case spv::Op::OpQuantizeToF16:
-      folded_inst = FoldWithInstructionFolder(pos);
-      break;
-    default:
-      // TODO: This should use the instruction folder as well, but some folding
-      // rules are missing.
-
-      // Component-wise operations.
-      folded_inst = DoComponentWiseOperation(pos);
-      break;
+  folded_inst = FoldWithInstructionFolder(pos);
+  if (!folded_inst) {
+    folded_inst = DoComponentWiseOperation(pos);
   }
   if (!folded_inst) return false;
 
@@ -176,8 +165,9 @@
   Instruction* new_const_inst =
       context()->get_instruction_folder().FoldInstructionToConstant(
           inst.get(), identity_map);
-  assert(new_const_inst != nullptr &&
-         "Failed to fold instruction that must be folded.");
+
+  // new_const_inst == null indicates we cannot fold this spec constant
+  if (!new_const_inst) return nullptr;
 
   // Get the instruction before |pos| to insert after.  |pos| cannot be the
   // first instruction in the list because its type has to come first.
diff --git a/third_party/SPIRV-Tools/source/opt/folding_rules.cpp b/third_party/SPIRV-Tools/source/opt/folding_rules.cpp
index 7730ac1..5c68e29 100644
--- a/third_party/SPIRV-Tools/source/opt/folding_rules.cpp
+++ b/third_party/SPIRV-Tools/source/opt/folding_rules.cpp
@@ -2067,7 +2067,8 @@
 }
 
 // Returns the number of elements in the composite type |type|.  Returns 0 if
-// |type| is a scalar value.
+// |type| is a scalar value. Return UINT32_MAX when the size is unknown at
+// compile time.
 uint32_t GetNumberOfElements(const analysis::Type* type) {
   if (auto* vector_type = type->AsVector()) {
     return vector_type->element_count();
@@ -2079,21 +2080,27 @@
     return static_cast<uint32_t>(struct_type->element_types().size());
   }
   if (auto* array_type = type->AsArray()) {
-    return array_type->length_info().words[0];
+    if (array_type->length_info().words[0] ==
+            analysis::Array::LengthInfo::kConstant &&
+        array_type->length_info().words.size() == 2) {
+      return array_type->length_info().words[1];
+    }
+    return UINT32_MAX;
   }
   return 0;
 }
 
 // Returns a map with the set of values that were inserted into an object by
 // the chain of OpCompositeInsertInstruction starting with |inst|.
-// The map will map the index to the value inserted at that index.
+// The map will map the index to the value inserted at that index. An empty map
+// will be returned if the map could not be properly generated.
 std::map<uint32_t, uint32_t> GetInsertedValues(Instruction* inst) {
   analysis::DefUseManager* def_use_mgr = inst->context()->get_def_use_mgr();
   std::map<uint32_t, uint32_t> values_inserted;
   Instruction* current_inst = inst;
   while (current_inst->opcode() == spv::Op::OpCompositeInsert) {
     if (current_inst->NumInOperands() > inst->NumInOperands()) {
-      // This is the catch the case
+      // This is to catch the case
       //   %2 = OpCompositeInsert %m2x2int %v2int_1_0 %m2x2int_undef 0
       //   %3 = OpCompositeInsert %m2x2int %int_4 %2 0 0
       //   %4 = OpCompositeInsert %m2x2int %v2int_2_3 %3 1
@@ -2884,8 +2891,12 @@
                "Offset and ConstOffset may not be used together");
         if (offset_operand_index < inst->NumOperands()) {
           if (constants[offset_operand_index]) {
-            image_operands =
-                image_operands | uint32_t(spv::ImageOperandsMask::ConstOffset);
+            if (constants[offset_operand_index]->IsZero()) {
+              inst->RemoveInOperand(offset_operand_index);
+            } else {
+              image_operands = image_operands |
+                               uint32_t(spv::ImageOperandsMask::ConstOffset);
+            }
             image_operands =
                 image_operands & ~uint32_t(spv::ImageOperandsMask::Offset);
             inst->SetInOperand(operand_index, {image_operands});
diff --git a/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.cpp b/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.cpp
index 8fff8a0..e765c39 100644
--- a/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.cpp
@@ -573,9 +573,9 @@
       context()->module()->AddExtInstImport(std::move(import_inst));
       module_status_.modified = true;
       context()->AnalyzeDefUse(inst);
-      // Reanalyze the feature list, since we added an extended instruction
-      // set improt.
-      context()->get_feature_mgr()->Analyze(context()->module());
+      // Invalidates the feature manager, since we added an extended instruction
+      // set import.
+      context()->ResetFeatureManager();
     }
   }
   return module_status_.glsl_insts_id;
diff --git a/third_party/SPIRV-Tools/source/opt/inline_pass.cpp b/third_party/SPIRV-Tools/source/opt/inline_pass.cpp
index 3f160b2..3186433 100644
--- a/third_party/SPIRV-Tools/source/opt/inline_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/inline_pass.cpp
@@ -213,6 +213,19 @@
         {(uint32_t)spv::StorageClass::Function}}}));
   new_vars->push_back(std::move(var_inst));
   get_decoration_mgr()->CloneDecorations(calleeFn->result_id(), returnVarId);
+
+  // Decorate the return var with AliasedPointer if the storage class of the
+  // pointee type is PhysicalStorageBuffer.
+  auto const pointee_type =
+      type_mgr->GetType(returnVarTypeId)->AsPointer()->pointee_type();
+  if (pointee_type->AsPointer() != nullptr) {
+    if (pointee_type->AsPointer()->storage_class() ==
+        spv::StorageClass::PhysicalStorageBuffer) {
+      get_decoration_mgr()->AddDecoration(
+          returnVarId, uint32_t(spv::Decoration::AliasedPointer));
+    }
+  }
+
   return returnVarId;
 }
 
diff --git a/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.cpp b/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.cpp
index e8c412f..8e7d4f8 100644
--- a/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.cpp
@@ -31,532 +31,88 @@
 constexpr int kSpvAccessChainBaseIdInIdx = 0;
 constexpr int kSpvAccessChainIndex0IdInIdx = 1;
 constexpr int kSpvTypeArrayTypeIdInIdx = 0;
-constexpr int kSpvTypeArrayLengthIdInIdx = 1;
-constexpr int kSpvConstantValueInIdx = 0;
 constexpr int kSpvVariableStorageClassInIdx = 0;
 constexpr int kSpvTypePtrTypeIdInIdx = 1;
 constexpr int kSpvTypeImageDim = 1;
 constexpr int kSpvTypeImageDepth = 2;
 constexpr int kSpvTypeImageArrayed = 3;
 constexpr int kSpvTypeImageMS = 4;
-constexpr int kSpvTypeImageSampled = 5;
 }  // namespace
 
-void InstBindlessCheckPass::SetupInputBufferIds() {
-  if (input_buffer_id_ != 0) {
-    return;
+// This is a stub function for use with Import linkage
+// clang-format off
+// GLSL:
+//bool inst_bindless_check_desc(const uint shader_id, const uint inst_num, const uvec4 stage_info, const uint desc_set,
+//                              const uint binding, const uint desc_index, const uint byte_offset) {
+//}
+// clang-format on
+uint32_t InstBindlessCheckPass::GenDescCheckFunctionId() {
+  enum {
+    kShaderId = 0,
+    kInstructionIndex = 1,
+    kStageInfo = 2,
+    kDescSet = 3,
+    kDescBinding = 4,
+    kDescIndex = 5,
+    kByteOffset = 6,
+    kNumArgs
+  };
+  if (check_desc_func_id_ != 0) {
+    return check_desc_func_id_;
   }
-  AddStorageBufferExt();
-  if (!get_feature_mgr()->HasExtension(kSPV_KHR_physical_storage_buffer)) {
-    context()->AddExtension("SPV_KHR_physical_storage_buffer");
-  }
-  context()->AddCapability(spv::Capability::PhysicalStorageBufferAddresses);
-  Instruction* memory_model = get_module()->GetMemoryModel();
-  // TODO should this be just Physical64?
-  memory_model->SetInOperand(
-      0u, {uint32_t(spv::AddressingModel::PhysicalStorageBuffer64)});
 
-  analysis::DecorationManager* deco_mgr = get_decoration_mgr();
   analysis::TypeManager* type_mgr = context()->get_type_mgr();
-  constexpr uint32_t width = 32u;
+  const analysis::Integer* uint_type = GetInteger(32, false);
+  const analysis::Vector v4uint(uint_type, 4);
+  const analysis::Type* v4uint_type = type_mgr->GetRegisteredType(&v4uint);
+  std::vector<const analysis::Type*> param_types(kNumArgs, uint_type);
+  param_types[2] = v4uint_type;
 
-  // declare the DescriptorSetData struct
-  analysis::Struct* desc_set_struct =
-      GetStruct({type_mgr->GetUIntType(), GetUintRuntimeArrayType(width)});
-  desc_set_type_id_ = type_mgr->GetTypeInstruction(desc_set_struct);
-  // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
-  // must be a block, and will therefore be decorated with Block. Therefore
-  // the undecorated type returned here will not be pre-existing and can
-  // safely be decorated. Since this type is now decorated, it is out of
-  // sync with the TypeManager and therefore the TypeManager must be
-  // invalidated after this pass.
-  assert(context()->get_def_use_mgr()->NumUses(desc_set_type_id_) == 0 &&
-         "used struct type returned");
-  deco_mgr->AddDecoration(desc_set_type_id_, uint32_t(spv::Decoration::Block));
-  deco_mgr->AddMemberDecoration(desc_set_type_id_, 0,
-                                uint32_t(spv::Decoration::Offset), 0);
-  deco_mgr->AddMemberDecoration(desc_set_type_id_, 1,
-                                uint32_t(spv::Decoration::Offset), 4);
-  context()->AddDebug2Inst(
-      NewGlobalName(desc_set_type_id_, "DescriptorSetData"));
-  context()->AddDebug2Inst(NewMemberName(desc_set_type_id_, 0, "num_bindings"));
-  context()->AddDebug2Inst(NewMemberName(desc_set_type_id_, 1, "data"));
+  const uint32_t func_id = TakeNextId();
+  std::unique_ptr<Function> func =
+      StartFunction(func_id, type_mgr->GetBoolType(), param_types);
 
-  // declare buffer address reference to DescriptorSetData
-  desc_set_ptr_id_ = type_mgr->FindPointerToType(
-      desc_set_type_id_, spv::StorageClass::PhysicalStorageBuffer);
-  // runtime array of buffer addresses
-  analysis::Type* rarr_ty = GetArray(type_mgr->GetType(desc_set_ptr_id_),
-                                     kDebugInputBindlessMaxDescSets);
-  deco_mgr->AddDecorationVal(type_mgr->GetId(rarr_ty),
-                             uint32_t(spv::Decoration::ArrayStride), 8u);
+  func->SetFunctionEnd(EndFunction());
 
-  // declare the InputBuffer type, a struct wrapper around the runtime array
-  analysis::Struct* input_buffer_struct = GetStruct({rarr_ty});
-  input_buffer_struct_id_ = type_mgr->GetTypeInstruction(input_buffer_struct);
-  deco_mgr->AddDecoration(input_buffer_struct_id_,
-                          uint32_t(spv::Decoration::Block));
-  deco_mgr->AddMemberDecoration(input_buffer_struct_id_, 0,
-                                uint32_t(spv::Decoration::Offset), 0);
-  context()->AddDebug2Inst(
-      NewGlobalName(input_buffer_struct_id_, "InputBuffer"));
-  context()->AddDebug2Inst(
-      NewMemberName(input_buffer_struct_id_, 0, "desc_sets"));
-
-  input_buffer_ptr_id_ = type_mgr->FindPointerToType(
-      input_buffer_struct_id_, spv::StorageClass::StorageBuffer);
-
-  // declare the input_buffer global variable
-  input_buffer_id_ = TakeNextId();
-
-  const std::vector<Operand> var_operands = {
+  static const std::string func_name{"inst_bindless_check_desc"};
+  context()->AddFunctionDeclaration(std::move(func));
+  context()->AddDebug2Inst(NewName(func_id, func_name));
+  std::vector<Operand> operands{
+      {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {func_id}},
       {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
-       {uint32_t(spv::StorageClass::StorageBuffer)}},
+       {uint32_t(spv::Decoration::LinkageAttributes)}},
+      {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_STRING,
+       utils::MakeVector(func_name.c_str())},
+      {spv_operand_type_t::SPV_OPERAND_TYPE_LINKAGE_TYPE,
+       {uint32_t(spv::LinkageType::Import)}},
   };
-  auto new_var_op = spvtools::MakeUnique<Instruction>(
-      context(), spv::Op::OpVariable, input_buffer_ptr_id_, input_buffer_id_,
-      var_operands);
+  get_decoration_mgr()->AddDecoration(spv::Op::OpDecorate, operands);
 
-  context()->AddGlobalValue(std::move(new_var_op));
-  context()->AddDebug2Inst(NewGlobalName(input_buffer_id_, "input_buffer"));
-  deco_mgr->AddDecorationVal(
-      input_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
-  deco_mgr->AddDecorationVal(input_buffer_id_,
-                             uint32_t(spv::Decoration::Binding),
-                             GetInputBufferBinding());
-  if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
-    // Add the new buffer to all entry points.
-    for (auto& entry : get_module()->entry_points()) {
-      entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}});
-      context()->AnalyzeUses(&entry);
-    }
-  }
-}
-
-// clang-format off
-// GLSL:
-// uint inst_bindless_read_binding_length(uint desc_set_idx, uint binding_idx)
-// {
-//     if (desc_set_idx >= inst_bindless_input_buffer.desc_sets.length()) {
-//         return 0;
-//     }
-//
-//     DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx];
-//     uvec2 ptr_as_vec = uvec2(set_data);
-//     if ((ptr_as_vec.x == 0u) && (_ptr_as_vec.y == 0u))
-//     {
-//         return 0u;
-//     }
-//     uint num_bindings = set_data.num_bindings;
-//     if (binding_idx >= num_bindings) {
-//         return 0;
-//     }
-//     return set_data.data[binding_idx];
-// }
-// clang-format on
-uint32_t InstBindlessCheckPass::GenDebugReadLengthFunctionId() {
-  if (read_length_func_id_ != 0) {
-    return read_length_func_id_;
-  }
-  SetupInputBufferIds();
-  const analysis::Integer* uint_type = GetInteger(32, false);
-  const std::vector<const analysis::Type*> param_types(2, uint_type);
-
-  const uint32_t func_id = TakeNextId();
-  std::unique_ptr<Function> func =
-      StartFunction(func_id, uint_type, param_types);
-
-  const std::vector<uint32_t> param_ids = AddParameters(*func, param_types);
-
-  // Create block
-  auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
-  InstructionBuilder builder(
-      context(), new_blk_ptr.get(),
-      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
-  Instruction* inst;
-
-  inst = builder.AddBinaryOp(
-      GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[0],
-      builder.GetUintConstantId(kDebugInputBindlessMaxDescSets));
-  const uint32_t desc_cmp_id = inst->result_id();
-
-  uint32_t error_blk_id = TakeNextId();
-  uint32_t merge_blk_id = TakeNextId();
-  std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
-  std::unique_ptr<Instruction> error_label(NewLabel(error_blk_id));
-  (void)builder.AddConditionalBranch(desc_cmp_id, error_blk_id, merge_blk_id,
-                                     merge_blk_id);
-
-  func->AddBasicBlock(std::move(new_blk_ptr));
-
-  // error return
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
-                           builder.GetUintConstantId(0));
-  func->AddBasicBlock(std::move(new_blk_ptr));
-
-  // check descriptor set table entry is non-null
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-
-  analysis::TypeManager* type_mgr = context()->get_type_mgr();
-  const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType(
-      desc_set_ptr_id_, spv::StorageClass::StorageBuffer);
-
-  inst = builder.AddAccessChain(desc_set_ptr_ptr, input_buffer_id_,
-                                {builder.GetUintConstantId(0), param_ids[0]});
-  const uint32_t set_access_chain_id = inst->result_id();
-
-  inst = builder.AddLoad(desc_set_ptr_id_, set_access_chain_id);
-  const uint32_t desc_set_ptr_id = inst->result_id();
-
-  inst =
-      builder.AddUnaryOp(GetVecUintId(2), spv::Op::OpBitcast, desc_set_ptr_id);
-  const uint32_t ptr_as_uvec_id = inst->result_id();
-
-  inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {0});
-  const uint32_t uvec_x = inst->result_id();
-
-  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_x,
-                             builder.GetUintConstantId(0));
-  const uint32_t x_is_zero_id = inst->result_id();
-
-  inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {1});
-  const uint32_t uvec_y = inst->result_id();
-
-  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_y,
-                             builder.GetUintConstantId(0));
-  const uint32_t y_is_zero_id = inst->result_id();
-
-  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpLogicalAnd, x_is_zero_id,
-                             y_is_zero_id);
-  const uint32_t is_null_id = inst->result_id();
-
-  error_blk_id = TakeNextId();
-  merge_blk_id = TakeNextId();
-  merge_label = NewLabel(merge_blk_id);
-  error_label = NewLabel(error_blk_id);
-  (void)builder.AddConditionalBranch(is_null_id, error_blk_id, merge_blk_id,
-                                     merge_blk_id);
-  func->AddBasicBlock(std::move(new_blk_ptr));
-  // error return
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
-                           builder.GetUintConstantId(0));
-  func->AddBasicBlock(std::move(new_blk_ptr));
-
-  // check binding is in range
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-
-  const uint32_t uint_ptr = type_mgr->FindPointerToType(
-      GetUintId(), spv::StorageClass::PhysicalStorageBuffer);
-
-  inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
-                                {builder.GetUintConstantId(0)});
-  const uint32_t binding_access_chain_id = inst->result_id();
-
-  inst = builder.AddLoad(GetUintId(), binding_access_chain_id, 8);
-  const uint32_t num_bindings_id = inst->result_id();
-
-  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual,
-                             param_ids[1], num_bindings_id);
-  const uint32_t bindings_cmp_id = inst->result_id();
-
-  error_blk_id = TakeNextId();
-  merge_blk_id = TakeNextId();
-  merge_label = NewLabel(merge_blk_id);
-  error_label = NewLabel(error_blk_id);
-  (void)builder.AddConditionalBranch(bindings_cmp_id, error_blk_id,
-                                     merge_blk_id, merge_blk_id);
-  func->AddBasicBlock(std::move(new_blk_ptr));
-  // error return
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
-                           builder.GetUintConstantId(0));
-  func->AddBasicBlock(std::move(new_blk_ptr));
-
-  // read binding length
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-
-  inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
-                                {{builder.GetUintConstantId(1), param_ids[1]}});
-  const uint32_t length_ac_id = inst->result_id();
-
-  inst = builder.AddLoad(GetUintId(), length_ac_id, sizeof(uint32_t));
-  const uint32_t length_id = inst->result_id();
-
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, length_id);
-
-  func->AddBasicBlock(std::move(new_blk_ptr));
-  func->SetFunctionEnd(EndFunction());
-
-  context()->AddFunction(std::move(func));
-  context()->AddDebug2Inst(NewGlobalName(func_id, "read_binding_length"));
-
-  read_length_func_id_ = func_id;
-  // Make sure this function doesn't get processed by
-  // InstrumentPass::InstProcessCallTreeFromRoots()
-  param2output_func_id_[2] = func_id;
-  return read_length_func_id_;
-}
-
-// clang-format off
-// GLSL:
-// result = inst_bindless_read_binding_length(desc_set_id, binding_id);
-// clang-format on
-uint32_t InstBindlessCheckPass::GenDebugReadLength(
-    uint32_t var_id, InstructionBuilder* builder) {
-  const uint32_t func_id = GenDebugReadLengthFunctionId();
-
-  const std::vector<uint32_t> args = {
-      builder->GetUintConstantId(var2desc_set_[var_id]),
-      builder->GetUintConstantId(var2binding_[var_id]),
-  };
-  return GenReadFunctionCall(func_id, args, builder);
-}
-
-// clang-format off
-// GLSL:
-// uint inst_bindless_read_desc_init(uint desc_set_idx, uint binding_idx, uint desc_idx)
-// {
-//     if (desc_set_idx >= uint(inst_bindless_input_buffer.desc_sets.length()))
-//     {
-//         return 0u;
-//     }
-//     DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx];
-//     uvec2 ptr_as_vec = uvec2(set_data)
-//     if ((ptr_as_vec .x == 0u) && (ptr_as_vec.y == 0u))
-//     {
-//         return 0u;
-//     }
-//     if (binding_idx >= set_data.num_bindings)
-//     {
-//         return 0u;
-//     }
-//     if (desc_idx >= set_data.data[binding_idx])
-//     {
-//         return 0u;
-//     }
-//     uint desc_records_start = set_data.data[set_data.num_bindings + binding_idx];
-//     return set_data.data[desc_records_start + desc_idx];
-// }
-// clang-format on
-uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() {
-  if (read_init_func_id_ != 0) {
-    return read_init_func_id_;
-  }
-  SetupInputBufferIds();
-  const analysis::Integer* uint_type = GetInteger(32, false);
-  const std::vector<const analysis::Type*> param_types(3, uint_type);
-
-  const uint32_t func_id = TakeNextId();
-  std::unique_ptr<Function> func =
-      StartFunction(func_id, uint_type, param_types);
-
-  const std::vector<uint32_t> param_ids = AddParameters(*func, param_types);
-
-  // Create block
-  auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
-  InstructionBuilder builder(
-      context(), new_blk_ptr.get(),
-      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
-  Instruction* inst;
-
-  inst = builder.AddBinaryOp(
-      GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[0],
-      builder.GetUintConstantId(kDebugInputBindlessMaxDescSets));
-  const uint32_t desc_cmp_id = inst->result_id();
-
-  uint32_t error_blk_id = TakeNextId();
-  uint32_t merge_blk_id = TakeNextId();
-  std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
-  std::unique_ptr<Instruction> error_label(NewLabel(error_blk_id));
-  (void)builder.AddConditionalBranch(desc_cmp_id, error_blk_id, merge_blk_id,
-                                     merge_blk_id);
-  func->AddBasicBlock(std::move(new_blk_ptr));
-
-  // error return
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
-                           builder.GetUintConstantId(0));
-  func->AddBasicBlock(std::move(new_blk_ptr));
-
-  // check descriptor set table entry is non-null
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-
-  analysis::TypeManager* type_mgr = context()->get_type_mgr();
-  const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType(
-      desc_set_ptr_id_, spv::StorageClass::StorageBuffer);
-
-  inst = builder.AddAccessChain(desc_set_ptr_ptr, input_buffer_id_,
-                                {builder.GetUintConstantId(0), param_ids[0]});
-  const uint32_t set_access_chain_id = inst->result_id();
-
-  inst = builder.AddLoad(desc_set_ptr_id_, set_access_chain_id);
-  const uint32_t desc_set_ptr_id = inst->result_id();
-
-  inst =
-      builder.AddUnaryOp(GetVecUintId(2), spv::Op::OpBitcast, desc_set_ptr_id);
-  const uint32_t ptr_as_uvec_id = inst->result_id();
-
-  inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {0});
-  const uint32_t uvec_x = inst->result_id();
-
-  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_x,
-                             builder.GetUintConstantId(0));
-  const uint32_t x_is_zero_id = inst->result_id();
-
-  inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {1});
-  const uint32_t uvec_y = inst->result_id();
-
-  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_y,
-                             builder.GetUintConstantId(0));
-  const uint32_t y_is_zero_id = inst->result_id();
-
-  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpLogicalAnd, x_is_zero_id,
-                             y_is_zero_id);
-  const uint32_t is_null_id = inst->result_id();
-
-  error_blk_id = TakeNextId();
-  merge_blk_id = TakeNextId();
-  merge_label = NewLabel(merge_blk_id);
-  error_label = NewLabel(error_blk_id);
-  (void)builder.AddConditionalBranch(is_null_id, error_blk_id, merge_blk_id,
-                                     merge_blk_id);
-  func->AddBasicBlock(std::move(new_blk_ptr));
-  // error return
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
-                           builder.GetUintConstantId(0));
-  func->AddBasicBlock(std::move(new_blk_ptr));
-
-  // check binding is in range
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-
-  const uint32_t uint_ptr = type_mgr->FindPointerToType(
-      GetUintId(), spv::StorageClass::PhysicalStorageBuffer);
-
-  inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
-                                {builder.GetUintConstantId(0)});
-  const uint32_t binding_access_chain_id = inst->result_id();
-
-  inst = builder.AddLoad(GetUintId(), binding_access_chain_id, 8);
-  const uint32_t num_bindings_id = inst->result_id();
-
-  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual,
-                             param_ids[1], num_bindings_id);
-  const uint32_t bindings_cmp_id = inst->result_id();
-
-  error_blk_id = TakeNextId();
-  merge_blk_id = TakeNextId();
-  merge_label = NewLabel(merge_blk_id);
-  error_label = NewLabel(error_blk_id);
-  (void)builder.AddConditionalBranch(bindings_cmp_id, error_blk_id,
-                                     merge_blk_id, merge_blk_id);
-  func->AddBasicBlock(std::move(new_blk_ptr));
-  // error return
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
-                           builder.GetUintConstantId(0));
-  func->AddBasicBlock(std::move(new_blk_ptr));
-
-  // read binding length
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-
-  inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
-                                {{builder.GetUintConstantId(1), param_ids[1]}});
-  const uint32_t length_ac_id = inst->result_id();
-
-  inst = builder.AddLoad(GetUintId(), length_ac_id, sizeof(uint32_t));
-  const uint32_t length_id = inst->result_id();
-
-  // Check descriptor index in bounds
-  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual,
-                             param_ids[2], length_id);
-  const uint32_t desc_idx_range_id = inst->result_id();
-
-  error_blk_id = TakeNextId();
-  merge_blk_id = TakeNextId();
-  merge_label = NewLabel(merge_blk_id);
-  error_label = NewLabel(error_blk_id);
-  (void)builder.AddConditionalBranch(desc_idx_range_id, error_blk_id,
-                                     merge_blk_id, merge_blk_id);
-  func->AddBasicBlock(std::move(new_blk_ptr));
-  // Error return
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
-                           builder.GetUintConstantId(0));
-  func->AddBasicBlock(std::move(new_blk_ptr));
-
-  // Read descriptor init status
-  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
-  builder.SetInsertPoint(&*new_blk_ptr);
-
-  inst = builder.AddIAdd(GetUintId(), num_bindings_id, param_ids[1]);
-  const uint32_t state_offset_id = inst->result_id();
-
-  inst =
-      builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
-                             {{builder.GetUintConstantId(1), state_offset_id}});
-  const uint32_t state_start_ac_id = inst->result_id();
-
-  inst = builder.AddLoad(GetUintId(), state_start_ac_id, sizeof(uint32_t));
-  const uint32_t state_start_id = inst->result_id();
-
-  inst = builder.AddIAdd(GetUintId(), state_start_id, param_ids[2]);
-  const uint32_t state_entry_id = inst->result_id();
-
-  // Note: length starts from the beginning of the buffer, not the beginning of
-  // the data array
-  inst =
-      builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
-                             {{builder.GetUintConstantId(1), state_entry_id}});
-  const uint32_t init_ac_id = inst->result_id();
-
-  inst = builder.AddLoad(GetUintId(), init_ac_id, sizeof(uint32_t));
-  const uint32_t init_status_id = inst->result_id();
-
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, init_status_id);
-
-  func->AddBasicBlock(std::move(new_blk_ptr));
-  func->SetFunctionEnd(EndFunction());
-
-  context()->AddFunction(std::move(func));
-  context()->AddDebug2Inst(NewGlobalName(func_id, "read_desc_init"));
-
-  read_init_func_id_ = func_id;
+  check_desc_func_id_ = func_id;
   // Make sure function doesn't get processed by
   // InstrumentPass::InstProcessCallTreeFromRoots()
   param2output_func_id_[3] = func_id;
-  return read_init_func_id_;
+  return check_desc_func_id_;
 }
 
 // clang-format off
 // GLSL:
-// result = inst_bindless_read_desc_init(desc_set_id, binding_id, desc_idx_id);
+// result = inst_bindless_check_desc(shader_id, inst_idx, stage_info, desc_set, binding, desc_idx, offset);
 //
 // clang-format on
-uint32_t InstBindlessCheckPass::GenDebugReadInit(uint32_t var_id,
-                                                 uint32_t desc_idx_id,
-                                                 InstructionBuilder* builder) {
-  const uint32_t func_id = GenDebugReadInitFunctionId();
+uint32_t InstBindlessCheckPass::GenDescCheckCall(
+    uint32_t inst_idx, uint32_t stage_idx, uint32_t var_id,
+    uint32_t desc_idx_id, uint32_t offset_id, InstructionBuilder* builder) {
+  const uint32_t func_id = GenDescCheckFunctionId();
   const std::vector<uint32_t> args = {
+      builder->GetUintConstantId(shader_id_),
+      builder->GetUintConstantId(inst_idx),
+      GenStageInfo(stage_idx, builder),
       builder->GetUintConstantId(var2desc_set_[var_id]),
       builder->GetUintConstantId(var2binding_[var_id]),
-      GenUintCastCode(desc_idx_id, builder)};
-  return GenReadFunctionCall(func_id, args, builder);
+      GenUintCastCode(desc_idx_id, builder),
+      offset_id};
+  return GenReadFunctionCall(GetBoolId(), func_id, args, builder);
 }
 
 uint32_t InstBindlessCheckPass::CloneOriginalImage(
@@ -1017,8 +573,7 @@
 }
 
 void InstBindlessCheckPass::GenCheckCode(
-    uint32_t check_id, uint32_t error_id, uint32_t offset_id,
-    uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref,
+    uint32_t check_id, RefAnalysis* ref,
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
   BasicBlock* back_blk_ptr = &*new_blocks->back();
   InstructionBuilder builder(
@@ -1047,30 +602,7 @@
   // Gen invalid block
   new_blk_ptr.reset(new BasicBlock(std::move(invalid_label)));
   builder.SetInsertPoint(&*new_blk_ptr);
-  const uint32_t u_set_id = builder.GetUintConstantId(ref->set);
-  const uint32_t u_binding_id = builder.GetUintConstantId(ref->binding);
-  const uint32_t u_index_id = GenUintCastCode(ref->desc_idx_id, &builder);
-  const uint32_t u_length_id = GenUintCastCode(length_id, &builder);
-  if (offset_id != 0) {
-    const uint32_t u_offset_id = GenUintCastCode(offset_id, &builder);
-    // Buffer OOB
-    GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx,
-                        {error_id, u_set_id, u_binding_id, u_index_id,
-                         u_offset_id, u_length_id},
-                        &builder);
-  } else if (buffer_bounds_enabled_ || texel_buffer_enabled_) {
-    // Uninitialized Descriptor - Return additional unused zero so all error
-    // modes will use same debug stream write function
-    GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx,
-                        {error_id, u_set_id, u_binding_id, u_index_id,
-                         u_length_id, builder.GetUintConstantId(0)},
-                        &builder);
-  } else {
-    // Uninitialized Descriptor - Normal error return
-    GenDebugStreamWrite(
-        uid2offset_[ref->ref_inst->unique_id()], stage_idx,
-        {error_id, u_set_id, u_binding_id, u_index_id, u_length_id}, &builder);
-  }
+
   // Generate a ConstantNull, converting to uint64 if the type cannot be a null.
   if (new_ref_id != 0) {
     analysis::TypeManager* type_mgr = context()->get_type_mgr();
@@ -1106,77 +638,42 @@
   context()->KillInst(ref->ref_inst);
 }
 
-void InstBindlessCheckPass::GenDescIdxCheckCode(
-    BasicBlock::iterator ref_inst_itr,
-    UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
-    std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
-  // Look for reference through indexed descriptor. If found, analyze and
-  // save components. If not, return.
-  RefAnalysis ref;
-  if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
-  Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id);
-  if (ptr_inst->opcode() != spv::Op::OpAccessChain) return;
-  // If index and bound both compile-time constants and index < bound,
-  // return without changing
-  Instruction* var_inst = get_def_use_mgr()->GetDef(ref.var_id);
-  Instruction* desc_type_inst = GetPointeeTypeInst(var_inst);
-  uint32_t length_id = 0;
-  if (desc_type_inst->opcode() == spv::Op::OpTypeArray) {
-    length_id =
-        desc_type_inst->GetSingleWordInOperand(kSpvTypeArrayLengthIdInIdx);
-    Instruction* index_inst = get_def_use_mgr()->GetDef(ref.desc_idx_id);
-    Instruction* length_inst = get_def_use_mgr()->GetDef(length_id);
-    if (index_inst->opcode() == spv::Op::OpConstant &&
-        length_inst->opcode() == spv::Op::OpConstant &&
-        index_inst->GetSingleWordInOperand(kSpvConstantValueInIdx) <
-            length_inst->GetSingleWordInOperand(kSpvConstantValueInIdx))
-      return;
-  } else if (!desc_idx_enabled_ ||
-             desc_type_inst->opcode() != spv::Op::OpTypeRuntimeArray) {
-    return;
-  }
-  // Move original block's preceding instructions into first new block
-  std::unique_ptr<BasicBlock> new_blk_ptr;
-  MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
-  InstructionBuilder builder(
-      context(), &*new_blk_ptr,
-      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
-  new_blocks->push_back(std::move(new_blk_ptr));
-  uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBounds);
-  // If length id not yet set, descriptor array is runtime size so
-  // generate load of length from stage's debug input buffer.
-  if (length_id == 0) {
-    assert(desc_type_inst->opcode() == spv::Op::OpTypeRuntimeArray &&
-           "unexpected bindless type");
-    length_id = GenDebugReadLength(ref.var_id, &builder);
-  }
-  // Generate full runtime bounds test code with true branch
-  // being full reference and false branch being debug output and zero
-  // for the referenced value.
-  uint32_t desc_idx_32b_id = Gen32BitCvtCode(ref.desc_idx_id, &builder);
-  uint32_t length_32b_id = Gen32BitCvtCode(length_id, &builder);
-  Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpULessThan,
-                                              desc_idx_32b_id, length_32b_id);
-  ref.desc_idx_id = desc_idx_32b_id;
-  GenCheckCode(ult_inst->result_id(), error_id, 0u, length_id, stage_idx, &ref,
-               new_blocks);
-  // Move original block's remaining code into remainder/merge block and add
-  // to new blocks
-  BasicBlock* back_blk_ptr = &*new_blocks->back();
-  MovePostludeCode(ref_block_itr, back_blk_ptr);
-}
-
-void InstBindlessCheckPass::GenDescInitCheckCode(
+void InstBindlessCheckPass::GenDescCheckCode(
     BasicBlock::iterator ref_inst_itr,
     UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
   // Look for reference through descriptor. If not, return.
   RefAnalysis ref;
   if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
+  std::unique_ptr<BasicBlock> new_blk_ptr;
+  // Move original block's preceding instructions into first new block
+  MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
+  InstructionBuilder builder(
+      context(), &*new_blk_ptr,
+      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+  new_blocks->push_back(std::move(new_blk_ptr));
   // Determine if we can only do initialization check
-  bool init_check = false;
-  if (ref.desc_load_id != 0 || !buffer_bounds_enabled_) {
-    init_check = true;
+  uint32_t ref_id = builder.GetUintConstantId(0u);
+  spv::Op op = ref.ref_inst->opcode();
+  if (ref.desc_load_id != 0) {
+    uint32_t num_in_oprnds = ref.ref_inst->NumInOperands();
+    if ((op == spv::Op::OpImageRead && num_in_oprnds == 2) ||
+        (op == spv::Op::OpImageFetch && num_in_oprnds == 2) ||
+        (op == spv::Op::OpImageWrite && num_in_oprnds == 3)) {
+      Instruction* image_inst = get_def_use_mgr()->GetDef(ref.image_id);
+      uint32_t image_ty_id = image_inst->type_id();
+      Instruction* image_ty_inst = get_def_use_mgr()->GetDef(image_ty_id);
+      if (spv::Dim(image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim)) ==
+          spv::Dim::Buffer) {
+        if ((image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDepth) == 0) &&
+            (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) ==
+             0) &&
+            (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) == 0)) {
+          ref_id = GenUintCastCode(ref.ref_inst->GetSingleWordInOperand(1),
+                                   &builder);
+        }
+      }
+    }
   } else {
     // For now, only do bounds check for non-aggregate types. Otherwise
     // just do descriptor initialization check.
@@ -1184,106 +681,24 @@
     Instruction* ref_ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id);
     Instruction* pte_type_inst = GetPointeeTypeInst(ref_ptr_inst);
     spv::Op pte_type_op = pte_type_inst->opcode();
-    if (pte_type_op == spv::Op::OpTypeArray ||
-        pte_type_op == spv::Op::OpTypeRuntimeArray ||
-        pte_type_op == spv::Op::OpTypeStruct)
-      init_check = true;
+    if (pte_type_op != spv::Op::OpTypeArray &&
+        pte_type_op != spv::Op::OpTypeRuntimeArray &&
+        pte_type_op != spv::Op::OpTypeStruct) {
+      ref_id = GenLastByteIdx(&ref, &builder);
+    }
   }
-  // If initialization check and not enabled, return
-  if (init_check && !desc_init_enabled_) return;
-  // Move original block's preceding instructions into first new block
-  std::unique_ptr<BasicBlock> new_blk_ptr;
-  MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
-  InstructionBuilder builder(
-      context(), &*new_blk_ptr,
-      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
-  new_blocks->push_back(std::move(new_blk_ptr));
-  // If initialization check, use reference value of zero.
-  // Else use the index of the last byte referenced.
-  uint32_t ref_id = init_check ? builder.GetUintConstantId(0u)
-                               : GenLastByteIdx(&ref, &builder);
   // Read initialization/bounds from debug input buffer. If index id not yet
   // set, binding is single descriptor, so set index to constant 0.
   if (ref.desc_idx_id == 0) ref.desc_idx_id = builder.GetUintConstantId(0u);
-  uint32_t init_id = GenDebugReadInit(ref.var_id, ref.desc_idx_id, &builder);
-  // Generate runtime initialization/bounds test code with true branch
-  // being full reference and false branch being debug output and zero
-  // for the referenced value.
-  Instruction* ult_inst =
-      builder.AddBinaryOp(GetBoolId(), spv::Op::OpULessThan, ref_id, init_id);
-  uint32_t error =
-      init_check
-          ? kInstErrorBindlessUninit
-          : (spv::StorageClass(ref.strg_class) == spv::StorageClass::Uniform
-                 ? kInstErrorBuffOOBUniform
-                 : kInstErrorBuffOOBStorage);
-  uint32_t error_id = builder.GetUintConstantId(error);
-  GenCheckCode(ult_inst->result_id(), error_id, init_check ? 0 : ref_id,
-               init_check ? builder.GetUintConstantId(0u) : init_id, stage_idx,
-               &ref, new_blocks);
-  // Move original block's remaining code into remainder/merge block and add
-  // to new blocks
-  BasicBlock* back_blk_ptr = &*new_blocks->back();
-  MovePostludeCode(ref_block_itr, back_blk_ptr);
-}
+  uint32_t check_id =
+      GenDescCheckCall(ref.ref_inst->unique_id(), stage_idx, ref.var_id,
+                       ref.desc_idx_id, ref_id, &builder);
 
-void InstBindlessCheckPass::GenTexBuffCheckCode(
-    BasicBlock::iterator ref_inst_itr,
-    UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
-    std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
-  // Only process OpImageRead and OpImageWrite with no optional operands
-  Instruction* ref_inst = &*ref_inst_itr;
-  spv::Op op = ref_inst->opcode();
-  uint32_t num_in_oprnds = ref_inst->NumInOperands();
-  if (!((op == spv::Op::OpImageRead && num_in_oprnds == 2) ||
-        (op == spv::Op::OpImageFetch && num_in_oprnds == 2) ||
-        (op == spv::Op::OpImageWrite && num_in_oprnds == 3)))
-    return;
-  // Pull components from descriptor reference
-  RefAnalysis ref;
-  if (!AnalyzeDescriptorReference(ref_inst, &ref)) return;
-  // Only process if image is texel buffer
-  Instruction* image_inst = get_def_use_mgr()->GetDef(ref.image_id);
-  uint32_t image_ty_id = image_inst->type_id();
-  Instruction* image_ty_inst = get_def_use_mgr()->GetDef(image_ty_id);
-  if (spv::Dim(image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim)) !=
-      spv::Dim::Buffer) {
-    return;
-  }
-  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDepth) != 0) return;
-  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) != 0) return;
-  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) != 0) return;
-  // Enable ImageQuery Capability if not yet enabled
-  context()->AddCapability(spv::Capability::ImageQuery);
-  // Move original block's preceding instructions into first new block
-  std::unique_ptr<BasicBlock> new_blk_ptr;
-  MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
-  InstructionBuilder builder(
-      context(), &*new_blk_ptr,
-      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
-  new_blocks->push_back(std::move(new_blk_ptr));
-  // Get texel coordinate
-  uint32_t coord_id =
-      GenUintCastCode(ref_inst->GetSingleWordInOperand(1), &builder);
-  // If index id not yet set, binding is single descriptor, so set index to
-  // constant 0.
-  if (ref.desc_idx_id == 0) ref.desc_idx_id = builder.GetUintConstantId(0u);
-  // Get texel buffer size.
-  Instruction* size_inst =
-      builder.AddUnaryOp(GetUintId(), spv::Op::OpImageQuerySize, ref.image_id);
-  uint32_t size_id = size_inst->result_id();
   // Generate runtime initialization/bounds test code with true branch
-  // being full reference and false branch being debug output and zero
+  // being full reference and false branch being zero
   // for the referenced value.
-  Instruction* ult_inst =
-      builder.AddBinaryOp(GetBoolId(), spv::Op::OpULessThan, coord_id, size_id);
-  uint32_t error =
-      (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageSampled) == 2)
-          ? kInstErrorBuffOOBStorageTexel
-          : kInstErrorBuffOOBUniformTexel;
-  uint32_t error_id = builder.GetUintConstantId(error);
-  GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_id, stage_idx,
-               &ref, new_blocks);
+  GenCheckCode(check_id, &ref, new_blocks);
+
   // Move original block's remaining code into remainder/merge block and add
   // to new blocks
   BasicBlock* back_blk_ptr = &*new_blocks->back();
@@ -1293,59 +708,48 @@
 void InstBindlessCheckPass::InitializeInstBindlessCheck() {
   // Initialize base class
   InitializeInstrument();
-  // If runtime array length support or buffer bounds checking are enabled,
-  // create variable mappings. Length support is always enabled if descriptor
-  // init check is enabled.
-  if (desc_idx_enabled_ || buffer_bounds_enabled_ || texel_buffer_enabled_)
-    for (auto& anno : get_module()->annotations())
-      if (anno.opcode() == spv::Op::OpDecorate) {
-        if (spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
-            spv::Decoration::DescriptorSet) {
-          var2desc_set_[anno.GetSingleWordInOperand(0u)] =
-              anno.GetSingleWordInOperand(2u);
-        } else if (spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
-                   spv::Decoration::Binding) {
-          var2binding_[anno.GetSingleWordInOperand(0u)] =
-              anno.GetSingleWordInOperand(2u);
-        }
+  for (auto& anno : get_module()->annotations()) {
+    if (anno.opcode() == spv::Op::OpDecorate) {
+      if (spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
+          spv::Decoration::DescriptorSet) {
+        var2desc_set_[anno.GetSingleWordInOperand(0u)] =
+            anno.GetSingleWordInOperand(2u);
+      } else if (spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
+                 spv::Decoration::Binding) {
+        var2binding_[anno.GetSingleWordInOperand(0u)] =
+            anno.GetSingleWordInOperand(2u);
       }
+    }
+  }
 }
 
 Pass::Status InstBindlessCheckPass::ProcessImpl() {
-  // Perform bindless bounds check on each entry point function in module
+  // The memory model and linkage must always be updated for spirv-link to work
+  // correctly.
+  AddStorageBufferExt();
+  if (!get_feature_mgr()->HasExtension(kSPV_KHR_physical_storage_buffer)) {
+    context()->AddExtension("SPV_KHR_physical_storage_buffer");
+  }
+
+  context()->AddCapability(spv::Capability::PhysicalStorageBufferAddresses);
+  Instruction* memory_model = get_module()->GetMemoryModel();
+  memory_model->SetInOperand(
+      0u, {uint32_t(spv::AddressingModel::PhysicalStorageBuffer64)});
+
+  context()->AddCapability(spv::Capability::Linkage);
+
   InstProcessFunction pfn =
       [this](BasicBlock::iterator ref_inst_itr,
              UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
              std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
-        return GenDescIdxCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
-                                   new_blocks);
+        return GenDescCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
+                                new_blocks);
       };
-  bool modified = InstProcessEntryPointCallTree(pfn);
-  if (desc_init_enabled_ || buffer_bounds_enabled_) {
-    // Perform descriptor initialization and/or buffer bounds check on each
-    // entry point function in module
-    pfn = [this](BasicBlock::iterator ref_inst_itr,
-                 UptrVectorIterator<BasicBlock> ref_block_itr,
-                 uint32_t stage_idx,
-                 std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
-      return GenDescInitCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
-                                  new_blocks);
-    };
-    modified |= InstProcessEntryPointCallTree(pfn);
-  }
-  if (texel_buffer_enabled_) {
-    // Perform texel buffer bounds check on each entry point function in
-    // module. Generate after descriptor bounds and initialization checks.
-    pfn = [this](BasicBlock::iterator ref_inst_itr,
-                 UptrVectorIterator<BasicBlock> ref_block_itr,
-                 uint32_t stage_idx,
-                 std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
-      return GenTexBuffCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
-                                 new_blocks);
-    };
-    modified |= InstProcessEntryPointCallTree(pfn);
-  }
-  return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+
+  InstProcessEntryPointCallTree(pfn);
+  // This pass always changes the memory model, so that linking will work
+  // properly.
+  return Status::SuccessWithChange;
 }
 
 Pass::Status InstBindlessCheckPass::Process() {
diff --git a/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.h b/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.h
index f89af02..243cba7 100644
--- a/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.h
@@ -28,16 +28,8 @@
 // external design may change as the layer evolves.
 class InstBindlessCheckPass : public InstrumentPass {
  public:
-  InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
-                        bool desc_idx_enable, bool desc_init_enable,
-                        bool buffer_bounds_enable, bool texel_buffer_enable,
-                        bool opt_direct_reads)
-      : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless,
-                       opt_direct_reads),
-        desc_idx_enabled_(desc_idx_enable),
-        desc_init_enabled_(desc_init_enable),
-        buffer_bounds_enabled_(buffer_bounds_enable),
-        texel_buffer_enabled_(texel_buffer_enable) {}
+  InstBindlessCheckPass(uint32_t shader_id)
+      : InstrumentPass(0, shader_id, true, true) {}
 
   ~InstBindlessCheckPass() override = default;
 
@@ -47,82 +39,16 @@
   const char* name() const override { return "inst-bindless-check-pass"; }
 
  private:
-  // These functions do bindless checking instrumentation on a single
-  // instruction which references through a descriptor (ie references into an
-  // image or buffer). Refer to Vulkan API for further information on
-  // descriptors. GenDescIdxCheckCode checks that an index into a descriptor
-  // array (array of images or buffers) is in-bounds. GenDescInitCheckCode
-  // checks that the referenced descriptor has been initialized, if the
-  // SPV_EXT_descriptor_indexing extension is enabled, and initialized large
-  // enough to handle the reference, if RobustBufferAccess is disabled.
-  // GenDescInitCheckCode checks for uniform and storage buffer overrun.
-  // GenTexBuffCheckCode checks for texel buffer overrun and should be
-  // run after GenDescInitCheckCode to first make sure that the descriptor
-  // is initialized because it uses OpImageQuerySize on the descriptor.
-  //
-  // The functions are designed to be passed to
-  // InstrumentPass::InstProcessEntryPointCallTree(), which applies the
-  // function to each instruction in a module and replaces the instruction
-  // if warranted.
-  //
-  // If |ref_inst_itr| is a bindless reference, return in |new_blocks| the
-  // result of instrumenting it with validation code within its block at
-  // |ref_block_itr|.  The validation code first executes a check for the
-  // specific condition called for. If the check passes, it executes
-  // the remainder of the reference, otherwise writes a record to the debug
-  // output buffer stream including |function_idx, instruction_idx, stage_idx|
-  // and replaces the reference with the null value of the original type. The
-  // block at |ref_block_itr| can just be replaced with the blocks in
-  // |new_blocks|, which will contain at least two blocks. The last block will
-  // comprise all instructions following |ref_inst_itr|,
-  // preceded by a phi instruction.
-  //
-  // These instrumentation functions utilize GenDebugDirectRead() to read data
-  // from the debug input buffer, specifically the lengths of variable length
-  // descriptor arrays, and the initialization status of each descriptor.
-  // The format of the debug input buffer is documented in instrument.hpp.
-  //
-  // These instrumentation functions utilize GenDebugStreamWrite() to write its
-  // error records. The validation-specific part of the error record will
-  // have the format:
-  //
-  //    Validation Error Code (=kInstErrorBindlessBounds)
-  //    Descriptor Index
-  //    Descriptor Array Size
-  //
-  // The Descriptor Index is the index which has been determined to be
-  // out-of-bounds.
-  //
-  // The Descriptor Array Size is the size of the descriptor array which was
-  // indexed.
-  void GenDescIdxCheckCode(
-      BasicBlock::iterator ref_inst_itr,
-      UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
-      std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
+  void GenDescCheckCode(BasicBlock::iterator ref_inst_itr,
+                        UptrVectorIterator<BasicBlock> ref_block_itr,
+                        uint32_t stage_idx,
+                        std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
 
-  void GenDescInitCheckCode(
-      BasicBlock::iterator ref_inst_itr,
-      UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
-      std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
+  uint32_t GenDescCheckFunctionId();
 
-  void GenTexBuffCheckCode(
-      BasicBlock::iterator ref_inst_itr,
-      UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
-      std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
-
-  void SetupInputBufferIds();
-  uint32_t GenDebugReadLengthFunctionId();
-
-  // Generate instructions into |builder| to read length of runtime descriptor
-  // array |var_id| from debug input buffer and return id of value.
-  uint32_t GenDebugReadLength(uint32_t var_id, InstructionBuilder* builder);
-
-  uint32_t GenDebugReadInitFunctionId();
-  // Generate instructions into |builder| to read initialization status of
-  // descriptor array |image_id| at |index_id| from debug input buffer and
-  // return id of value.
-  uint32_t GenDebugReadInit(uint32_t image_id, uint32_t index_id,
-                            InstructionBuilder* builder);
+  uint32_t GenDescCheckCall(uint32_t inst_idx, uint32_t stage_idx,
+                            uint32_t var_id, uint32_t index_id,
+                            uint32_t byte_offset, InstructionBuilder* builder);
 
   // Analysis data for descriptor reference components, generated by
   // AnalyzeDescriptorReference. It is necessary and sufficient for further
@@ -179,8 +105,7 @@
   // writes debug error output utilizing |ref|, |error_id|, |length_id| and
   // |stage_idx|. Generate merge block for valid and invalid branches. Kill
   // original reference.
-  void GenCheckCode(uint32_t check_id, uint32_t error_id, uint32_t offset_id,
-                    uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref,
+  void GenCheckCode(uint32_t check_id, RefAnalysis* ref,
                     std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
 
   // Initialize state for instrumenting bindless checking
@@ -190,30 +115,13 @@
   // GenDescInitCheckCode to every instruction in module.
   Pass::Status ProcessImpl();
 
-  // Enable instrumentation of runtime array length checking
-  bool desc_idx_enabled_;
-
-  // Enable instrumentation of descriptor initialization checking
-  bool desc_init_enabled_;
-
-  // Enable instrumentation of uniform and storage buffer overrun checking
-  bool buffer_bounds_enabled_;
-
-  // Enable instrumentation of texel buffer overrun checking
-  bool texel_buffer_enabled_;
-
   // Mapping from variable to descriptor set
   std::unordered_map<uint32_t, uint32_t> var2desc_set_;
 
   // Mapping from variable to binding
   std::unordered_map<uint32_t, uint32_t> var2binding_;
 
-  uint32_t read_length_func_id_{0};
-  uint32_t read_init_func_id_{0};
-  uint32_t desc_set_type_id_{0};
-  uint32_t desc_set_ptr_id_{0};
-  uint32_t input_buffer_struct_id_{0};
-  uint32_t input_buffer_ptr_id_{0};
+  uint32_t check_desc_func_id_{0};
 };
 
 }  // namespace opt
diff --git a/third_party/SPIRV-Tools/source/opt/inst_buff_addr_check_pass.cpp b/third_party/SPIRV-Tools/source/opt/inst_buff_addr_check_pass.cpp
index 4954706..e6c5508 100644
--- a/third_party/SPIRV-Tools/source/opt/inst_buff_addr_check_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/inst_buff_addr_check_pass.cpp
@@ -19,24 +19,6 @@
 namespace spvtools {
 namespace opt {
 
-bool InstBuffAddrCheckPass::InstrumentFunction(Function* func,
-                                               uint32_t stage_idx,
-                                               InstProcessFunction& pfn) {
-  // The bindless instrumentation pass adds functions that use
-  // BufferDeviceAddress They should not be instrumented by this pass.
-  Instruction* func_name_inst =
-      context()->GetNames(func->DefInst().result_id()).begin()->second;
-  if (func_name_inst) {
-    static const std::string kPrefix{"inst_bindless_"};
-    std::string func_name = func_name_inst->GetOperand(1).AsString();
-    if (func_name.size() >= kPrefix.size() &&
-        func_name.compare(0, kPrefix.size(), kPrefix) == 0) {
-      return false;
-    }
-  }
-  return InstrumentPass::InstrumentFunction(func, stage_idx, pfn);
-}
-
 uint32_t InstBuffAddrCheckPass::CloneOriginalReference(
     Instruction* ref_inst, InstructionBuilder* builder) {
   // Clone original ref with new result id (if load)
@@ -76,8 +58,7 @@
 
 // TODO(greg-lunarg): Refactor with InstBindlessCheckPass::GenCheckCode() ??
 void InstBuffAddrCheckPass::GenCheckCode(
-    uint32_t check_id, uint32_t error_id, uint32_t ref_uptr_id,
-    uint32_t stage_idx, Instruction* ref_inst,
+    uint32_t check_id, Instruction* ref_inst,
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
   BasicBlock* back_blk_ptr = &*new_blocks->back();
   InstructionBuilder builder(
@@ -104,18 +85,6 @@
   // Gen invalid block
   new_blk_ptr.reset(new BasicBlock(std::move(invalid_label)));
   builder.SetInsertPoint(&*new_blk_ptr);
-  // Convert uptr from uint64 to 2 uint32
-  Instruction* lo_uptr_inst =
-      builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, ref_uptr_id);
-  Instruction* rshift_uptr_inst =
-      builder.AddBinaryOp(GetUint64Id(), spv::Op::OpShiftRightLogical,
-                          ref_uptr_id, builder.GetUintConstantId(32));
-  Instruction* hi_uptr_inst = builder.AddUnaryOp(
-      GetUintId(), spv::Op::OpUConvert, rshift_uptr_inst->result_id());
-  GenDebugStreamWrite(
-      uid2offset_[ref_inst->unique_id()], stage_idx,
-      {error_id, lo_uptr_inst->result_id(), hi_uptr_inst->result_id()},
-      &builder);
   // Gen zero for invalid load. If pointer type, need to convert uint64
   // zero to pointer; cannot create ConstantNull of pointer type.
   uint32_t null_id = 0;
@@ -150,48 +119,13 @@
   context()->KillInst(ref_inst);
 }
 
-uint32_t InstBuffAddrCheckPass::GetTypeAlignment(uint32_t type_id) {
-  Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
-  switch (type_inst->opcode()) {
-    case spv::Op::OpTypeFloat:
-    case spv::Op::OpTypeInt:
-    case spv::Op::OpTypeVector:
-      return GetTypeLength(type_id);
-    case spv::Op::OpTypeMatrix:
-      return GetTypeAlignment(type_inst->GetSingleWordInOperand(0));
-    case spv::Op::OpTypeArray:
-    case spv::Op::OpTypeRuntimeArray:
-      return GetTypeAlignment(type_inst->GetSingleWordInOperand(0));
-    case spv::Op::OpTypeStruct: {
-      uint32_t max = 0;
-      type_inst->ForEachInId([&max, this](const uint32_t* iid) {
-        uint32_t alignment = GetTypeAlignment(*iid);
-        max = (alignment > max) ? alignment : max;
-      });
-      return max;
-    }
-    case spv::Op::OpTypePointer:
-      assert(spv::StorageClass(type_inst->GetSingleWordInOperand(0)) ==
-                 spv::StorageClass::PhysicalStorageBufferEXT &&
-             "unexpected pointer type");
-      return 8u;
-    default:
-      assert(false && "unexpected type");
-      return 0;
-  }
-}
-
 uint32_t InstBuffAddrCheckPass::GetTypeLength(uint32_t type_id) {
   Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
   switch (type_inst->opcode()) {
     case spv::Op::OpTypeFloat:
     case spv::Op::OpTypeInt:
       return type_inst->GetSingleWordInOperand(0) / 8u;
-    case spv::Op::OpTypeVector: {
-      uint32_t raw_cnt = type_inst->GetSingleWordInOperand(1);
-      uint32_t adj_cnt = (raw_cnt == 3u) ? 4u : raw_cnt;
-      return adj_cnt * GetTypeLength(type_inst->GetSingleWordInOperand(0));
-    }
+    case spv::Op::OpTypeVector:
     case spv::Op::OpTypeMatrix:
       return type_inst->GetSingleWordInOperand(1) *
              GetTypeLength(type_inst->GetSingleWordInOperand(0));
@@ -207,18 +141,19 @@
       return cnt * GetTypeLength(type_inst->GetSingleWordInOperand(0));
     }
     case spv::Op::OpTypeStruct: {
-      uint32_t len = 0;
-      type_inst->ForEachInId([&len, this](const uint32_t* iid) {
-        // Align struct length
-        uint32_t alignment = GetTypeAlignment(*iid);
-        uint32_t mod = len % alignment;
-        uint32_t diff = (mod != 0) ? alignment - mod : 0;
-        len += diff;
-        // Increment struct length by component length
-        uint32_t comp_len = GetTypeLength(*iid);
-        len += comp_len;
+      // Figure out the location of the last byte of the last member of the
+      // structure.
+      uint32_t last_offset = 0, last_len = 0;
+
+      get_decoration_mgr()->ForEachDecoration(
+          type_id, uint32_t(spv::Decoration::Offset),
+          [&last_offset](const Instruction& deco_inst) {
+            last_offset = deco_inst.GetSingleWordInOperand(3);
+          });
+      type_inst->ForEachInId([&last_len, this](const uint32_t* iid) {
+        last_len = GetTypeLength(*iid);
       });
-      return len;
+      return last_offset + last_len;
     }
     case spv::Op::OpTypeRuntimeArray:
     default:
@@ -238,201 +173,86 @@
   (*input_func)->AddParameter(std::move(param_inst));
 }
 
+// This is a stub function for use with Import linkage
+// clang-format off
+// GLSL:
+//bool inst_bindless_search_and_test(const uint shader_id, const uint inst_num, const uvec4 stage_info,
+//				     const uint64 ref_ptr, const uint length) {
+//}
+// clang-format on
 uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() {
-  if (search_test_func_id_ == 0) {
-    // Generate function "bool search_and_test(uint64_t ref_ptr, uint32_t len)"
-    // which searches input buffer for buffer which most likely contains the
-    // pointer value |ref_ptr| and verifies that the entire reference of
-    // length |len| bytes is contained in the buffer.
-    search_test_func_id_ = TakeNextId();
-    analysis::TypeManager* type_mgr = context()->get_type_mgr();
-    std::vector<const analysis::Type*> param_types = {
-        type_mgr->GetType(GetUint64Id()), type_mgr->GetType(GetUintId())};
-    analysis::Function func_ty(type_mgr->GetType(GetBoolId()), param_types);
-    analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
-    std::unique_ptr<Instruction> func_inst(
-        new Instruction(get_module()->context(), spv::Op::OpFunction,
-                        GetBoolId(), search_test_func_id_,
-                        {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
-                          {uint32_t(spv::FunctionControlMask::MaskNone)}},
-                         {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
-                          {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
-    get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
-    std::unique_ptr<Function> input_func =
-        MakeUnique<Function>(std::move(func_inst));
-    std::vector<uint32_t> param_vec;
-    // Add ref_ptr and length parameters
-    AddParam(GetUint64Id(), &param_vec, &input_func);
-    AddParam(GetUintId(), &param_vec, &input_func);
-    // Empty first block.
-    uint32_t first_blk_id = TakeNextId();
-    std::unique_ptr<Instruction> first_blk_label(NewLabel(first_blk_id));
-    std::unique_ptr<BasicBlock> first_blk_ptr =
-        MakeUnique<BasicBlock>(std::move(first_blk_label));
-    InstructionBuilder builder(
-        context(), &*first_blk_ptr,
-        IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
-    uint32_t hdr_blk_id = TakeNextId();
-    // Branch to search loop header
-    std::unique_ptr<Instruction> hdr_blk_label(NewLabel(hdr_blk_id));
-    (void)builder.AddBranch(hdr_blk_id);
-    input_func->AddBasicBlock(std::move(first_blk_ptr));
-    // Linear search loop header block
-    // TODO(greg-lunarg): Implement binary search
-    std::unique_ptr<BasicBlock> hdr_blk_ptr =
-        MakeUnique<BasicBlock>(std::move(hdr_blk_label));
-    builder.SetInsertPoint(&*hdr_blk_ptr);
-    // Phi for search index. Starts with 1.
-    uint32_t cont_blk_id = TakeNextId();
-    std::unique_ptr<Instruction> cont_blk_label(NewLabel(cont_blk_id));
-    // Deal with def-use cycle caused by search loop index computation.
-    // Create Add and Phi instructions first, then do Def analysis on Add.
-    // Add Phi and Add instructions and do Use analysis later.
-    uint32_t idx_phi_id = TakeNextId();
-    uint32_t idx_inc_id = TakeNextId();
-    std::unique_ptr<Instruction> idx_inc_inst(new Instruction(
-        context(), spv::Op::OpIAdd, GetUintId(), idx_inc_id,
-        {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {idx_phi_id}},
-         {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
-          {builder.GetUintConstantId(1u)}}}));
-    std::unique_ptr<Instruction> idx_phi_inst(new Instruction(
-        context(), spv::Op::OpPhi, GetUintId(), idx_phi_id,
-        {{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
-          {builder.GetUintConstantId(1u)}},
-         {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {first_blk_id}},
-         {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {idx_inc_id}},
-         {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cont_blk_id}}}));
-    get_def_use_mgr()->AnalyzeInstDef(&*idx_inc_inst);
-    // Add (previously created) search index phi
-    (void)builder.AddInstruction(std::move(idx_phi_inst));
-    // LoopMerge
-    uint32_t bound_test_blk_id = TakeNextId();
-    std::unique_ptr<Instruction> bound_test_blk_label(
-        NewLabel(bound_test_blk_id));
-    (void)builder.AddLoopMerge(bound_test_blk_id, cont_blk_id,
-                               uint32_t(spv::LoopControlMask::MaskNone));
-    // Branch to continue/work block
-    (void)builder.AddBranch(cont_blk_id);
-    input_func->AddBasicBlock(std::move(hdr_blk_ptr));
-    // Continue/Work Block. Read next buffer pointer and break if greater
-    // than ref_ptr arg.
-    std::unique_ptr<BasicBlock> cont_blk_ptr =
-        MakeUnique<BasicBlock>(std::move(cont_blk_label));
-    builder.SetInsertPoint(&*cont_blk_ptr);
-    // Add (previously created) search index increment now.
-    (void)builder.AddInstruction(std::move(idx_inc_inst));
-    // Load next buffer address from debug input buffer
-    uint32_t ibuf_id = GetInputBufferId();
-    uint32_t ibuf_ptr_id = GetInputBufferPtrId();
-    Instruction* uptr_ac_inst = builder.AddTernaryOp(
-        ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id,
-        builder.GetUintConstantId(kDebugInputDataOffset), idx_inc_id);
-    uint32_t ibuf_type_id = GetInputBufferTypeId();
-    Instruction* uptr_load_inst = builder.AddUnaryOp(
-        ibuf_type_id, spv::Op::OpLoad, uptr_ac_inst->result_id());
-    // If loaded address greater than ref_ptr arg, break, else branch back to
-    // loop header
-    Instruction* uptr_test_inst =
-        builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThan,
-                            uptr_load_inst->result_id(), param_vec[0]);
-    (void)builder.AddConditionalBranch(
-        uptr_test_inst->result_id(), bound_test_blk_id, hdr_blk_id, kInvalidId,
-        uint32_t(spv::SelectionControlMask::MaskNone));
-    input_func->AddBasicBlock(std::move(cont_blk_ptr));
-    // Bounds test block. Read length of selected buffer and test that
-    // all len arg bytes are in buffer.
-    std::unique_ptr<BasicBlock> bound_test_blk_ptr =
-        MakeUnique<BasicBlock>(std::move(bound_test_blk_label));
-    builder.SetInsertPoint(&*bound_test_blk_ptr);
-    // Decrement index to point to previous/candidate buffer address
-    Instruction* cand_idx_inst =
-        builder.AddBinaryOp(GetUintId(), spv::Op::OpISub, idx_inc_id,
-                            builder.GetUintConstantId(1u));
-    // Load candidate buffer address
-    Instruction* cand_ac_inst =
-        builder.AddTernaryOp(ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id,
-                             builder.GetUintConstantId(kDebugInputDataOffset),
-                             cand_idx_inst->result_id());
-    Instruction* cand_load_inst = builder.AddUnaryOp(
-        ibuf_type_id, spv::Op::OpLoad, cand_ac_inst->result_id());
-    // Compute offset of ref_ptr from candidate buffer address
-    Instruction* offset_inst =
-        builder.AddBinaryOp(ibuf_type_id, spv::Op::OpISub, param_vec[0],
-                            cand_load_inst->result_id());
-    // Convert ref length to uint64
-    Instruction* ref_len_64_inst =
-        builder.AddUnaryOp(ibuf_type_id, spv::Op::OpUConvert, param_vec[1]);
-    // Add ref length to ref offset to compute end of reference
-    Instruction* ref_end_inst = builder.AddBinaryOp(
-        ibuf_type_id, spv::Op::OpIAdd, offset_inst->result_id(),
-        ref_len_64_inst->result_id());
-    // Load starting index of lengths in input buffer and convert to uint32
-    Instruction* len_start_ac_inst =
-        builder.AddTernaryOp(ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id,
-                             builder.GetUintConstantId(kDebugInputDataOffset),
-                             builder.GetUintConstantId(0u));
-    Instruction* len_start_load_inst = builder.AddUnaryOp(
-        ibuf_type_id, spv::Op::OpLoad, len_start_ac_inst->result_id());
-    Instruction* len_start_32_inst = builder.AddUnaryOp(
-        GetUintId(), spv::Op::OpUConvert, len_start_load_inst->result_id());
-    // Decrement search index to get candidate buffer length index
-    Instruction* cand_len_idx_inst = builder.AddBinaryOp(
-        GetUintId(), spv::Op::OpISub, cand_idx_inst->result_id(),
-        builder.GetUintConstantId(1u));
-    // Add candidate length index to start index
-    Instruction* len_idx_inst = builder.AddBinaryOp(
-        GetUintId(), spv::Op::OpIAdd, cand_len_idx_inst->result_id(),
-        len_start_32_inst->result_id());
-    // Load candidate buffer length
-    Instruction* len_ac_inst =
-        builder.AddTernaryOp(ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id,
-                             builder.GetUintConstantId(kDebugInputDataOffset),
-                             len_idx_inst->result_id());
-    Instruction* len_load_inst = builder.AddUnaryOp(
-        ibuf_type_id, spv::Op::OpLoad, len_ac_inst->result_id());
-    // Test if reference end within candidate buffer length
-    Instruction* len_test_inst = builder.AddBinaryOp(
-        GetBoolId(), spv::Op::OpULessThanEqual, ref_end_inst->result_id(),
-        len_load_inst->result_id());
-    // Return test result
-    (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
-                             len_test_inst->result_id());
-    // Close block
-    input_func->AddBasicBlock(std::move(bound_test_blk_ptr));
-    // Close function and add function to module
-    std::unique_ptr<Instruction> func_end_inst(new Instruction(
-        get_module()->context(), spv::Op::OpFunctionEnd, 0, 0, {}));
-    get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
-    input_func->SetFunctionEnd(std::move(func_end_inst));
-    context()->AddFunction(std::move(input_func));
-    context()->AddDebug2Inst(
-        NewGlobalName(search_test_func_id_, "search_and_test"));
+  enum {
+    kShaderId = 0,
+    kInstructionIndex = 1,
+    kStageInfo = 2,
+    kRefPtr = 3,
+    kLength = 4,
+    kNumArgs
+  };
+  if (search_test_func_id_ != 0) {
+    return search_test_func_id_;
   }
+  // Generate function "bool search_and_test(uint64_t ref_ptr, uint32_t len)"
+  // which searches input buffer for buffer which most likely contains the
+  // pointer value |ref_ptr| and verifies that the entire reference of
+  // length |len| bytes is contained in the buffer.
+  analysis::TypeManager* type_mgr = context()->get_type_mgr();
+  const analysis::Integer* uint_type = GetInteger(32, false);
+  const analysis::Vector v4uint(uint_type, 4);
+  const analysis::Type* v4uint_type = type_mgr->GetRegisteredType(&v4uint);
+
+  std::vector<const analysis::Type*> param_types = {
+      uint_type, uint_type, v4uint_type, type_mgr->GetType(GetUint64Id()),
+      uint_type};
+
+  const std::string func_name{"inst_buff_addr_search_and_test"};
+  const uint32_t func_id = TakeNextId();
+  std::unique_ptr<Function> func =
+      StartFunction(func_id, type_mgr->GetBoolType(), param_types);
+  func->SetFunctionEnd(EndFunction());
+  context()->AddFunctionDeclaration(std::move(func));
+  context()->AddDebug2Inst(NewName(func_id, func_name));
+
+  std::vector<Operand> operands{
+      {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {func_id}},
+      {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
+       {uint32_t(spv::Decoration::LinkageAttributes)}},
+      {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_STRING,
+       utils::MakeVector(func_name.c_str())},
+      {spv_operand_type_t::SPV_OPERAND_TYPE_LINKAGE_TYPE,
+       {uint32_t(spv::LinkageType::Import)}},
+  };
+  get_decoration_mgr()->AddDecoration(spv::Op::OpDecorate, operands);
+
+  search_test_func_id_ = func_id;
   return search_test_func_id_;
 }
 
 uint32_t InstBuffAddrCheckPass::GenSearchAndTest(Instruction* ref_inst,
                                                  InstructionBuilder* builder,
-                                                 uint32_t* ref_uptr_id) {
+                                                 uint32_t* ref_uptr_id,
+                                                 uint32_t stage_idx) {
   // Enable Int64 if necessary
-  context()->AddCapability(spv::Capability::Int64);
   // Convert reference pointer to uint64
-  uint32_t ref_ptr_id = ref_inst->GetSingleWordInOperand(0);
+  const uint32_t ref_ptr_id = ref_inst->GetSingleWordInOperand(0);
   Instruction* ref_uptr_inst =
       builder->AddUnaryOp(GetUint64Id(), spv::Op::OpConvertPtrToU, ref_ptr_id);
   *ref_uptr_id = ref_uptr_inst->result_id();
   // Compute reference length in bytes
   analysis::DefUseManager* du_mgr = get_def_use_mgr();
   Instruction* ref_ptr_inst = du_mgr->GetDef(ref_ptr_id);
-  uint32_t ref_ptr_ty_id = ref_ptr_inst->type_id();
+  const uint32_t ref_ptr_ty_id = ref_ptr_inst->type_id();
   Instruction* ref_ptr_ty_inst = du_mgr->GetDef(ref_ptr_ty_id);
-  uint32_t ref_len = GetTypeLength(ref_ptr_ty_inst->GetSingleWordInOperand(1));
-  uint32_t ref_len_id = builder->GetUintConstantId(ref_len);
+  const uint32_t ref_len =
+      GetTypeLength(ref_ptr_ty_inst->GetSingleWordInOperand(1));
   // Gen call to search and test function
-  Instruction* call_inst = builder->AddFunctionCall(
-      GetBoolId(), GetSearchAndTestFuncId(), {*ref_uptr_id, ref_len_id});
-  uint32_t retval = call_inst->result_id();
-  return retval;
+  const uint32_t func_id = GetSearchAndTestFuncId();
+  const std::vector<uint32_t> args = {
+      builder->GetUintConstantId(shader_id_),
+      builder->GetUintConstantId(ref_inst->unique_id()),
+      GenStageInfo(stage_idx, builder), *ref_uptr_id,
+      builder->GetUintConstantId(ref_len)};
+  return GenReadFunctionCall(GetBoolId(), func_id, args, builder);
 }
 
 void InstBuffAddrCheckPass::GenBuffAddrCheckCode(
@@ -450,16 +270,16 @@
       context(), &*new_blk_ptr,
       IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
   new_blocks->push_back(std::move(new_blk_ptr));
-  uint32_t error_id = builder.GetUintConstantId(kInstErrorBuffAddrUnallocRef);
   // Generate code to do search and test if all bytes of reference
   // are within a listed buffer. Return reference pointer converted to uint64.
   uint32_t ref_uptr_id;
-  uint32_t valid_id = GenSearchAndTest(ref_inst, &builder, &ref_uptr_id);
+  uint32_t valid_id =
+      GenSearchAndTest(ref_inst, &builder, &ref_uptr_id, stage_idx);
   // Generate test of search results with true branch
   // being full reference and false branch being debug output and zero
   // for the referenced value.
-  GenCheckCode(valid_id, error_id, ref_uptr_id, stage_idx, ref_inst,
-               new_blocks);
+  GenCheckCode(valid_id, ref_inst, new_blocks);
+
   // Move original block's remaining code into remainder/merge block and add
   // to new blocks
   BasicBlock* back_blk_ptr = &*new_blocks->back();
@@ -474,6 +294,20 @@
 }
 
 Pass::Status InstBuffAddrCheckPass::ProcessImpl() {
+  // The memory model and linkage must always be updated for spirv-link to work
+  // correctly.
+  AddStorageBufferExt();
+  if (!get_feature_mgr()->HasExtension(kSPV_KHR_physical_storage_buffer)) {
+    context()->AddExtension("SPV_KHR_physical_storage_buffer");
+  }
+
+  context()->AddCapability(spv::Capability::PhysicalStorageBufferAddresses);
+  Instruction* memory_model = get_module()->GetMemoryModel();
+  memory_model->SetInOperand(
+      0u, {uint32_t(spv::AddressingModel::PhysicalStorageBuffer64)});
+
+  context()->AddCapability(spv::Capability::Int64);
+  context()->AddCapability(spv::Capability::Linkage);
   // Perform bindless bounds check on each entry point function in module
   InstProcessFunction pfn =
       [this](BasicBlock::iterator ref_inst_itr,
@@ -482,14 +316,13 @@
         return GenBuffAddrCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
                                     new_blocks);
       };
-  bool modified = InstProcessEntryPointCallTree(pfn);
-  return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+  InstProcessEntryPointCallTree(pfn);
+  // This pass always changes the memory model, so that linking will work
+  // properly.
+  return Status::SuccessWithChange;
 }
 
 Pass::Status InstBuffAddrCheckPass::Process() {
-  if (!get_feature_mgr()->HasCapability(
-          spv::Capability::PhysicalStorageBufferAddressesEXT))
-    return Status::SuccessWithoutChange;
   InitInstBuffAddrCheck();
   return ProcessImpl();
 }
diff --git a/third_party/SPIRV-Tools/source/opt/inst_buff_addr_check_pass.h b/third_party/SPIRV-Tools/source/opt/inst_buff_addr_check_pass.h
index 2ec212b..f07f98a 100644
--- a/third_party/SPIRV-Tools/source/opt/inst_buff_addr_check_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/inst_buff_addr_check_pass.h
@@ -29,10 +29,10 @@
 class InstBuffAddrCheckPass : public InstrumentPass {
  public:
   // For test harness only
-  InstBuffAddrCheckPass() : InstrumentPass(7, 23, kInstValidationIdBuffAddr) {}
+  InstBuffAddrCheckPass() : InstrumentPass(0, 23, false, true) {}
   // For all other interfaces
-  InstBuffAddrCheckPass(uint32_t desc_set, uint32_t shader_id)
-      : InstrumentPass(desc_set, shader_id, kInstValidationIdBuffAddr) {}
+  InstBuffAddrCheckPass(uint32_t shader_id)
+      : InstrumentPass(0, shader_id, false, true) {}
 
   ~InstBuffAddrCheckPass() override = default;
 
@@ -41,14 +41,7 @@
 
   const char* name() const override { return "inst-buff-addr-check-pass"; }
 
-  bool InstrumentFunction(Function* func, uint32_t stage_idx,
-                          InstProcessFunction& pfn) override;
-
  private:
-  // Return byte alignment of type |type_id|. Must be int, float, vector,
-  // matrix, struct, array or physical pointer. Uses std430 alignment.
-  uint32_t GetTypeAlignment(uint32_t type_id);
-
   // Return byte length of type |type_id|. Must be int, float, vector, matrix,
   // struct, array or physical pointer. Uses std430 alignment and sizes.
   uint32_t GetTypeLength(uint32_t type_id);
@@ -65,7 +58,7 @@
   // are within the buffer. Returns id of boolean value which is true if
   // search and test is successful, false otherwise.
   uint32_t GenSearchAndTest(Instruction* ref_inst, InstructionBuilder* builder,
-                            uint32_t* ref_uptr_id);
+                            uint32_t* ref_uptr_id, uint32_t stage_idx);
 
   // This function does checking instrumentation on a single
   // instruction which references through a physical storage buffer address.
@@ -118,8 +111,7 @@
   // writes debug error output utilizing |ref_inst|, |error_id| and
   // |stage_idx|. Generate merge block for valid and invalid reference blocks.
   // Kill original reference.
-  void GenCheckCode(uint32_t check_id, uint32_t error_id, uint32_t length_id,
-                    uint32_t stage_idx, Instruction* ref_inst,
+  void GenCheckCode(uint32_t check_id, Instruction* ref_inst,
                     std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
 
   // Initialize state for instrumenting physical buffer address checking
diff --git a/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.cpp b/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.cpp
index 4f97277..abd25e9 100644
--- a/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.cpp
@@ -16,6 +16,7 @@
 
 #include "inst_debug_printf_pass.h"
 
+#include "source/spirv_constant.h"
 #include "source/util/string_utils.h"
 #include "spirv/unified1/NonSemanticDebugPrintf.h"
 
@@ -137,7 +138,7 @@
 }
 
 void InstDebugPrintfPass::GenOutputCode(
-    Instruction* printf_inst, uint32_t stage_idx,
+    Instruction* printf_inst,
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
   BasicBlock* back_blk_ptr = &*new_blocks->back();
   InstructionBuilder builder(
@@ -165,14 +166,16 @@
           GenOutputValues(opnd_inst, &val_ids, &builder);
         }
       });
-  GenDebugStreamWrite(uid2offset_[printf_inst->unique_id()], stage_idx, val_ids,
-                      &builder);
+  GenDebugStreamWrite(
+      builder.GetUintConstantId(shader_id_),
+      builder.GetUintConstantId(uid2offset_[printf_inst->unique_id()]), val_ids,
+      &builder);
   context()->KillInst(printf_inst);
 }
 
 void InstDebugPrintfPass::GenDebugPrintfCode(
     BasicBlock::iterator ref_inst_itr,
-    UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
+    UptrVectorIterator<BasicBlock> ref_block_itr,
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
   // If not DebugPrintf OpExtInst, return.
   Instruction* printf_inst = &*ref_inst_itr;
@@ -188,7 +191,7 @@
   MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
   new_blocks->push_back(std::move(new_blk_ptr));
   // Generate instructions to output printf args to printf buffer
-  GenOutputCode(printf_inst, stage_idx, new_blocks);
+  GenOutputCode(printf_inst, new_blocks);
   // Caller expects at least two blocks with last block containing remaining
   // code, so end block after instrumentation, create remainder block, and
   // branch to it
@@ -208,19 +211,243 @@
   new_blocks->push_back(std::move(new_blk_ptr));
 }
 
+// Return id for output buffer
+uint32_t InstDebugPrintfPass::GetOutputBufferId() {
+  if (output_buffer_id_ == 0) {
+    // If not created yet, create one
+    analysis::DecorationManager* deco_mgr = get_decoration_mgr();
+    analysis::TypeManager* type_mgr = context()->get_type_mgr();
+    analysis::RuntimeArray* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
+    analysis::Integer* reg_uint_ty = GetInteger(32, false);
+    analysis::Type* reg_buf_ty =
+        GetStruct({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty});
+    uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
+    // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
+    // must be a block, and will therefore be decorated with Block. Therefore
+    // the undecorated type returned here will not be pre-existing and can
+    // safely be decorated. Since this type is now decorated, it is out of
+    // sync with the TypeManager and therefore the TypeManager must be
+    // invalidated after this pass.
+    assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
+           "used struct type returned");
+    deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block));
+    deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset,
+                                  uint32_t(spv::Decoration::Offset), 0);
+    deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
+                                  uint32_t(spv::Decoration::Offset), 4);
+    deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
+                                  uint32_t(spv::Decoration::Offset), 8);
+    uint32_t obufTyPtrId_ =
+        type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer);
+    output_buffer_id_ = TakeNextId();
+    std::unique_ptr<Instruction> newVarOp(new Instruction(
+        context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_,
+        {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
+          {uint32_t(spv::StorageClass::StorageBuffer)}}}));
+    context()->AddGlobalValue(std::move(newVarOp));
+    context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer"));
+    context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags"));
+    context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count"));
+    context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data"));
+    context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer"));
+    deco_mgr->AddDecorationVal(
+        output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
+    deco_mgr->AddDecorationVal(output_buffer_id_,
+                               uint32_t(spv::Decoration::Binding),
+                               GetOutputBufferBinding());
+    AddStorageBufferExt();
+    if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
+      // Add the new buffer to all entry points.
+      for (auto& entry : get_module()->entry_points()) {
+        entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}});
+        context()->AnalyzeUses(&entry);
+      }
+    }
+  }
+  return output_buffer_id_;
+}
+
+uint32_t InstDebugPrintfPass::GetOutputBufferPtrId() {
+  if (output_buffer_ptr_id_ == 0) {
+    output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
+        GetUintId(), spv::StorageClass::StorageBuffer);
+  }
+  return output_buffer_ptr_id_;
+}
+
+uint32_t InstDebugPrintfPass::GetOutputBufferBinding() {
+  return kDebugOutputPrintfStream;
+}
+
+void InstDebugPrintfPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
+                                                  uint32_t field_offset,
+                                                  uint32_t field_value_id,
+                                                  InstructionBuilder* builder) {
+  // Cast value to 32-bit unsigned if necessary
+  uint32_t val_id = GenUintCastCode(field_value_id, builder);
+  // Store value
+  Instruction* data_idx_inst = builder->AddIAdd(
+      GetUintId(), base_offset_id, builder->GetUintConstantId(field_offset));
+  uint32_t buf_id = GetOutputBufferId();
+  uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
+  Instruction* achain_inst = builder->AddAccessChain(
+      buf_uint_ptr_id, buf_id,
+      {builder->GetUintConstantId(kDebugOutputDataOffset),
+       data_idx_inst->result_id()});
+  (void)builder->AddStore(achain_inst->result_id(), val_id);
+}
+
+uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) {
+  enum {
+    kShaderId = 0,
+    kInstructionIndex = 1,
+    kFirstParam = 2,
+  };
+  // Total param count is common params plus validation-specific
+  // params
+  if (param2output_func_id_[param_cnt] == 0) {
+    // Create function
+    param2output_func_id_[param_cnt] = TakeNextId();
+    analysis::TypeManager* type_mgr = context()->get_type_mgr();
+
+    const analysis::Type* uint_type = GetInteger(32, false);
+
+    std::vector<const analysis::Type*> param_types(kFirstParam + param_cnt,
+                                                   uint_type);
+    std::unique_ptr<Function> output_func = StartFunction(
+        param2output_func_id_[param_cnt], type_mgr->GetVoidType(), param_types);
+
+    std::vector<uint32_t> param_ids = AddParameters(*output_func, param_types);
+
+    // Create first block
+    auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
+
+    InstructionBuilder builder(
+        context(), &*new_blk_ptr,
+        IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+    // Gen test if debug output buffer size will not be exceeded.
+    const uint32_t first_param_offset = kInstCommonOutInstructionIdx + 1;
+    const uint32_t obuf_record_sz = first_param_offset + param_cnt;
+    const uint32_t buf_id = GetOutputBufferId();
+    const uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
+    Instruction* obuf_curr_sz_ac_inst = builder.AddAccessChain(
+        buf_uint_ptr_id, buf_id,
+        {builder.GetUintConstantId(kDebugOutputSizeOffset)});
+    // Fetch the current debug buffer written size atomically, adding the
+    // size of the record to be written.
+    uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
+    uint32_t mask_none_id =
+        builder.GetUintConstantId(uint32_t(spv::MemoryAccessMask::MaskNone));
+    uint32_t scope_invok_id =
+        builder.GetUintConstantId(uint32_t(spv::Scope::Invocation));
+    Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
+        GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
+        scope_invok_id, mask_none_id, obuf_record_sz_id);
+    uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
+    // Compute new written size
+    Instruction* obuf_new_sz_inst =
+        builder.AddIAdd(GetUintId(), obuf_curr_sz_id,
+                        builder.GetUintConstantId(obuf_record_sz));
+    // Fetch the data bound
+    Instruction* obuf_bnd_inst =
+        builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength,
+                               GetOutputBufferId(), kDebugOutputDataOffset);
+    // Test that new written size is less than or equal to debug output
+    // data bound
+    Instruction* obuf_safe_inst = builder.AddBinaryOp(
+        GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(),
+        obuf_bnd_inst->result_id());
+    uint32_t merge_blk_id = TakeNextId();
+    uint32_t write_blk_id = TakeNextId();
+    std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
+    std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
+    (void)builder.AddConditionalBranch(
+        obuf_safe_inst->result_id(), write_blk_id, merge_blk_id, merge_blk_id,
+        uint32_t(spv::SelectionControlMask::MaskNone));
+    // Close safety test block and gen write block
+    output_func->AddBasicBlock(std::move(new_blk_ptr));
+    new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
+    builder.SetInsertPoint(&*new_blk_ptr);
+    // Generate common and stage-specific debug record members
+    GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutSize,
+                            builder.GetUintConstantId(obuf_record_sz),
+                            &builder);
+    // Store Shader Id
+    GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutShaderId,
+                            param_ids[kShaderId], &builder);
+    // Store Instruction Idx
+    GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutInstructionIdx,
+                            param_ids[kInstructionIndex], &builder);
+    // Gen writes of validation specific data
+    for (uint32_t i = 0; i < param_cnt; ++i) {
+      GenDebugOutputFieldCode(obuf_curr_sz_id, first_param_offset + i,
+                              param_ids[kFirstParam + i], &builder);
+    }
+    // Close write block and gen merge block
+    (void)builder.AddBranch(merge_blk_id);
+    output_func->AddBasicBlock(std::move(new_blk_ptr));
+    new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
+    builder.SetInsertPoint(&*new_blk_ptr);
+    // Close merge block and function and add function to module
+    (void)builder.AddNullaryOp(0, spv::Op::OpReturn);
+
+    output_func->AddBasicBlock(std::move(new_blk_ptr));
+    output_func->SetFunctionEnd(EndFunction());
+    context()->AddFunction(std::move(output_func));
+
+    std::string name("stream_write_");
+    name += std::to_string(param_cnt);
+
+    context()->AddDebug2Inst(
+        NewGlobalName(param2output_func_id_[param_cnt], name));
+  }
+  return param2output_func_id_[param_cnt];
+}
+
+void InstDebugPrintfPass::GenDebugStreamWrite(
+    uint32_t shader_id, uint32_t instruction_idx_id,
+    const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
+  // Call debug output function. Pass func_idx, instruction_idx and
+  // validation ids as args.
+  uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
+  std::vector<uint32_t> args = {shader_id, instruction_idx_id};
+  (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
+  (void)builder->AddFunctionCall(GetVoidId(),
+                                 GetStreamWriteFunctionId(val_id_cnt), args);
+}
+
+std::unique_ptr<Instruction> InstDebugPrintfPass::NewGlobalName(
+    uint32_t id, const std::string& name_str) {
+  std::string prefixed_name{"inst_printf_"};
+  prefixed_name += name_str;
+  return NewName(id, prefixed_name);
+}
+
+std::unique_ptr<Instruction> InstDebugPrintfPass::NewMemberName(
+    uint32_t id, uint32_t member_index, const std::string& name_str) {
+  return MakeUnique<Instruction>(
+      context(), spv::Op::OpMemberName, 0, 0,
+      std::initializer_list<Operand>{
+          {SPV_OPERAND_TYPE_ID, {id}},
+          {SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}},
+          {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}});
+}
+
 void InstDebugPrintfPass::InitializeInstDebugPrintf() {
   // Initialize base class
   InitializeInstrument();
+  output_buffer_id_ = 0;
+  output_buffer_ptr_id_ = 0;
 }
 
 Pass::Status InstDebugPrintfPass::ProcessImpl() {
   // Perform printf instrumentation on each entry point function in module
   InstProcessFunction pfn =
       [this](BasicBlock::iterator ref_inst_itr,
-             UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
+             UptrVectorIterator<BasicBlock> ref_block_itr,
+             [[maybe_unused]] uint32_t stage_idx,
              std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
-        return GenDebugPrintfCode(ref_inst_itr, ref_block_itr, stage_idx,
-                                  new_blocks);
+        return GenDebugPrintfCode(ref_inst_itr, ref_block_itr, new_blocks);
       };
   (void)InstProcessEntryPointCallTree(pfn);
   // Remove DebugPrintf OpExtInstImport instruction
@@ -239,15 +466,7 @@
     }
   }
   if (!non_sem_set_seen) {
-    for (auto c_itr = context()->module()->extension_begin();
-         c_itr != context()->module()->extension_end(); ++c_itr) {
-      const std::string ext_name = c_itr->GetInOperand(0).AsString();
-      if (ext_name == "SPV_KHR_non_semantic_info") {
-        context()->KillInst(&*c_itr);
-        break;
-      }
-    }
-    context()->get_feature_mgr()->RemoveExtension(kSPV_KHR_non_semantic_info);
+    context()->RemoveExtension(kSPV_KHR_non_semantic_info);
   }
   return Status::SuccessWithChange;
 }
diff --git a/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.h b/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.h
index 70b0a72..5688d38 100644
--- a/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.h
@@ -28,10 +28,10 @@
 class InstDebugPrintfPass : public InstrumentPass {
  public:
   // For test harness only
-  InstDebugPrintfPass() : InstrumentPass(7, 23, kInstValidationIdDebugPrintf) {}
+  InstDebugPrintfPass() : InstrumentPass(7, 23, false, false) {}
   // For all other interfaces
   InstDebugPrintfPass(uint32_t desc_set, uint32_t shader_id)
-      : InstrumentPass(desc_set, shader_id, kInstValidationIdDebugPrintf) {}
+      : InstrumentPass(desc_set, shader_id, false, false) {}
 
   ~InstDebugPrintfPass() override = default;
 
@@ -41,12 +41,92 @@
   const char* name() const override { return "inst-printf-pass"; }
 
  private:
+  // Gen code into |builder| to write |field_value_id| into debug output
+  // buffer at |base_offset_id| + |field_offset|.
+  void GenDebugOutputFieldCode(uint32_t base_offset_id, uint32_t field_offset,
+                               uint32_t field_value_id,
+                               InstructionBuilder* builder);
+
+  // Generate instructions in |builder| which will atomically fetch and
+  // increment the size of the debug output buffer stream of the current
+  // validation and write a record to the end of the stream, if enough space
+  // in the buffer remains. The record will contain the index of the function
+  // and instruction within that function |func_idx, instruction_idx| which
+  // generated the record. Finally, the record will contain validation-specific
+  // data contained in |validation_ids| which will identify the validation
+  // error as well as the values involved in the error.
+  //
+  // The output buffer binding written to by the code generated by the function
+  // is determined by the validation id specified when each specific
+  // instrumentation pass is created.
+  //
+  // The output buffer is a sequence of 32-bit values with the following
+  // format (where all elements are unsigned 32-bit unless otherwise noted):
+  //
+  //     Size
+  //     Record0
+  //     Record1
+  //     Record2
+  //     ...
+  //
+  // Size is the number of 32-bit values that have been written or
+  // attempted to be written to the output buffer, excluding the Size. It is
+  // initialized to 0. If the size of attempts to write the buffer exceeds
+  // the actual size of the buffer, it is possible that this field can exceed
+  // the actual size of the buffer.
+  //
+  // Each Record* is a variable-length sequence of 32-bit values with the
+  // following format defined using static const offsets in the .cpp file:
+  //
+  //     Record Size
+  //     Shader ID
+  //     Instruction Index
+  //     ...
+  //     Validation Error Code
+  //     Validation-specific Word 0
+  //     Validation-specific Word 1
+  //     Validation-specific Word 2
+  //     ...
+  //
+  // Each record consists of two subsections: members common across all
+  // validation and members specific to a
+  // validation.
+  //
+  // The Record Size is the number of 32-bit words in the record, including
+  // the Record Size word.
+  //
+  // Shader ID is a value that identifies which shader has generated the
+  // validation error. It is passed when the instrumentation pass is created.
+  //
+  // The Instruction Index is the position of the instruction within the
+  // SPIR-V file which is in error.
+  //
+  // The Validation Error Code specifies the exact error which has occurred.
+  // These are enumerated with the kInstError* static consts. This allows
+  // multiple validation layers to use the same, single output buffer.
+  //
+  // The Validation-specific Words are a validation-specific number of 32-bit
+  // words which give further information on the validation error that
+  // occurred. These are documented further in each file containing the
+  // validation-specific class which derives from this base class.
+  //
+  // Because the code that is generated checks against the size of the buffer
+  // before writing, the size of the debug out buffer can be used by the
+  // validation layer to control the number of error records that are written.
+  void GenDebugStreamWrite(uint32_t shader_id, uint32_t instruction_idx_id,
+                           const std::vector<uint32_t>& validation_ids,
+                           InstructionBuilder* builder);
+
+  // Return id for output function. Define if it doesn't exist with
+  // |val_spec_param_cnt| validation-specific uint32 parameters.
+  uint32_t GetStreamWriteFunctionId(uint32_t val_spec_param_cnt);
+
   // Generate instructions for OpDebugPrintf.
   //
   // If |ref_inst_itr| is an OpDebugPrintf, return in |new_blocks| the result
   // of replacing it with buffer write instructions within its block at
   // |ref_block_itr|.  The instructions write a record to the printf
-  // output buffer stream including |function_idx, instruction_idx, stage_idx|
+  // output buffer stream including |function_idx, instruction_idx|
   // and removes the OpDebugPrintf. The block at |ref_block_itr| can just be
   // replaced with the block in |new_blocks|. Besides the buffer writes, this
   // block will comprise all instructions preceding and following
@@ -64,7 +144,6 @@
   // DebugPrintf.
   void GenDebugPrintfCode(BasicBlock::iterator ref_inst_itr,
                           UptrVectorIterator<BasicBlock> ref_block_itr,
-                          uint32_t stage_idx,
                           std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
 
   // Generate a sequence of uint32 instructions in |builder| (if necessary)
@@ -77,16 +156,40 @@
   // Generate instructions to write a record containing the operands of
   // |printf_inst| arguments to printf buffer, adding new code to the end of
   // the last block in |new_blocks|. Kill OpDebugPrintf instruction.
-  void GenOutputCode(Instruction* printf_inst, uint32_t stage_idx,
+  void GenOutputCode(Instruction* printf_inst,
                      std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
 
+  // Set the name for a function or global variable, names will be
+  // prefixed to identify which instrumentation pass generated them.
+  std::unique_ptr<Instruction> NewGlobalName(uint32_t id,
+                                             const std::string& name_str);
+
+  // Set the name for a structure member
+  std::unique_ptr<Instruction> NewMemberName(uint32_t id, uint32_t member_index,
+                                             const std::string& name_str);
+
+  // Return id for debug output buffer
+  uint32_t GetOutputBufferId();
+
+  // Return id for buffer uint type
+  uint32_t GetOutputBufferPtrId();
+
+  // Return binding for output buffer for current validation.
+  uint32_t GetOutputBufferBinding();
+
   // Initialize state for instrumenting bindless checking
   void InitializeInstDebugPrintf();
 
   // Apply GenDebugPrintfCode to every instruction in module.
   Pass::Status ProcessImpl();
 
-  uint32_t ext_inst_printf_id_;
+  uint32_t ext_inst_printf_id_{0};
+
+  // id for output buffer variable
+  uint32_t output_buffer_id_{0};
+
+  // ptr type id for output buffer element
+  uint32_t output_buffer_ptr_id_{0};
 };
 
 }  // namespace opt
diff --git a/third_party/SPIRV-Tools/source/opt/instruction.cpp b/third_party/SPIRV-Tools/source/opt/instruction.cpp
index ece6baf..aa4ae26 100644
--- a/third_party/SPIRV-Tools/source/opt/instruction.cpp
+++ b/third_party/SPIRV-Tools/source/opt/instruction.cpp
@@ -751,7 +751,7 @@
 }
 
 bool Instruction::IsFoldable() const {
-  return IsFoldableByFoldScalar() ||
+  return IsFoldableByFoldScalar() || IsFoldableByFoldVector() ||
          context()->get_instruction_folder().HasConstFoldingRule(this);
 }
 
@@ -762,7 +762,7 @@
   }
 
   Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
-  if (!folder.IsFoldableType(type)) {
+  if (!folder.IsFoldableScalarType(type)) {
     return false;
   }
 
@@ -773,7 +773,29 @@
     Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
     Instruction* def_inst_type =
         context()->get_def_use_mgr()->GetDef(def_inst->type_id());
-    return folder.IsFoldableType(def_inst_type);
+    return folder.IsFoldableScalarType(def_inst_type);
+  });
+}
+
+bool Instruction::IsFoldableByFoldVector() const {
+  const InstructionFolder& folder = context()->get_instruction_folder();
+  if (!folder.IsFoldableOpcode(opcode())) {
+    return false;
+  }
+
+  Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
+  if (!folder.IsFoldableVectorType(type)) {
+    return false;
+  }
+
+  // Even if the type of the instruction is foldable, its operands may not be
+  // foldable (e.g., comparisons of 64bit types).  Check that all operand types
+  // are foldable before accepting the instruction.
+  return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
+    Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
+    Instruction* def_inst_type =
+        context()->get_def_use_mgr()->GetDef(def_inst->type_id());
+    return folder.IsFoldableVectorType(def_inst_type);
   });
 }
 
diff --git a/third_party/SPIRV-Tools/source/opt/instruction.h b/third_party/SPIRV-Tools/source/opt/instruction.h
index d50e625..c2617fb 100644
--- a/third_party/SPIRV-Tools/source/opt/instruction.h
+++ b/third_party/SPIRV-Tools/source/opt/instruction.h
@@ -294,6 +294,8 @@
   // It is the responsibility of the caller to make sure
   // that the instruction remains valid.
   inline void AddOperand(Operand&& operand);
+  // Adds a copy of |operand| to the list of operands of this instruction.
+  inline void AddOperand(const Operand& operand);
   // Gets the |index|-th logical operand as a single SPIR-V word. This method is
   // not expected to be used with logical operands consisting of multiple SPIR-V
   // words.
@@ -522,6 +524,10 @@
   // constant value by |FoldScalar|.
   bool IsFoldableByFoldScalar() const;
 
+  // Returns true if |this| is an instruction which could be folded into a
+  // constant value by |FoldVector|.
+  bool IsFoldableByFoldVector() const;
+
   // Returns true if we are allowed to fold or otherwise manipulate the
   // instruction that defines |id| in the given context. This includes not
   // handling NaN values.
@@ -676,6 +682,10 @@
   operands_.push_back(std::move(operand));
 }
 
+inline void Instruction::AddOperand(const Operand& operand) {
+  operands_.push_back(operand);
+}
+
 inline void Instruction::SetInOperand(uint32_t index,
                                       Operand::OperandData&& data) {
   SetOperand(index + TypeResultIdCount(), std::move(data));
diff --git a/third_party/SPIRV-Tools/source/opt/instrument_pass.cpp b/third_party/SPIRV-Tools/source/opt/instrument_pass.cpp
index 9233ffd..b6845a5 100644
--- a/third_party/SPIRV-Tools/source/opt/instrument_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/instrument_pass.cpp
@@ -22,9 +22,6 @@
 namespace spvtools {
 namespace opt {
 namespace {
-// Common Parameter Positions
-constexpr int kInstCommonParamInstIdx = 0;
-constexpr int kInstCommonParamCnt = 1;
 // Indices of operands in SPIR-V instructions
 constexpr int kEntryPointFunctionIdInIdx = 1;
 }  // namespace
@@ -134,38 +131,6 @@
           {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}});
 }
 
-std::unique_ptr<Instruction> InstrumentPass::NewGlobalName(
-    uint32_t id, const std::string& name_str) {
-  std::string prefixed_name;
-  switch (validation_id_) {
-    case kInstValidationIdBindless:
-      prefixed_name = "inst_bindless_";
-      break;
-    case kInstValidationIdBuffAddr:
-      prefixed_name = "inst_buff_addr_";
-      break;
-    case kInstValidationIdDebugPrintf:
-      prefixed_name = "inst_printf_";
-      break;
-    default:
-      assert(false);  // add new instrumentation pass here
-      prefixed_name = "inst_pass_";
-      break;
-  }
-  prefixed_name += name_str;
-  return NewName(id, prefixed_name);
-}
-
-std::unique_ptr<Instruction> InstrumentPass::NewMemberName(
-    uint32_t id, uint32_t member_index, const std::string& name_str) {
-  return MakeUnique<Instruction>(
-      context(), spv::Op::OpMemberName, 0, 0,
-      std::initializer_list<Operand>{
-          {SPV_OPERAND_TYPE_ID, {id}},
-          {SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}},
-          {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}});
-}
-
 uint32_t InstrumentPass::Gen32BitCvtCode(uint32_t val_id,
                                          InstructionBuilder* builder) {
   // Convert integer value to 32-bit if necessary
@@ -198,52 +163,6 @@
       ->result_id();
 }
 
-void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
-                                             uint32_t field_offset,
-                                             uint32_t field_value_id,
-                                             InstructionBuilder* builder) {
-  // Cast value to 32-bit unsigned if necessary
-  uint32_t val_id = GenUintCastCode(field_value_id, builder);
-  // Store value
-  Instruction* data_idx_inst = builder->AddIAdd(
-      GetUintId(), base_offset_id, builder->GetUintConstantId(field_offset));
-  uint32_t buf_id = GetOutputBufferId();
-  uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
-  Instruction* achain_inst = builder->AddAccessChain(
-      buf_uint_ptr_id, buf_id,
-      {builder->GetUintConstantId(kDebugOutputDataOffset),
-       data_idx_inst->result_id()});
-  (void)builder->AddStore(achain_inst->result_id(), val_id);
-}
-
-void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz,
-                                              uint32_t inst_id,
-                                              uint32_t stage_idx,
-                                              uint32_t base_offset_id,
-                                              InstructionBuilder* builder) {
-  // Store record size
-  GenDebugOutputFieldCode(base_offset_id, kInstCommonOutSize,
-                          builder->GetUintConstantId(record_sz), builder);
-  // Store Shader Id
-  GenDebugOutputFieldCode(base_offset_id, kInstCommonOutShaderId,
-                          builder->GetUintConstantId(shader_id_), builder);
-  // Store Instruction Idx
-  GenDebugOutputFieldCode(base_offset_id, kInstCommonOutInstructionIdx, inst_id,
-                          builder);
-  // Store Stage Idx
-  GenDebugOutputFieldCode(base_offset_id, kInstCommonOutStageIdx,
-                          builder->GetUintConstantId(stage_idx), builder);
-}
-
-void InstrumentPass::GenFragCoordEltDebugOutputCode(
-    uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element,
-    InstructionBuilder* builder) {
-  Instruction* element_val_inst =
-      builder->AddCompositeExtract(GetUintId(), uint_frag_coord_id, {element});
-  GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element,
-                          element_val_inst->result_id(), builder);
-}
-
 uint32_t InstrumentPass::GenVarLoad(uint32_t var_id,
                                     InstructionBuilder* builder) {
   Instruction* var_inst = get_def_use_mgr()->GetDef(var_id);
@@ -252,28 +171,24 @@
   return load_inst->result_id();
 }
 
-void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id,
-                                          uint32_t builtin_off,
-                                          uint32_t base_offset_id,
-                                          InstructionBuilder* builder) {
-  // Load and store builtin
-  uint32_t load_id = GenVarLoad(builtin_id, builder);
-  GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder);
-}
-
-void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
-                                             uint32_t base_offset_id,
-                                             InstructionBuilder* builder) {
+uint32_t InstrumentPass::GenStageInfo(uint32_t stage_idx,
+                                      InstructionBuilder* builder) {
+  std::vector<uint32_t> ids(4, builder->GetUintConstantId(0));
+  ids[0] = builder->GetUintConstantId(stage_idx);
+  // %289 = OpCompositeConstruct %v4uint %uint_0 %285 %288 %uint_0
   // TODO(greg-lunarg): Add support for all stages
   switch (spv::ExecutionModel(stage_idx)) {
     case spv::ExecutionModel::Vertex: {
       // Load and store VertexId and InstanceId
-      GenBuiltinOutputCode(
+      uint32_t load_id = GenVarLoad(
           context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::VertexIndex)),
-          kInstVertOutVertexIndex, base_offset_id, builder);
-      GenBuiltinOutputCode(context()->GetBuiltinInputVarId(
+          builder);
+      ids[1] = GenUintCastCode(load_id, builder);
+
+      load_id = GenVarLoad(context()->GetBuiltinInputVarId(
                                uint32_t(spv::BuiltIn::InstanceIndex)),
-                           kInstVertOutInstanceIndex, base_offset_id, builder);
+                           builder);
+      ids[2] = GenUintCastCode(load_id, builder);
     } break;
     case spv::ExecutionModel::GLCompute:
     case spv::ExecutionModel::TaskNV:
@@ -284,56 +199,50 @@
       uint32_t load_id = GenVarLoad(context()->GetBuiltinInputVarId(uint32_t(
                                         spv::BuiltIn::GlobalInvocationId)),
                                     builder);
-      Instruction* x_inst =
-          builder->AddCompositeExtract(GetUintId(), load_id, {0});
-      Instruction* y_inst =
-          builder->AddCompositeExtract(GetUintId(), load_id, {1});
-      Instruction* z_inst =
-          builder->AddCompositeExtract(GetUintId(), load_id, {2});
-      GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX,
-                              x_inst->result_id(), builder);
-      GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY,
-                              y_inst->result_id(), builder);
-      GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ,
-                              z_inst->result_id(), builder);
+      for (uint32_t u = 0; u < 3u; ++u) {
+        ids[u + 1] = builder->AddCompositeExtract(GetUintId(), load_id, {u})
+                         ->result_id();
+      }
     } break;
     case spv::ExecutionModel::Geometry: {
       // Load and store PrimitiveId and InvocationId.
-      GenBuiltinOutputCode(
+      uint32_t load_id = GenVarLoad(
           context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
-          kInstGeomOutPrimitiveId, base_offset_id, builder);
-      GenBuiltinOutputCode(
+          builder);
+      ids[1] = load_id;
+      load_id = GenVarLoad(
           context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)),
-          kInstGeomOutInvocationId, base_offset_id, builder);
+          builder);
+      ids[2] = GenUintCastCode(load_id, builder);
     } break;
     case spv::ExecutionModel::TessellationControl: {
       // Load and store InvocationId and PrimitiveId
-      GenBuiltinOutputCode(
+      uint32_t load_id = GenVarLoad(
           context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)),
-          kInstTessCtlOutInvocationId, base_offset_id, builder);
-      GenBuiltinOutputCode(
+          builder);
+      ids[1] = GenUintCastCode(load_id, builder);
+      load_id = GenVarLoad(
           context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
-          kInstTessCtlOutPrimitiveId, base_offset_id, builder);
+          builder);
+      ids[2] = load_id;
     } break;
     case spv::ExecutionModel::TessellationEvaluation: {
       // Load and store PrimitiveId and TessCoord.uv
-      GenBuiltinOutputCode(
-          context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
-          kInstTessEvalOutPrimitiveId, base_offset_id, builder);
       uint32_t load_id = GenVarLoad(
+          context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
+          builder);
+      ids[1] = load_id;
+      load_id = GenVarLoad(
           context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::TessCoord)),
           builder);
       Instruction* uvec3_cast_inst =
           builder->AddUnaryOp(GetVec3UintId(), spv::Op::OpBitcast, load_id);
       uint32_t uvec3_cast_id = uvec3_cast_inst->result_id();
-      Instruction* u_inst =
-          builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {0});
-      Instruction* v_inst =
-          builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {1});
-      GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU,
-                              u_inst->result_id(), builder);
-      GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV,
-                              v_inst->result_id(), builder);
+      for (uint32_t u = 0; u < 2u; ++u) {
+        ids[u + 2] =
+            builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {u})
+                ->result_id();
+      }
     } break;
     case spv::ExecutionModel::Fragment: {
       // Load FragCoord and convert to Uint
@@ -342,9 +251,13 @@
           context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::FragCoord)));
       Instruction* uint_frag_coord_inst = builder->AddUnaryOp(
           GetVec4UintId(), spv::Op::OpBitcast, frag_coord_inst->result_id());
-      for (uint32_t u = 0; u < 2u; ++u)
-        GenFragCoordEltDebugOutputCode(
-            base_offset_id, uint_frag_coord_inst->result_id(), u, builder);
+      for (uint32_t u = 0; u < 2u; ++u) {
+        ids[u + 1] =
+            builder
+                ->AddCompositeExtract(GetUintId(),
+                                      uint_frag_coord_inst->result_id(), {u})
+                ->result_id();
+      }
     } break;
     case spv::ExecutionModel::RayGenerationNV:
     case spv::ExecutionModel::IntersectionNV:
@@ -356,33 +269,14 @@
       uint32_t launch_id = GenVarLoad(
           context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::LaunchIdNV)),
           builder);
-      Instruction* x_launch_inst =
-          builder->AddCompositeExtract(GetUintId(), launch_id, {0});
-      Instruction* y_launch_inst =
-          builder->AddCompositeExtract(GetUintId(), launch_id, {1});
-      Instruction* z_launch_inst =
-          builder->AddCompositeExtract(GetUintId(), launch_id, {2});
-      GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX,
-                              x_launch_inst->result_id(), builder);
-      GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY,
-                              y_launch_inst->result_id(), builder);
-      GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ,
-                              z_launch_inst->result_id(), builder);
+      for (uint32_t u = 0; u < 3u; ++u) {
+        ids[u + 1] = builder->AddCompositeExtract(GetUintId(), launch_id, {u})
+                         ->result_id();
+      }
     } break;
     default: { assert(false && "unsupported stage"); } break;
   }
-}
-
-void InstrumentPass::GenDebugStreamWrite(
-    uint32_t instruction_idx, uint32_t stage_idx,
-    const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
-  // Call debug output function. Pass func_idx, instruction_idx and
-  // validation ids as args.
-  uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
-  std::vector<uint32_t> args = {builder->GetUintConstantId(instruction_idx)};
-  (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
-  (void)builder->AddFunctionCall(
-      GetVoidId(), GetStreamWriteFunctionId(stage_idx, val_id_cnt), args);
+  return builder->AddCompositeConstruct(GetVec4UintId(), ids)->result_id();
 }
 
 bool InstrumentPass::AllConstant(const std::vector<uint32_t>& ids) {
@@ -393,16 +287,9 @@
   return true;
 }
 
-uint32_t InstrumentPass::GenDebugDirectRead(
-    const std::vector<uint32_t>& offset_ids, InstructionBuilder* builder) {
-  // Call debug input function. Pass func_idx and offset ids as args.
-  const uint32_t off_id_cnt = static_cast<uint32_t>(offset_ids.size());
-  const uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt);
-  return GenReadFunctionCall(input_func_id, offset_ids, builder);
-}
-
 uint32_t InstrumentPass::GenReadFunctionCall(
-    uint32_t func_id, const std::vector<uint32_t>& func_call_args,
+    uint32_t return_id, uint32_t func_id,
+    const std::vector<uint32_t>& func_call_args,
     InstructionBuilder* ref_builder) {
   // If optimizing direct reads and the call has already been generated,
   // use its result
@@ -423,8 +310,7 @@
     builder.SetInsertPoint(insert_before);
   }
   uint32_t res_id =
-      builder.AddFunctionCall(GetUintId(), func_id, func_call_args)
-          ->result_id();
+      builder.AddFunctionCall(return_id, func_id, func_call_args)->result_id();
   if (insert_in_first_block) call2id_[func_call_args] = res_id;
   return res_id;
 }
@@ -494,53 +380,6 @@
       });
 }
 
-uint32_t InstrumentPass::GetOutputBufferPtrId() {
-  if (output_buffer_ptr_id_ == 0) {
-    output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
-        GetUintId(), spv::StorageClass::StorageBuffer);
-  }
-  return output_buffer_ptr_id_;
-}
-
-uint32_t InstrumentPass::GetInputBufferTypeId() {
-  return (validation_id_ == kInstValidationIdBuffAddr) ? GetUint64Id()
-                                                       : GetUintId();
-}
-
-uint32_t InstrumentPass::GetInputBufferPtrId() {
-  if (input_buffer_ptr_id_ == 0) {
-    input_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
-        GetInputBufferTypeId(), spv::StorageClass::StorageBuffer);
-  }
-  return input_buffer_ptr_id_;
-}
-
-uint32_t InstrumentPass::GetOutputBufferBinding() {
-  switch (validation_id_) {
-    case kInstValidationIdBindless:
-      return kDebugOutputBindingStream;
-    case kInstValidationIdBuffAddr:
-      return kDebugOutputBindingStream;
-    case kInstValidationIdDebugPrintf:
-      return kDebugOutputPrintfStream;
-    default:
-      assert(false && "unexpected validation id");
-  }
-  return 0;
-}
-
-uint32_t InstrumentPass::GetInputBufferBinding() {
-  switch (validation_id_) {
-    case kInstValidationIdBindless:
-      return kDebugInputBindingBindless;
-    case kInstValidationIdBuffAddr:
-      return kDebugInputBindingBuffAddr;
-    default:
-      assert(false && "unexpected validation id");
-  }
-  return 0;
-}
-
 analysis::Integer* InstrumentPass::GetInteger(uint32_t width, bool is_signed) {
   analysis::Integer i(width, is_signed);
   analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&i);
@@ -621,110 +460,6 @@
   storage_buffer_ext_defined_ = true;
 }
 
-// Return id for output buffer
-uint32_t InstrumentPass::GetOutputBufferId() {
-  if (output_buffer_id_ == 0) {
-    // If not created yet, create one
-    analysis::DecorationManager* deco_mgr = get_decoration_mgr();
-    analysis::TypeManager* type_mgr = context()->get_type_mgr();
-    analysis::RuntimeArray* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
-    analysis::Integer* reg_uint_ty = GetInteger(32, false);
-    analysis::Type* reg_buf_ty =
-        GetStruct({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty});
-    uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
-    // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
-    // must be a block, and will therefore be decorated with Block. Therefore
-    // the undecorated type returned here will not be pre-existing and can
-    // safely be decorated. Since this type is now decorated, it is out of
-    // sync with the TypeManager and therefore the TypeManager must be
-    // invalidated after this pass.
-    assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
-           "used struct type returned");
-    deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block));
-    deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset,
-                                  uint32_t(spv::Decoration::Offset), 0);
-    deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
-                                  uint32_t(spv::Decoration::Offset), 4);
-    deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
-                                  uint32_t(spv::Decoration::Offset), 8);
-    uint32_t obufTyPtrId_ =
-        type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer);
-    output_buffer_id_ = TakeNextId();
-    std::unique_ptr<Instruction> newVarOp(new Instruction(
-        context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_,
-        {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
-          {uint32_t(spv::StorageClass::StorageBuffer)}}}));
-    context()->AddGlobalValue(std::move(newVarOp));
-    context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer"));
-    context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags"));
-    context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count"));
-    context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data"));
-    context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer"));
-    deco_mgr->AddDecorationVal(
-        output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
-    deco_mgr->AddDecorationVal(output_buffer_id_,
-                               uint32_t(spv::Decoration::Binding),
-                               GetOutputBufferBinding());
-    AddStorageBufferExt();
-    if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
-      // Add the new buffer to all entry points.
-      for (auto& entry : get_module()->entry_points()) {
-        entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}});
-        context()->AnalyzeUses(&entry);
-      }
-    }
-  }
-  return output_buffer_id_;
-}
-
-uint32_t InstrumentPass::GetInputBufferId() {
-  if (input_buffer_id_ == 0) {
-    // If not created yet, create one
-    analysis::DecorationManager* deco_mgr = get_decoration_mgr();
-    analysis::TypeManager* type_mgr = context()->get_type_mgr();
-    uint32_t width = (validation_id_ == kInstValidationIdBuffAddr) ? 64u : 32u;
-    analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(width);
-    analysis::Struct* reg_buf_ty = GetStruct({reg_uint_rarr_ty});
-    uint32_t ibufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
-    // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
-    // must be a block, and will therefore be decorated with Block. Therefore
-    // the undecorated type returned here will not be pre-existing and can
-    // safely be decorated. Since this type is now decorated, it is out of
-    // sync with the TypeManager and therefore the TypeManager must be
-    // invalidated after this pass.
-    assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 &&
-           "used struct type returned");
-    deco_mgr->AddDecoration(ibufTyId, uint32_t(spv::Decoration::Block));
-    deco_mgr->AddMemberDecoration(ibufTyId, 0,
-                                  uint32_t(spv::Decoration::Offset), 0);
-    uint32_t ibufTyPtrId_ =
-        type_mgr->FindPointerToType(ibufTyId, spv::StorageClass::StorageBuffer);
-    input_buffer_id_ = TakeNextId();
-    std::unique_ptr<Instruction> newVarOp(new Instruction(
-        context(), spv::Op::OpVariable, ibufTyPtrId_, input_buffer_id_,
-        {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
-          {uint32_t(spv::StorageClass::StorageBuffer)}}}));
-    context()->AddGlobalValue(std::move(newVarOp));
-    context()->AddDebug2Inst(NewGlobalName(ibufTyId, "InputBuffer"));
-    context()->AddDebug2Inst(NewMemberName(ibufTyId, 0, "data"));
-    context()->AddDebug2Inst(NewGlobalName(input_buffer_id_, "input_buffer"));
-    deco_mgr->AddDecorationVal(
-        input_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
-    deco_mgr->AddDecorationVal(input_buffer_id_,
-                               uint32_t(spv::Decoration::Binding),
-                               GetInputBufferBinding());
-    AddStorageBufferExt();
-    if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
-      // Add the new buffer to all entry points.
-      for (auto& entry : get_module()->entry_points()) {
-        entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}});
-        context()->AnalyzeUses(&entry);
-      }
-    }
-  }
-  return input_buffer_id_;
-}
-
 uint32_t InstrumentPass::GetFloatId() {
   if (float_id_ == 0) {
     analysis::TypeManager* type_mgr = context()->get_type_mgr();
@@ -817,159 +552,6 @@
   return void_id_;
 }
 
-uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
-                                                  uint32_t val_spec_param_cnt) {
-  // Total param count is common params plus validation-specific
-  // params
-  uint32_t param_cnt = kInstCommonParamCnt + val_spec_param_cnt;
-  if (param2output_func_id_[param_cnt] == 0) {
-    // Create function
-    param2output_func_id_[param_cnt] = TakeNextId();
-    analysis::TypeManager* type_mgr = context()->get_type_mgr();
-
-    const std::vector<const analysis::Type*> param_types(param_cnt,
-                                                         GetInteger(32, false));
-    std::unique_ptr<Function> output_func = StartFunction(
-        param2output_func_id_[param_cnt], type_mgr->GetVoidType(), param_types);
-
-    std::vector<uint32_t> param_ids = AddParameters(*output_func, param_types);
-
-    // Create first block
-    auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
-
-    InstructionBuilder builder(
-        context(), &*new_blk_ptr,
-        IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
-    // Gen test if debug output buffer size will not be exceeded.
-    uint32_t val_spec_offset = kInstStageOutCnt;
-    uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt;
-    uint32_t buf_id = GetOutputBufferId();
-    uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
-    Instruction* obuf_curr_sz_ac_inst = builder.AddAccessChain(
-        buf_uint_ptr_id, buf_id,
-        {builder.GetUintConstantId(kDebugOutputSizeOffset)});
-    // Fetch the current debug buffer written size atomically, adding the
-    // size of the record to be written.
-    uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
-    uint32_t mask_none_id =
-        builder.GetUintConstantId(uint32_t(spv::MemoryAccessMask::MaskNone));
-    uint32_t scope_invok_id =
-        builder.GetUintConstantId(uint32_t(spv::Scope::Invocation));
-    Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
-        GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
-        scope_invok_id, mask_none_id, obuf_record_sz_id);
-    uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
-    // Compute new written size
-    Instruction* obuf_new_sz_inst =
-        builder.AddIAdd(GetUintId(), obuf_curr_sz_id,
-                        builder.GetUintConstantId(obuf_record_sz));
-    // Fetch the data bound
-    Instruction* obuf_bnd_inst =
-        builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength,
-                               GetOutputBufferId(), kDebugOutputDataOffset);
-    // Test that new written size is less than or equal to debug output
-    // data bound
-    Instruction* obuf_safe_inst = builder.AddBinaryOp(
-        GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(),
-        obuf_bnd_inst->result_id());
-    uint32_t merge_blk_id = TakeNextId();
-    uint32_t write_blk_id = TakeNextId();
-    std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
-    std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
-    (void)builder.AddConditionalBranch(
-        obuf_safe_inst->result_id(), write_blk_id, merge_blk_id, merge_blk_id,
-        uint32_t(spv::SelectionControlMask::MaskNone));
-    // Close safety test block and gen write block
-    output_func->AddBasicBlock(std::move(new_blk_ptr));
-    new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
-    builder.SetInsertPoint(&*new_blk_ptr);
-    // Generate common and stage-specific debug record members
-    GenCommonStreamWriteCode(obuf_record_sz, param_ids[kInstCommonParamInstIdx],
-                             stage_idx, obuf_curr_sz_id, &builder);
-    GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder);
-    // Gen writes of validation specific data
-    for (uint32_t i = 0; i < val_spec_param_cnt; ++i) {
-      GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i,
-                              param_ids[kInstCommonParamCnt + i], &builder);
-    }
-    // Close write block and gen merge block
-    (void)builder.AddBranch(merge_blk_id);
-    output_func->AddBasicBlock(std::move(new_blk_ptr));
-    new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
-    builder.SetInsertPoint(&*new_blk_ptr);
-    // Close merge block and function and add function to module
-    (void)builder.AddNullaryOp(0, spv::Op::OpReturn);
-
-    output_func->AddBasicBlock(std::move(new_blk_ptr));
-    output_func->SetFunctionEnd(EndFunction());
-    context()->AddFunction(std::move(output_func));
-
-    std::string name("stream_write_");
-    name += std::to_string(param_cnt);
-
-    context()->AddDebug2Inst(
-        NewGlobalName(param2output_func_id_[param_cnt], name));
-  }
-  return param2output_func_id_[param_cnt];
-}
-
-uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) {
-  uint32_t func_id = param2input_func_id_[param_cnt];
-  if (func_id != 0) return func_id;
-  // Create input function for param_cnt.
-  func_id = TakeNextId();
-  analysis::Integer* uint_type = GetInteger(32, false);
-  std::vector<const analysis::Type*> param_types(param_cnt, uint_type);
-
-  std::unique_ptr<Function> input_func =
-      StartFunction(func_id, uint_type, param_types);
-  std::vector<uint32_t> param_ids = AddParameters(*input_func, param_types);
-
-  // Create block
-  auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
-  InstructionBuilder builder(
-      context(), &*new_blk_ptr,
-      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
-  // For each offset parameter, generate new offset with parameter, adding last
-  // loaded value if it exists, and load value from input buffer at new offset.
-  // Return last loaded value.
-  uint32_t ibuf_type_id = GetInputBufferTypeId();
-  uint32_t buf_id = GetInputBufferId();
-  uint32_t buf_ptr_id = GetInputBufferPtrId();
-  uint32_t last_value_id = 0;
-  for (uint32_t p = 0; p < param_cnt; ++p) {
-    uint32_t offset_id;
-    if (p == 0) {
-      offset_id = param_ids[0];
-    } else {
-      if (ibuf_type_id != GetUintId()) {
-        last_value_id =
-            builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, last_value_id)
-                ->result_id();
-      }
-      offset_id = builder.AddIAdd(GetUintId(), last_value_id, param_ids[p])
-                      ->result_id();
-    }
-    Instruction* ac_inst = builder.AddAccessChain(
-        buf_ptr_id, buf_id,
-        {builder.GetUintConstantId(kDebugInputDataOffset), offset_id});
-    last_value_id =
-        builder.AddLoad(ibuf_type_id, ac_inst->result_id())->result_id();
-  }
-  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, last_value_id);
-  // Close block and function and add function to module
-  input_func->AddBasicBlock(std::move(new_blk_ptr));
-  input_func->SetFunctionEnd(EndFunction());
-  context()->AddFunction(std::move(input_func));
-
-  std::string name("direct_read_");
-  name += std::to_string(param_cnt);
-  context()->AddDebug2Inst(NewGlobalName(func_id, name));
-
-  param2input_func_id_[param_cnt] = func_id;
-  return func_id;
-}
-
 void InstrumentPass::SplitBlock(
     BasicBlock::iterator inst_itr, UptrVectorIterator<BasicBlock> block_itr,
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
@@ -1071,52 +653,54 @@
 }
 
 bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
-  // Make sure all entry points have the same execution model. Do not
-  // instrument if they do not.
-  // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module
-  // can contain entry points with different execution models, although
-  // such modules will likely be rare as GLSL and HLSL are geared toward
-  // one model per module. In such cases we will need
-  // to clone any functions which are in the call trees of entrypoints
-  // with differing execution models.
-  spv::ExecutionModel stage = context()->GetStage();
-  // Check for supported stages
-  if (stage != spv::ExecutionModel::Vertex &&
-      stage != spv::ExecutionModel::Fragment &&
-      stage != spv::ExecutionModel::Geometry &&
-      stage != spv::ExecutionModel::GLCompute &&
-      stage != spv::ExecutionModel::TessellationControl &&
-      stage != spv::ExecutionModel::TessellationEvaluation &&
-      stage != spv::ExecutionModel::TaskNV &&
-      stage != spv::ExecutionModel::MeshNV &&
-      stage != spv::ExecutionModel::RayGenerationNV &&
-      stage != spv::ExecutionModel::IntersectionNV &&
-      stage != spv::ExecutionModel::AnyHitNV &&
-      stage != spv::ExecutionModel::ClosestHitNV &&
-      stage != spv::ExecutionModel::MissNV &&
-      stage != spv::ExecutionModel::CallableNV &&
-      stage != spv::ExecutionModel::TaskEXT &&
-      stage != spv::ExecutionModel::MeshEXT) {
-    if (consumer()) {
-      std::string message = "Stage not supported by instrumentation";
-      consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
+  uint32_t stage_id;
+  if (use_stage_info_) {
+    // Make sure all entry points have the same execution model. Do not
+    // instrument if they do not.
+    // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module
+    // can contain entry points with different execution models, although
+    // such modules will likely be rare as GLSL and HLSL are geared toward
+    // one model per module. In such cases we will need
+    // to clone any functions which are in the call trees of entrypoints
+    // with differing execution models.
+    spv::ExecutionModel stage = context()->GetStage();
+    // Check for supported stages
+    if (stage != spv::ExecutionModel::Vertex &&
+        stage != spv::ExecutionModel::Fragment &&
+        stage != spv::ExecutionModel::Geometry &&
+        stage != spv::ExecutionModel::GLCompute &&
+        stage != spv::ExecutionModel::TessellationControl &&
+        stage != spv::ExecutionModel::TessellationEvaluation &&
+        stage != spv::ExecutionModel::TaskNV &&
+        stage != spv::ExecutionModel::MeshNV &&
+        stage != spv::ExecutionModel::RayGenerationNV &&
+        stage != spv::ExecutionModel::IntersectionNV &&
+        stage != spv::ExecutionModel::AnyHitNV &&
+        stage != spv::ExecutionModel::ClosestHitNV &&
+        stage != spv::ExecutionModel::MissNV &&
+        stage != spv::ExecutionModel::CallableNV &&
+        stage != spv::ExecutionModel::TaskEXT &&
+        stage != spv::ExecutionModel::MeshEXT) {
+      if (consumer()) {
+        std::string message = "Stage not supported by instrumentation";
+        consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
+      }
+      return false;
     }
-    return false;
+    stage_id = static_cast<uint32_t>(stage);
+  } else {
+    stage_id = 0;
   }
   // Add together the roots of all entry points
   std::queue<uint32_t> roots;
   for (auto& e : get_module()->entry_points()) {
     roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
   }
-  bool modified = InstProcessCallTreeFromRoots(pfn, &roots, uint32_t(stage));
+  bool modified = InstProcessCallTreeFromRoots(pfn, &roots, stage_id);
   return modified;
 }
 
 void InstrumentPass::InitializeInstrument() {
-  output_buffer_id_ = 0;
-  output_buffer_ptr_id_ = 0;
-  input_buffer_ptr_id_ = 0;
-  input_buffer_id_ = 0;
   float_id_ = 0;
   v4float_id_ = 0;
   uint_id_ = 0;
diff --git a/third_party/SPIRV-Tools/source/opt/instrument_pass.h b/third_party/SPIRV-Tools/source/opt/instrument_pass.h
index 4bbbb09..e4408c9 100644
--- a/third_party/SPIRV-Tools/source/opt/instrument_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/instrument_pass.h
@@ -55,14 +55,6 @@
 
 namespace spvtools {
 namespace opt {
-namespace {
-// Validation Ids
-// These are used to identify the general validation being done and map to
-// its output buffers.
-constexpr uint32_t kInstValidationIdBindless = 0;
-constexpr uint32_t kInstValidationIdBuffAddr = 1;
-constexpr uint32_t kInstValidationIdDebugPrintf = 2;
-}  // namespace
 
 class InstrumentPass : public Pass {
   using cbb_ptr = const BasicBlock*;
@@ -85,13 +77,13 @@
   // set |desc_set| for debug input and output buffers and writes |shader_id|
   // into debug output records. |opt_direct_reads| indicates that the pass
   // will see direct input buffer reads and should prepare to optimize them.
-  InstrumentPass(uint32_t desc_set, uint32_t shader_id, uint32_t validation_id,
-                 bool opt_direct_reads = false)
+  InstrumentPass(uint32_t desc_set, uint32_t shader_id, bool opt_direct_reads,
+                 bool use_stage_info)
       : Pass(),
         desc_set_(desc_set),
         shader_id_(shader_id),
-        validation_id_(validation_id),
-        opt_direct_reads_(opt_direct_reads) {}
+        opt_direct_reads_(opt_direct_reads),
+        use_stage_info_(use_stage_info) {}
 
   // Initialize state for instrumentation of module.
   void InitializeInstrument();
@@ -113,108 +105,10 @@
   void MovePostludeCode(UptrVectorIterator<BasicBlock> ref_block_itr,
                         BasicBlock* new_blk_ptr);
 
-  // Generate instructions in |builder| which will atomically fetch and
-  // increment the size of the debug output buffer stream of the current
-  // validation and write a record to the end of the stream, if enough space
-  // in the buffer remains. The record will contain the index of the function
-  // and instruction within that function |func_idx, instruction_idx| which
-  // generated the record. It will also contain additional information to
-  // identify the instance of the shader, depending on the stage |stage_idx|
-  // of the shader. Finally, the record will contain validation-specific
-  // data contained in |validation_ids| which will identify the validation
-  // error as well as the values involved in the error.
-  //
-  // The output buffer binding written to by the code generated by the function
-  // is determined by the validation id specified when each specific
-  // instrumentation pass is created.
-  //
-  // The output buffer is a sequence of 32-bit values with the following
-  // format (where all elements are unsigned 32-bit unless otherwise noted):
-  //
-  //     Size
-  //     Record0
-  //     Record1
-  //     Record2
-  //     ...
-  //
-  // Size is the number of 32-bit values that have been written or
-  // attempted to be written to the output buffer, excluding the Size. It is
-  // initialized to 0. If the size of attempts to write the buffer exceeds
-  // the actual size of the buffer, it is possible that this field can exceed
-  // the actual size of the buffer.
-  //
-  // Each Record* is a variable-length sequence of 32-bit values with the
-  // following format defined using static const offsets in the .cpp file:
-  //
-  //     Record Size
-  //     Shader ID
-  //     Instruction Index
-  //     Stage
-  //     Stage-specific Word 0
-  //     Stage-specific Word 1
-  //     ...
-  //     Validation Error Code
-  //     Validation-specific Word 0
-  //     Validation-specific Word 1
-  //     Validation-specific Word 2
-  //     ...
-  //
-  // Each record consists of three subsections: members common across all
-  // validation, members specific to the stage, and members specific to a
-  // validation.
-  //
-  // The Record Size is the number of 32-bit words in the record, including
-  // the Record Size word.
-  //
-  // Shader ID is a value that identifies which shader has generated the
-  // validation error. It is passed when the instrumentation pass is created.
-  //
-  // The Instruction Index is the position of the instruction within the
-  // SPIR-V file which is in error.
-  //
-  // The Stage is the pipeline stage which has generated the error as defined
-  // by the SpvExecutionModel_ enumeration. This is used to interpret the
-  // following Stage-specific words.
-  //
-  // The Stage-specific Words identify which invocation of the shader generated
-  // the error. Every stage will write a fixed number of words. Vertex shaders
-  // will write the Vertex and Instance ID. Fragment shaders will write
-  // FragCoord.xy. Compute shaders will write the GlobalInvocation ID.
-  // The tessellation eval shader will write the Primitive ID and TessCoords.uv.
-  // The tessellation control shader and geometry shader will write the
-  // Primitive ID and Invocation ID.
-  //
-  // The Validation Error Code specifies the exact error which has occurred.
-  // These are enumerated with the kInstError* static consts. This allows
-  // multiple validation layers to use the same, single output buffer.
-  //
-  // The Validation-specific Words are a validation-specific number of 32-bit
-  // words which give further information on the validation error that
-  // occurred. These are documented further in each file containing the
-  // validation-specific class which derives from this base class.
-  //
-  // Because the code that is generated checks against the size of the buffer
-  // before writing, the size of the debug out buffer can be used by the
-  // validation layer to control the number of error records that are written.
-  void GenDebugStreamWrite(uint32_t instruction_idx, uint32_t stage_idx,
-                           const std::vector<uint32_t>& validation_ids,
-                           InstructionBuilder* builder);
-
   // Return true if all instructions in |ids| are constants or spec constants.
   bool AllConstant(const std::vector<uint32_t>& ids);
 
-  // Generate in |builder| instructions to read the unsigned integer from the
-  // input buffer specified by the offsets in |offset_ids|. Given offsets
-  // o0, o1, ... oN, and input buffer ibuf, return the id for the value:
-  //
-  // ibuf[...ibuf[ibuf[o0]+o1]...+oN]
-  //
-  // The binding and the format of the input buffer is determined by each
-  // specific validation, which is specified at the creation of the pass.
-  uint32_t GenDebugDirectRead(const std::vector<uint32_t>& offset_ids,
-                              InstructionBuilder* builder);
-
-  uint32_t GenReadFunctionCall(uint32_t func_id,
+  uint32_t GenReadFunctionCall(uint32_t return_id, uint32_t func_id,
                                const std::vector<uint32_t>& args,
                                InstructionBuilder* builder);
 
@@ -242,15 +136,6 @@
   std::unique_ptr<Instruction> NewName(uint32_t id,
                                        const std::string& name_str);
 
-  // Set the name for a function or global variable, names will be
-  // prefixed to identify which instrumentation pass generated them.
-  std::unique_ptr<Instruction> NewGlobalName(uint32_t id,
-                                             const std::string& name_str);
-
-  // Set the name for a structure member
-  std::unique_ptr<Instruction> NewMemberName(uint32_t id, uint32_t member_index,
-                                             const std::string& name_str);
-
   // Return id for 32-bit unsigned type
   uint32_t GetUintId();
 
@@ -282,30 +167,9 @@
   // Return pointer to type for runtime array of uint
   analysis::RuntimeArray* GetUintRuntimeArrayType(uint32_t width);
 
-  // Return id for buffer uint type
-  uint32_t GetOutputBufferPtrId();
-
-  // Return id for buffer uint type
-  uint32_t GetInputBufferTypeId();
-
-  // Return id for buffer uint type
-  uint32_t GetInputBufferPtrId();
-
-  // Return binding for output buffer for current validation.
-  uint32_t GetOutputBufferBinding();
-
-  // Return binding for input buffer for current validation.
-  uint32_t GetInputBufferBinding();
-
   // Add storage buffer extension if needed
   void AddStorageBufferExt();
 
-  // Return id for debug output buffer
-  uint32_t GetOutputBufferId();
-
-  // Return id for debug input buffer
-  uint32_t GetInputBufferId();
-
   // Return id for 32-bit float type
   uint32_t GetFloatId();
 
@@ -321,15 +185,6 @@
   // Return id for v3uint type
   uint32_t GetVec3UintId();
 
-  // Return id for output function. Define if it doesn't exist with
-  // |val_spec_param_cnt| validation-specific uint32 parameters.
-  uint32_t GetStreamWriteFunctionId(uint32_t stage_idx,
-                                    uint32_t val_spec_param_cnt);
-
-  // Return id for input function taking |param_cnt| uint32 parameters. Define
-  // if it doesn't exist.
-  uint32_t GetDirectReadFunctionId(uint32_t param_cnt);
-
   // Split block |block_itr| into two new blocks where the second block
   // contains |inst_itr| and place in |new_blocks|.
   void SplitBlock(BasicBlock::iterator inst_itr,
@@ -349,40 +204,11 @@
                                     std::queue<uint32_t>* roots,
                                     uint32_t stage_idx);
 
-  // Gen code into |builder| to write |field_value_id| into debug output
-  // buffer at |base_offset_id| + |field_offset|.
-  void GenDebugOutputFieldCode(uint32_t base_offset_id, uint32_t field_offset,
-                               uint32_t field_value_id,
-                               InstructionBuilder* builder);
-
-  // Generate instructions into |builder| which will write the members
-  // of the debug output record common for all stages and validations at
-  // |base_off|.
-  void GenCommonStreamWriteCode(uint32_t record_sz, uint32_t instruction_idx,
-                                uint32_t stage_idx, uint32_t base_off,
-                                InstructionBuilder* builder);
-
-  // Generate instructions into |builder| which will write
-  // |uint_frag_coord_id| at |component| of the record at |base_offset_id| of
-  // the debug output buffer .
-  void GenFragCoordEltDebugOutputCode(uint32_t base_offset_id,
-                                      uint32_t uint_frag_coord_id,
-                                      uint32_t component,
-                                      InstructionBuilder* builder);
-
   // Generate instructions into |builder| which will load |var_id| and return
   // its result id.
   uint32_t GenVarLoad(uint32_t var_id, InstructionBuilder* builder);
 
-  // Generate instructions into |builder| which will load the uint |builtin_id|
-  // and write it into the debug output buffer at |base_off| + |builtin_off|.
-  void GenBuiltinOutputCode(uint32_t builtin_id, uint32_t builtin_off,
-                            uint32_t base_off, InstructionBuilder* builder);
-
-  // Generate instructions into |builder| which will write the |stage_idx|-
-  // specific members of the debug output stream at |base_off|.
-  void GenStageStreamWriteCode(uint32_t stage_idx, uint32_t base_off,
-                               InstructionBuilder* builder);
+  uint32_t GenStageInfo(uint32_t stage_idx, InstructionBuilder* builder);
 
   // Return true if instruction must be in the same block that its result
   // is used.
@@ -418,62 +244,47 @@
   // Map from instruction's unique id to offset in original file.
   std::unordered_map<uint32_t, uint32_t> uid2offset_;
 
-  // result id for OpConstantFalse
-  uint32_t validation_id_;
-
-  // id for output buffer variable
-  uint32_t output_buffer_id_;
-
-  // ptr type id for output buffer element
-  uint32_t output_buffer_ptr_id_;
-
-  // ptr type id for input buffer element
-  uint32_t input_buffer_ptr_id_;
-
   // id for debug output function
   std::unordered_map<uint32_t, uint32_t> param2output_func_id_;
 
   // ids for debug input functions
   std::unordered_map<uint32_t, uint32_t> param2input_func_id_;
 
-  // id for input buffer variable
-  uint32_t input_buffer_id_;
-
   // id for 32-bit float type
-  uint32_t float_id_;
+  uint32_t float_id_{0};
 
   // id for v4float type
-  uint32_t v4float_id_;
+  uint32_t v4float_id_{0};
 
   // id for v4uint type
-  uint32_t v4uint_id_;
+  uint32_t v4uint_id_{0};
 
   // id for v3uint type
-  uint32_t v3uint_id_;
+  uint32_t v3uint_id_{0};
 
   // id for 32-bit unsigned type
-  uint32_t uint_id_;
+  uint32_t uint_id_{0};
 
   // id for 64-bit unsigned type
-  uint32_t uint64_id_;
+  uint32_t uint64_id_{0};
 
   // id for 8-bit unsigned type
-  uint32_t uint8_id_;
+  uint32_t uint8_id_{0};
 
   // id for bool type
-  uint32_t bool_id_;
+  uint32_t bool_id_{0};
 
   // id for void type
-  uint32_t void_id_;
+  uint32_t void_id_{0};
 
   // boolean to remember storage buffer extension
-  bool storage_buffer_ext_defined_;
+  bool storage_buffer_ext_defined_{false};
 
   // runtime array of uint type
-  analysis::RuntimeArray* uint64_rarr_ty_;
+  analysis::RuntimeArray* uint64_rarr_ty_{nullptr};
 
   // runtime array of uint type
-  analysis::RuntimeArray* uint32_rarr_ty_;
+  analysis::RuntimeArray* uint32_rarr_ty_{nullptr};
 
   // Pre-instrumentation same-block insts
   std::unordered_map<uint32_t, Instruction*> same_block_pre_;
@@ -498,11 +309,15 @@
   std::unordered_map<std::vector<uint32_t>, uint32_t, vector_hash_> call2id_;
 
   // Function currently being instrumented
-  Function* curr_func_;
+  Function* curr_func_{nullptr};
 
   // Optimize direct debug input buffer reads. Specifically, move all such
   // reads with constant args to first block and reuse them.
-  bool opt_direct_reads_;
+  const bool opt_direct_reads_;
+
+  // Set true if the instrumentation needs to know the current stage.
+  // Note that this does not work with multi-stage modules.
+  const bool use_stage_info_;
 };
 
 }  // namespace opt
diff --git a/third_party/SPIRV-Tools/source/opt/invocation_interlock_placement_pass.cpp b/third_party/SPIRV-Tools/source/opt/invocation_interlock_placement_pass.cpp
new file mode 100644
index 0000000..642e2d2
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/invocation_interlock_placement_pass.cpp
@@ -0,0 +1,493 @@
+// Copyright (c) 2023 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/invocation_interlock_placement_pass.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <functional>
+#include <optional>
+#include <queue>
+#include <stack>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "source/enum_set.h"
+#include "source/enum_string_mapping.h"
+#include "source/opt/ir_context.h"
+#include "source/opt/reflect.h"
+#include "source/spirv_target_env.h"
+#include "source/util/string_utils.h"
+
+namespace spvtools {
+namespace opt {
+
+namespace {
+constexpr uint32_t kEntryPointExecutionModelInIdx = 0;
+constexpr uint32_t kEntryPointFunctionIdInIdx = 1;
+constexpr uint32_t kFunctionCallFunctionIdInIdx = 0;
+}  // namespace
+
+bool InvocationInterlockPlacementPass::hasSingleNextBlock(uint32_t block_id,
+                                                          bool reverse_cfg) {
+  if (reverse_cfg) {
+    // We are traversing forward, so check whether there is a single successor.
+    BasicBlock* block = cfg()->block(block_id);
+
+    switch (block->tail()->opcode()) {
+      case spv::Op::OpBranchConditional:
+        return false;
+      case spv::Op::OpSwitch:
+        return block->tail()->NumInOperandWords() == 1;
+      default:
+        return !block->tail()->IsReturnOrAbort();
+    }
+  } else {
+    // We are traversing backward, so check whether there is a single
+    // predecessor.
+    return cfg()->preds(block_id).size() == 1;
+  }
+}
+
+void InvocationInterlockPlacementPass::forEachNext(
+    uint32_t block_id, bool reverse_cfg, std::function<void(uint32_t)> f) {
+  if (reverse_cfg) {
+    BasicBlock* block = cfg()->block(block_id);
+
+    block->ForEachSuccessorLabel([f](uint32_t succ_id) { f(succ_id); });
+  } else {
+    for (uint32_t pred_id : cfg()->preds(block_id)) {
+      f(pred_id);
+    }
+  }
+}
+
+void InvocationInterlockPlacementPass::addInstructionAtBlockBoundary(
+    BasicBlock* block, spv::Op opcode, bool at_end) {
+  if (at_end) {
+    assert(block->begin()->opcode() != spv::Op::OpPhi &&
+           "addInstructionAtBlockBoundary expects to be called with at_end == "
+           "true only if there is a single successor to block");
+    // Insert a begin instruction at the end of the block.
+    Instruction* begin_inst = new Instruction(context(), opcode);
+    begin_inst->InsertAfter(&*--block->tail());
+  } else {
+    assert(block->begin()->opcode() != spv::Op::OpPhi &&
+           "addInstructionAtBlockBoundary expects to be called with at_end == "
+           "false only if there is a single predecessor to block");
+    // Insert an end instruction at the beginning of the block.
+    Instruction* end_inst = new Instruction(context(), opcode);
+    end_inst->InsertBefore(&*block->begin());
+  }
+}
+
+bool InvocationInterlockPlacementPass::killDuplicateBegin(BasicBlock* block) {
+  bool found = false;
+
+  return context()->KillInstructionIf(
+      block->begin(), block->end(), [&found](Instruction* inst) {
+        if (inst->opcode() == spv::Op::OpBeginInvocationInterlockEXT) {
+          if (found) {
+            return true;
+          }
+          found = true;
+        }
+        return false;
+      });
+}
+
+bool InvocationInterlockPlacementPass::killDuplicateEnd(BasicBlock* block) {
+  std::vector<Instruction*> to_kill;
+  block->ForEachInst([&to_kill](Instruction* inst) {
+    if (inst->opcode() == spv::Op::OpEndInvocationInterlockEXT) {
+      to_kill.push_back(inst);
+    }
+  });
+
+  if (to_kill.size() <= 1) {
+    return false;
+  }
+
+  to_kill.pop_back();
+
+  for (Instruction* inst : to_kill) {
+    context()->KillInst(inst);
+  }
+
+  return true;
+}
+
+void InvocationInterlockPlacementPass::recordBeginOrEndInFunction(
+    Function* func) {
+  if (extracted_functions_.count(func)) {
+    return;
+  }
+
+  bool had_begin = false;
+  bool had_end = false;
+
+  func->ForEachInst([this, &had_begin, &had_end](Instruction* inst) {
+    switch (inst->opcode()) {
+      case spv::Op::OpBeginInvocationInterlockEXT:
+        had_begin = true;
+        break;
+      case spv::Op::OpEndInvocationInterlockEXT:
+        had_end = true;
+        break;
+      case spv::Op::OpFunctionCall: {
+        uint32_t function_id =
+            inst->GetSingleWordInOperand(kFunctionCallFunctionIdInIdx);
+        Function* inner_func = context()->GetFunction(function_id);
+        recordBeginOrEndInFunction(inner_func);
+        ExtractionResult result = extracted_functions_[inner_func];
+        had_begin = had_begin || result.had_begin;
+        had_end = had_end || result.had_end;
+        break;
+      }
+      default:
+        break;
+    }
+  });
+
+  ExtractionResult result = {had_begin, had_end};
+  extracted_functions_[func] = result;
+}
+
+bool InvocationInterlockPlacementPass::
+    removeBeginAndEndInstructionsFromFunction(Function* func) {
+  bool modified = false;
+  func->ForEachInst([this, &modified](Instruction* inst) {
+    switch (inst->opcode()) {
+      case spv::Op::OpBeginInvocationInterlockEXT:
+        context()->KillInst(inst);
+        modified = true;
+        break;
+      case spv::Op::OpEndInvocationInterlockEXT:
+        context()->KillInst(inst);
+        modified = true;
+        break;
+      default:
+        break;
+    }
+  });
+  return modified;
+}
+
+bool InvocationInterlockPlacementPass::extractInstructionsFromCalls(
+    std::vector<BasicBlock*> blocks) {
+  bool modified = false;
+
+  for (BasicBlock* block : blocks) {
+    block->ForEachInst([this, &modified](Instruction* inst) {
+      if (inst->opcode() == spv::Op::OpFunctionCall) {
+        uint32_t function_id =
+            inst->GetSingleWordInOperand(kFunctionCallFunctionIdInIdx);
+        Function* func = context()->GetFunction(function_id);
+        ExtractionResult result = extracted_functions_[func];
+
+        if (result.had_begin) {
+          Instruction* new_inst = new Instruction(
+              context(), spv::Op::OpBeginInvocationInterlockEXT);
+          new_inst->InsertBefore(inst);
+          modified = true;
+        }
+        if (result.had_end) {
+          Instruction* new_inst =
+              new Instruction(context(), spv::Op::OpEndInvocationInterlockEXT);
+          new_inst->InsertAfter(inst);
+          modified = true;
+        }
+      }
+    });
+  }
+  return modified;
+}
+
+void InvocationInterlockPlacementPass::recordExistingBeginAndEndBlock(
+    std::vector<BasicBlock*> blocks) {
+  for (BasicBlock* block : blocks) {
+    block->ForEachInst([this, block](Instruction* inst) {
+      switch (inst->opcode()) {
+        case spv::Op::OpBeginInvocationInterlockEXT:
+          begin_.insert(block->id());
+          break;
+        case spv::Op::OpEndInvocationInterlockEXT:
+          end_.insert(block->id());
+          break;
+        default:
+          break;
+      }
+    });
+  }
+}
+
+InvocationInterlockPlacementPass::BlockSet
+InvocationInterlockPlacementPass::computeReachableBlocks(
+    BlockSet& previous_inside, const BlockSet& starting_nodes,
+    bool reverse_cfg) {
+  BlockSet inside = starting_nodes;
+
+  std::deque<uint32_t> worklist;
+  worklist.insert(worklist.begin(), starting_nodes.begin(),
+                  starting_nodes.end());
+
+  while (!worklist.empty()) {
+    uint32_t block_id = worklist.front();
+    worklist.pop_front();
+
+    forEachNext(block_id, reverse_cfg,
+                [&inside, &previous_inside, &worklist](uint32_t next_id) {
+                  previous_inside.insert(next_id);
+                  if (inside.insert(next_id).second) {
+                    worklist.push_back(next_id);
+                  }
+                });
+  }
+
+  return inside;
+}
+
+bool InvocationInterlockPlacementPass::removeUnneededInstructions(
+    BasicBlock* block) {
+  bool modified = false;
+  if (!predecessors_after_begin_.count(block->id()) &&
+      after_begin_.count(block->id())) {
+    // None of the previous blocks are in the critical section, but this block
+    // is. This can only happen if this block already has at least one begin
+    // instruction. Leave the first begin instruction, and remove any others.
+    modified |= killDuplicateBegin(block);
+  } else if (predecessors_after_begin_.count(block->id())) {
+    // At least one previous block is in the critical section; remove all
+    // begin instructions in this block.
+    modified |= context()->KillInstructionIf(
+        block->begin(), block->end(), [](Instruction* inst) {
+          return inst->opcode() == spv::Op::OpBeginInvocationInterlockEXT;
+        });
+  }
+
+  if (!successors_before_end_.count(block->id()) &&
+      before_end_.count(block->id())) {
+    // Same as above
+    modified |= killDuplicateEnd(block);
+  } else if (successors_before_end_.count(block->id())) {
+    modified |= context()->KillInstructionIf(
+        block->begin(), block->end(), [](Instruction* inst) {
+          return inst->opcode() == spv::Op::OpEndInvocationInterlockEXT;
+        });
+  }
+  return modified;
+}
+
+BasicBlock* InvocationInterlockPlacementPass::splitEdge(BasicBlock* block,
+                                                        uint32_t succ_id) {
+  // Create a new block to replace the critical edge.
+  auto new_succ_temp = MakeUnique<BasicBlock>(
+      MakeUnique<Instruction>(context(), spv::Op::OpLabel, 0, TakeNextId(),
+                              std::initializer_list<Operand>{}));
+  auto* new_succ = new_succ_temp.get();
+
+  // Insert the new block into the function.
+  block->GetParent()->InsertBasicBlockAfter(std::move(new_succ_temp), block);
+
+  new_succ->AddInstruction(MakeUnique<Instruction>(
+      context(), spv::Op::OpBranch, 0, 0,
+      std::initializer_list<Operand>{
+          Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {succ_id})}));
+
+  assert(block->tail()->opcode() == spv::Op::OpBranchConditional ||
+         block->tail()->opcode() == spv::Op::OpSwitch);
+
+  // Update the first branch to successor to instead branch to
+  // the new successor. If there are multiple edges, we arbitrarily choose the
+  // first time it appears in the list. The other edges to `succ_id` will have
+  // to be split by another call to `splitEdge`.
+  block->tail()->WhileEachInId([new_succ, succ_id](uint32_t* branch_id) {
+    if (*branch_id == succ_id) {
+      *branch_id = new_succ->id();
+      return false;
+    }
+    return true;
+  });
+
+  return new_succ;
+}
+
+bool InvocationInterlockPlacementPass::placeInstructionsForEdge(
+    BasicBlock* block, uint32_t next_id, BlockSet& inside,
+    BlockSet& previous_inside, spv::Op opcode, bool reverse_cfg) {
+  bool modified = false;
+
+  if (previous_inside.count(next_id) && !inside.count(block->id())) {
+    // This block is not in the critical section but the next has at least one
+    // other previous block that is, so this block should be enter it as well.
+    // We need to add begin or end instructions to the edge.
+
+    modified = true;
+
+    if (hasSingleNextBlock(block->id(), reverse_cfg)) {
+      // This is the only next block.
+
+      // Additionally, because `next_id` is in `previous_inside`, we know that
+      // `next_id` has at least one previous block in `inside`. And because
+      // 'block` is not in `inside`, that means the `next_id` has to have at
+      // least one other previous block in `inside`.
+
+      // This is solely for a debug assertion. It is essentially recomputing the
+      // value of `previous_inside` to verify that it was computed correctly
+      // such that the above statement is true.
+      bool next_has_previous_inside = false;
+      // By passing !reverse_cfg to forEachNext, we are actually iterating over
+      // the previous blocks.
+      forEachNext(next_id, !reverse_cfg,
+                  [&next_has_previous_inside, inside](uint32_t previous_id) {
+                    if (inside.count(previous_id)) {
+                      next_has_previous_inside = true;
+                    }
+                  });
+      assert(next_has_previous_inside &&
+             "`previous_inside` must be the set of blocks with at least one "
+             "previous block in `inside`");
+
+      addInstructionAtBlockBoundary(block, opcode, reverse_cfg);
+    } else {
+      // This block has multiple next blocks. Split the edge and insert the
+      // instruction in the new next block.
+      BasicBlock* new_branch;
+      if (reverse_cfg) {
+        new_branch = splitEdge(block, next_id);
+      } else {
+        new_branch = splitEdge(cfg()->block(next_id), block->id());
+      }
+
+      auto inst = new Instruction(context(), opcode);
+      inst->InsertBefore(&*new_branch->tail());
+    }
+  }
+
+  return modified;
+}
+
+bool InvocationInterlockPlacementPass::placeInstructions(BasicBlock* block) {
+  bool modified = false;
+
+  block->ForEachSuccessorLabel([this, block, &modified](uint32_t succ_id) {
+    modified |= placeInstructionsForEdge(
+        block, succ_id, after_begin_, predecessors_after_begin_,
+        spv::Op::OpBeginInvocationInterlockEXT, /* reverse_cfg= */ true);
+    modified |= placeInstructionsForEdge(cfg()->block(succ_id), block->id(),
+                                         before_end_, successors_before_end_,
+                                         spv::Op::OpEndInvocationInterlockEXT,
+                                         /* reverse_cfg= */ false);
+  });
+
+  return modified;
+}
+
+bool InvocationInterlockPlacementPass::processFragmentShaderEntry(
+    Function* entry_func) {
+  bool modified = false;
+
+  // Save the original order of blocks in the function, so we don't iterate over
+  // newly-added blocks.
+  std::vector<BasicBlock*> original_blocks;
+  for (auto bi = entry_func->begin(); bi != entry_func->end(); ++bi) {
+    original_blocks.push_back(&*bi);
+  }
+
+  modified |= extractInstructionsFromCalls(original_blocks);
+  recordExistingBeginAndEndBlock(original_blocks);
+
+  after_begin_ = computeReachableBlocks(predecessors_after_begin_, begin_,
+                                        /* reverse_cfg= */ true);
+  before_end_ = computeReachableBlocks(successors_before_end_, end_,
+                                       /* reverse_cfg= */ false);
+
+  for (BasicBlock* block : original_blocks) {
+    modified |= removeUnneededInstructions(block);
+    modified |= placeInstructions(block);
+  }
+  return modified;
+}
+
+bool InvocationInterlockPlacementPass::isFragmentShaderInterlockEnabled() {
+  if (!context()->get_feature_mgr()->HasExtension(
+          kSPV_EXT_fragment_shader_interlock)) {
+    return false;
+  }
+
+  if (context()->get_feature_mgr()->HasCapability(
+          spv::Capability::FragmentShaderSampleInterlockEXT)) {
+    return true;
+  }
+
+  if (context()->get_feature_mgr()->HasCapability(
+          spv::Capability::FragmentShaderPixelInterlockEXT)) {
+    return true;
+  }
+
+  if (context()->get_feature_mgr()->HasCapability(
+          spv::Capability::FragmentShaderShadingRateInterlockEXT)) {
+    return true;
+  }
+
+  return false;
+}
+
+Pass::Status InvocationInterlockPlacementPass::Process() {
+  // Skip this pass if the necessary extension or capability is missing
+  if (!isFragmentShaderInterlockEnabled()) {
+    return Status::SuccessWithoutChange;
+  }
+
+  bool modified = false;
+
+  std::unordered_set<Function*> entry_points;
+  for (Instruction& entry_inst : context()->module()->entry_points()) {
+    uint32_t entry_id =
+        entry_inst.GetSingleWordInOperand(kEntryPointFunctionIdInIdx);
+    entry_points.insert(context()->GetFunction(entry_id));
+  }
+
+  for (auto fi = context()->module()->begin(); fi != context()->module()->end();
+       ++fi) {
+    Function* func = &*fi;
+    recordBeginOrEndInFunction(func);
+    if (!entry_points.count(func) && extracted_functions_.count(func)) {
+      modified |= removeBeginAndEndInstructionsFromFunction(func);
+    }
+  }
+
+  for (Instruction& entry_inst : context()->module()->entry_points()) {
+    uint32_t entry_id =
+        entry_inst.GetSingleWordInOperand(kEntryPointFunctionIdInIdx);
+    Function* entry_func = context()->GetFunction(entry_id);
+
+    auto execution_model = spv::ExecutionModel(
+        entry_inst.GetSingleWordInOperand(kEntryPointExecutionModelInIdx));
+
+    if (execution_model != spv::ExecutionModel::Fragment) {
+      continue;
+    }
+
+    modified |= processFragmentShaderEntry(entry_func);
+  }
+
+  return modified ? Pass::Status::SuccessWithChange
+                  : Pass::Status::SuccessWithoutChange;
+}
+
+}  // namespace opt
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/opt/invocation_interlock_placement_pass.h b/third_party/SPIRV-Tools/source/opt/invocation_interlock_placement_pass.h
new file mode 100644
index 0000000..4e85be8
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/invocation_interlock_placement_pass.h
@@ -0,0 +1,158 @@
+// Copyright (c) 2023 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_DEDUPE_INTERLOCK_INVOCATION_PASS_H_
+#define SOURCE_OPT_DEDUPE_INTERLOCK_INVOCATION_PASS_H_
+
+#include <algorithm>
+#include <array>
+#include <functional>
+#include <optional>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "source/enum_set.h"
+#include "source/extensions.h"
+#include "source/opt/ir_context.h"
+#include "source/opt/module.h"
+#include "source/opt/pass.h"
+#include "source/spirv_target_env.h"
+
+namespace spvtools {
+namespace opt {
+
+// This pass will ensure that an entry point will only have at most one
+// OpBeginInterlockInvocationEXT and one OpEndInterlockInvocationEXT, in that
+// order
+class InvocationInterlockPlacementPass : public Pass {
+ public:
+  InvocationInterlockPlacementPass() {}
+  InvocationInterlockPlacementPass(const InvocationInterlockPlacementPass&) =
+      delete;
+  InvocationInterlockPlacementPass(InvocationInterlockPlacementPass&&) = delete;
+
+  const char* name() const override { return "dedupe-interlock-invocation"; }
+  Status Process() override;
+
+ private:
+  using BlockSet = std::unordered_set<uint32_t>;
+
+  // Specifies whether a function originally had a begin or end instruction.
+  struct ExtractionResult {
+    bool had_begin : 1;
+    bool had_end : 2;
+  };
+
+  // Check if a block has only a single next block, depending on the directing
+  // that we are traversing the CFG. If reverse_cfg is true, we are walking
+  // forward through the CFG, and will return if the block has only one
+  // successor. Otherwise, we are walking backward through the CFG, and will
+  // return if the block has only one predecessor.
+  bool hasSingleNextBlock(uint32_t block_id, bool reverse_cfg);
+
+  // Iterate over each of a block's predecessors or successors, depending on
+  // direction. If reverse_cfg is true, we are walking forward through the CFG,
+  // and need to iterate over the successors. Otherwise, we are walking backward
+  // through the CFG, and need to iterate over the predecessors.
+  void forEachNext(uint32_t block_id, bool reverse_cfg,
+                   std::function<void(uint32_t)> f);
+
+  // Add either a begin or end instruction to the edge of the basic block. If
+  // at_end is true, add the instruction to the end of the block; otherwise add
+  // the instruction to the beginning of the basic block.
+  void addInstructionAtBlockBoundary(BasicBlock* block, spv::Op opcode,
+                                     bool at_end);
+
+  // Remove every OpBeginInvocationInterlockEXT instruction in block after the
+  // first. Returns whether any instructions were removed.
+  bool killDuplicateBegin(BasicBlock* block);
+  // Remove every OpBeginInvocationInterlockEXT instruction in block before the
+  // last. Returns whether any instructions were removed.
+  bool killDuplicateEnd(BasicBlock* block);
+
+  // Records whether a function will potentially execute a begin or end
+  // instruction.
+  void recordBeginOrEndInFunction(Function* func);
+
+  // Recursively removes any begin or end instructions from func and any
+  // function func calls. Returns whether any instructions were removed.
+  bool removeBeginAndEndInstructionsFromFunction(Function* func);
+
+  // For every function call in any of the passed blocks, move any begin or end
+  // instructions outside of the function call. Returns whether any extractions
+  // occurred.
+  bool extractInstructionsFromCalls(std::vector<BasicBlock*> blocks);
+
+  // Finds the sets of blocks that contain OpBeginInvocationInterlockEXT and
+  // OpEndInvocationInterlockEXT, storing them in the member variables begin_
+  // and end_ respectively.
+  void recordExistingBeginAndEndBlock(std::vector<BasicBlock*> blocks);
+
+  // Compute the set of blocks including or after the barrier instruction, and
+  // the set of blocks with any previous blocks inside the barrier instruction.
+  // If reverse_cfg is true, move forward through the CFG, computing
+  // after_begin_ and predecessors_after_begin_computing after_begin_ and
+  // predecessors_after_begin_, otherwise, move backward through the CFG,
+  // computing before_end_ and successors_before_end_.
+  BlockSet computeReachableBlocks(BlockSet& in_set,
+                                  const BlockSet& starting_nodes,
+                                  bool reverse_cfg);
+
+  // Remove unneeded begin and end instructions in block.
+  bool removeUnneededInstructions(BasicBlock* block);
+
+  // Given a block which branches to multiple successors, and a specific
+  // successor, creates a new empty block, and update the branch instruction to
+  // branch to the new block instead.
+  BasicBlock* splitEdge(BasicBlock* block, uint32_t succ_id);
+
+  // For the edge from block to next_id, places a begin or end instruction on
+  // the edge, based on the direction we are walking the CFG, specified in
+  // reverse_cfg.
+  bool placeInstructionsForEdge(BasicBlock* block, uint32_t next_id,
+                                BlockSet& inside, BlockSet& previous_inside,
+                                spv::Op opcode, bool reverse_cfg);
+  // Calls placeInstructionsForEdge for each edge in block.
+  bool placeInstructions(BasicBlock* block);
+
+  // Processes a single fragment shader entry function.
+  bool processFragmentShaderEntry(Function* entry_func);
+
+  // Returns whether the module has the SPV_EXT_fragment_shader_interlock
+  // extension and one of the FragmentShader*InterlockEXT capabilities.
+  bool isFragmentShaderInterlockEnabled();
+
+  // Maps a function to whether that function originally held a begin or end
+  // instruction.
+  std::unordered_map<Function*, ExtractionResult> extracted_functions_;
+
+  // The set of blocks which have an OpBeginInvocationInterlockEXT instruction.
+  BlockSet begin_;
+  // The set of blocks which have an OpEndInvocationInterlockEXT instruction.
+  BlockSet end_;
+  // The set of blocks which either have a begin instruction, or have a
+  // predecessor which has a begin instruction.
+  BlockSet after_begin_;
+  // The set of blocks which either have an end instruction, or have a successor
+  // which have an end instruction.
+  BlockSet before_end_;
+  // The set of blocks which have a predecessor in after_begin_.
+  BlockSet predecessors_after_begin_;
+  // The set of blocks which have a successor in before_end_.
+  BlockSet successors_before_end_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+#endif  // SOURCE_OPT_DEDUPE_INTERLOCK_INVOCATION_PASS_H_
diff --git a/third_party/SPIRV-Tools/source/opt/ir_builder.h b/third_party/SPIRV-Tools/source/opt/ir_builder.h
index 48e08ee..f3e0afc 100644
--- a/third_party/SPIRV-Tools/source/opt/ir_builder.h
+++ b/third_party/SPIRV-Tools/source/opt/ir_builder.h
@@ -440,6 +440,22 @@
     return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
   }
 
+  Instruction* GetBoolConstant(bool value) {
+    analysis::Bool type;
+    uint32_t type_id = GetContext()->get_type_mgr()->GetTypeInstruction(&type);
+    analysis::Type* rebuilt_type =
+        GetContext()->get_type_mgr()->GetType(type_id);
+    uint32_t word = value;
+    const analysis::Constant* constant =
+        GetContext()->get_constant_mgr()->GetConstant(rebuilt_type, {word});
+    return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
+  }
+
+  uint32_t GetBoolConstantId(bool value) {
+    Instruction* inst = GetBoolConstant(value);
+    return (inst != nullptr ? inst->result_id() : 0);
+  }
+
   Instruction* AddCompositeExtract(uint32_t type, uint32_t id_of_composite,
                                    const std::vector<uint32_t>& index_list) {
     std::vector<Operand> operands;
diff --git a/third_party/SPIRV-Tools/source/opt/ir_context.cpp b/third_party/SPIRV-Tools/source/opt/ir_context.cpp
index 26501c2..d864b7c 100644
--- a/third_party/SPIRV-Tools/source/opt/ir_context.cpp
+++ b/third_party/SPIRV-Tools/source/opt/ir_context.cpp
@@ -88,6 +88,9 @@
   if (set & kAnalysisDebugInfo) {
     BuildDebugInfoManager();
   }
+  if (set & kAnalysisLiveness) {
+    BuildLivenessManager();
+  }
 }
 
 void IRContext::InvalidateAnalysesExceptFor(
@@ -220,6 +223,28 @@
   return next_instruction;
 }
 
+bool IRContext::KillInstructionIf(Module::inst_iterator begin,
+                                  Module::inst_iterator end,
+                                  std::function<bool(Instruction*)> condition) {
+  bool removed = false;
+  for (auto it = begin; it != end;) {
+    if (!condition(&*it)) {
+      ++it;
+      continue;
+    }
+
+    removed = true;
+    // `it` is an iterator on an intrusive list. Next is invalidated on the
+    // current node when an instruction is killed. The iterator must be moved
+    // forward before deleting the node.
+    auto instruction = &*it;
+    ++it;
+    KillInst(instruction);
+  }
+
+  return removed;
+}
+
 void IRContext::CollectNonSemanticTree(
     Instruction* inst, std::unordered_set<Instruction*>* to_kill) {
   if (!inst->HasResultId()) return;
@@ -251,6 +276,36 @@
   return false;
 }
 
+bool IRContext::RemoveCapability(spv::Capability capability) {
+  const bool removed = KillInstructionIf(
+      module()->capability_begin(), module()->capability_end(),
+      [capability](Instruction* inst) {
+        return static_cast<spv::Capability>(inst->GetSingleWordOperand(0)) ==
+               capability;
+      });
+
+  if (removed && feature_mgr_ != nullptr) {
+    feature_mgr_->RemoveCapability(capability);
+  }
+
+  return removed;
+}
+
+bool IRContext::RemoveExtension(Extension extension) {
+  const std::string_view extensionName = ExtensionToString(extension);
+  const bool removed = KillInstructionIf(
+      module()->extension_begin(), module()->extension_end(),
+      [&extensionName](Instruction* inst) {
+        return inst->GetOperand(0).AsString() == extensionName;
+      });
+
+  if (removed && feature_mgr_ != nullptr) {
+    feature_mgr_->RemoveExtension(extension);
+  }
+
+  return removed;
+}
+
 bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
   return ReplaceAllUsesWithPredicate(before, after,
                                      [](Instruction*) { return true; });
@@ -718,9 +773,9 @@
 }
 
 void IRContext::InitializeCombinators() {
-  get_feature_mgr()->GetCapabilities()->ForEach([this](spv::Capability cap) {
-    AddCombinatorsForCapability(uint32_t(cap));
-  });
+  for (auto capability : get_feature_mgr()->GetCapabilities()) {
+    AddCombinatorsForCapability(uint32_t(capability));
+  }
 
   for (auto& extension : module()->ext_inst_imports()) {
     AddCombinatorsForExtension(&extension);
diff --git a/third_party/SPIRV-Tools/source/opt/ir_context.h b/third_party/SPIRV-Tools/source/opt/ir_context.h
index 8419ee7..ef7c458 100644
--- a/third_party/SPIRV-Tools/source/opt/ir_context.h
+++ b/third_party/SPIRV-Tools/source/opt/ir_context.h
@@ -27,6 +27,7 @@
 #include <vector>
 
 #include "source/assembly_grammar.h"
+#include "source/enum_string_mapping.h"
 #include "source/opt/cfg.h"
 #include "source/opt/constants.h"
 #include "source/opt/debug_info_manager.h"
@@ -83,7 +84,7 @@
     kAnalysisTypes = 1 << 15,
     kAnalysisDebugInfo = 1 << 16,
     kAnalysisLiveness = 1 << 17,
-    kAnalysisEnd = 1 << 17
+    kAnalysisEnd = 1 << 18
   };
 
   using ProcessFunction = std::function<bool(Function*)>;
@@ -153,13 +154,19 @@
   inline IteratorRange<Module::inst_iterator> capabilities();
   inline IteratorRange<Module::const_inst_iterator> capabilities() const;
 
+  // Iterators for extensions instructions contained in this module.
+  inline Module::inst_iterator extension_begin();
+  inline Module::inst_iterator extension_end();
+  inline IteratorRange<Module::inst_iterator> extensions();
+  inline IteratorRange<Module::const_inst_iterator> extensions() const;
+
   // Iterators for types, constants and global variables instructions.
   inline Module::inst_iterator types_values_begin();
   inline Module::inst_iterator types_values_end();
   inline IteratorRange<Module::inst_iterator> types_values();
   inline IteratorRange<Module::const_inst_iterator> types_values() const;
 
-  // Iterators for extension instructions contained in this module.
+  // Iterators for ext_inst import instructions contained in this module.
   inline Module::inst_iterator ext_inst_import_begin();
   inline Module::inst_iterator ext_inst_import_end();
   inline IteratorRange<Module::inst_iterator> ext_inst_imports();
@@ -204,17 +211,26 @@
 
   // Add |capability| to the module, if it is not already enabled.
   inline void AddCapability(spv::Capability capability);
-
   // Appends a capability instruction to this module.
   inline void AddCapability(std::unique_ptr<Instruction>&& c);
+  // Removes instruction declaring `capability` from this module.
+  // Returns true if the capability was removed, false otherwise.
+  bool RemoveCapability(spv::Capability capability);
+
   // Appends an extension instruction to this module.
   inline void AddExtension(const std::string& ext_name);
   inline void AddExtension(std::unique_ptr<Instruction>&& e);
+  // Removes instruction declaring `extension` from this module.
+  // Returns true if the extension was removed, false otherwise.
+  bool RemoveExtension(Extension extension);
+
   // Appends an extended instruction set instruction to this module.
   inline void AddExtInstImport(const std::string& name);
   inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
   // Set the memory model for this module.
   inline void SetMemoryModel(std::unique_ptr<Instruction>&& m);
+  // Get the memory model for this module.
+  inline const Instruction* GetMemoryModel() const;
   // Appends an entry point instruction to this module.
   inline void AddEntryPoint(std::unique_ptr<Instruction>&& e);
   // Appends an execution mode instruction to this module.
@@ -238,6 +254,8 @@
   inline void AddType(std::unique_ptr<Instruction>&& t);
   // Appends a constant, global variable, or OpUndef instruction to this module.
   inline void AddGlobalValue(std::unique_ptr<Instruction>&& v);
+  // Prepends a function declaration to this module.
+  inline void AddFunctionDeclaration(std::unique_ptr<Function>&& f);
   // Appends a function to this module.
   inline void AddFunction(std::unique_ptr<Function>&& f);
 
@@ -422,6 +440,15 @@
   // instruction exists.
   Instruction* KillInst(Instruction* inst);
 
+  // Deletes all the instruction in the range [`begin`; `end`[, for which the
+  // unary predicate `condition` returned true.
+  // Returns true if at least one instruction was removed, false otherwise.
+  //
+  // Pointer and iterator pointing to the deleted instructions become invalid.
+  // However other pointers and iterators are still valid.
+  bool KillInstructionIf(Module::inst_iterator begin, Module::inst_iterator end,
+                         std::function<bool(Instruction*)> condition);
+
   // Collects the non-semantic instruction tree that uses |inst|'s result id
   // to be killed later.
   void CollectNonSemanticTree(Instruction* inst,
@@ -772,7 +799,8 @@
 
   // Analyzes the features in the owned module. Builds the manager if required.
   void AnalyzeFeatures() {
-    feature_mgr_ = MakeUnique<FeatureManager>(grammar_);
+    feature_mgr_ =
+        std::unique_ptr<FeatureManager>(new FeatureManager(grammar_));
     feature_mgr_->Analyze(module());
   }
 
@@ -964,6 +992,22 @@
   return ((const Module*)module())->capabilities();
 }
 
+Module::inst_iterator IRContext::extension_begin() {
+  return module()->extension_begin();
+}
+
+Module::inst_iterator IRContext::extension_end() {
+  return module()->extension_end();
+}
+
+IteratorRange<Module::inst_iterator> IRContext::extensions() {
+  return module()->extensions();
+}
+
+IteratorRange<Module::const_inst_iterator> IRContext::extensions() const {
+  return ((const Module*)module())->extensions();
+}
+
 Module::inst_iterator IRContext::types_values_begin() {
   return module()->types_values_begin();
 }
@@ -1114,6 +1158,10 @@
   module()->SetMemoryModel(std::move(m));
 }
 
+const Instruction* IRContext::GetMemoryModel() const {
+  return module()->GetMemoryModel();
+}
+
 void IRContext::AddEntryPoint(std::unique_ptr<Instruction>&& e) {
   module()->AddEntryPoint(std::move(e));
 }
@@ -1173,6 +1221,10 @@
   module()->AddGlobalValue(std::move(v));
 }
 
+void IRContext::AddFunctionDeclaration(std::unique_ptr<Function>&& f) {
+  module()->AddFunctionDeclaration(std::move(f));
+}
+
 void IRContext::AddFunction(std::unique_ptr<Function>&& f) {
   module()->AddFunction(std::move(f));
 }
diff --git a/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.cpp b/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.cpp
index 6ec0c2d..7ba75cb 100644
--- a/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.cpp
@@ -420,13 +420,16 @@
        "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing",
        "SPV_NV_fragment_shader_barycentric",
        "SPV_NV_compute_shader_derivatives", "SPV_NV_shader_image_footprint",
-       "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing",
-       "SPV_KHR_ray_tracing", "SPV_KHR_ray_query",
+       "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_EXT_mesh_shader",
+       "SPV_NV_ray_tracing", "SPV_KHR_ray_tracing", "SPV_KHR_ray_query",
        "SPV_EXT_fragment_invocation_density", "SPV_KHR_terminate_invocation",
        "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product",
        "SPV_EXT_shader_image_int64", "SPV_KHR_non_semantic_info",
        "SPV_KHR_uniform_group_instructions",
-       "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model"});
+       "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model",
+       "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add",
+       "SPV_EXT_fragment_shader_interlock",
+       "SPV_NV_compute_shader_derivatives"});
 }
 
 bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds(
diff --git a/third_party/SPIRV-Tools/source/opt/local_single_block_elim_pass.cpp b/third_party/SPIRV-Tools/source/opt/local_single_block_elim_pass.cpp
index 063d1b9..d7a9295 100644
--- a/third_party/SPIRV-Tools/source/opt/local_single_block_elim_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/local_single_block_elim_pass.cpp
@@ -273,11 +273,13 @@
                                 "SPV_NV_shader_image_footprint",
                                 "SPV_NV_shading_rate",
                                 "SPV_NV_mesh_shader",
+                                "SPV_EXT_mesh_shader",
                                 "SPV_NV_ray_tracing",
                                 "SPV_KHR_ray_tracing",
                                 "SPV_KHR_ray_query",
                                 "SPV_EXT_fragment_invocation_density",
                                 "SPV_EXT_physical_storage_buffer",
+                                "SPV_KHR_physical_storage_buffer",
                                 "SPV_KHR_terminate_invocation",
                                 "SPV_KHR_subgroup_uniform_control_flow",
                                 "SPV_KHR_integer_dot_product",
@@ -285,7 +287,11 @@
                                 "SPV_KHR_non_semantic_info",
                                 "SPV_KHR_uniform_group_instructions",
                                 "SPV_KHR_fragment_shader_barycentric",
-                                "SPV_KHR_vulkan_memory_model"});
+                                "SPV_KHR_vulkan_memory_model",
+                                "SPV_NV_bindless_texture",
+                                "SPV_EXT_shader_atomic_float_add",
+                                "SPV_EXT_fragment_shader_interlock",
+                                "SPV_NV_compute_shader_derivatives"});
 }
 
 }  // namespace opt
diff --git a/third_party/SPIRV-Tools/source/opt/local_single_store_elim_pass.cpp b/third_party/SPIRV-Tools/source/opt/local_single_store_elim_pass.cpp
index a0de44c..7cd6b0e 100644
--- a/third_party/SPIRV-Tools/source/opt/local_single_store_elim_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/local_single_store_elim_pass.cpp
@@ -124,10 +124,12 @@
                                 "SPV_NV_shader_image_footprint",
                                 "SPV_NV_shading_rate",
                                 "SPV_NV_mesh_shader",
+                                "SPV_EXT_mesh_shader",
                                 "SPV_NV_ray_tracing",
                                 "SPV_KHR_ray_query",
                                 "SPV_EXT_fragment_invocation_density",
                                 "SPV_EXT_physical_storage_buffer",
+                                "SPV_KHR_physical_storage_buffer",
                                 "SPV_KHR_terminate_invocation",
                                 "SPV_KHR_subgroup_uniform_control_flow",
                                 "SPV_KHR_integer_dot_product",
@@ -135,7 +137,11 @@
                                 "SPV_KHR_non_semantic_info",
                                 "SPV_KHR_uniform_group_instructions",
                                 "SPV_KHR_fragment_shader_barycentric",
-                                "SPV_KHR_vulkan_memory_model"});
+                                "SPV_KHR_vulkan_memory_model",
+                                "SPV_NV_bindless_texture",
+                                "SPV_EXT_shader_atomic_float_add",
+                                "SPV_EXT_fragment_shader_interlock",
+                                "SPV_NV_compute_shader_derivatives"});
 }
 bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
   std::vector<Instruction*> users;
diff --git a/third_party/SPIRV-Tools/source/opt/log.h b/third_party/SPIRV-Tools/source/opt/log.h
index 6805100..4fb66fd 100644
--- a/third_party/SPIRV-Tools/source/opt/log.h
+++ b/third_party/SPIRV-Tools/source/opt/log.h
@@ -23,7 +23,7 @@
 #include "spirv-tools/libspirv.hpp"
 
 // Asserts the given condition is true. Otherwise, sends a message to the
-// consumer and exits the problem with failure code. Accepts the following
+// consumer and exits the program with failure code. Accepts the following
 // formats:
 //
 // SPIRV_ASSERT(<message-consumer>, <condition-expression>);
@@ -36,7 +36,9 @@
 #if !defined(NDEBUG)
 #define SPIRV_ASSERT(consumer, ...) SPIRV_ASSERT_IMPL(consumer, __VA_ARGS__)
 #else
-#define SPIRV_ASSERT(consumer, ...)
+// Adding a use to avoid errors in the release build related to unused
+// consumers.
+#define SPIRV_ASSERT(consumer, ...) (void)(consumer)
 #endif
 
 // Logs a debug message to the consumer. Accepts the following formats:
@@ -49,26 +51,11 @@
 #if !defined(NDEBUG) && defined(SPIRV_LOG_DEBUG)
 #define SPIRV_DEBUG(consumer, ...) SPIRV_DEBUG_IMPL(consumer, __VA_ARGS__)
 #else
-#define SPIRV_DEBUG(consumer, ...)
+// Adding a use to avoid errors in the release build related to unused
+// consumers.
+#define SPIRV_DEBUG(consumer, ...) (void)(consumer)
 #endif
 
-// Logs an error message to the consumer saying the given feature is
-// unimplemented.
-#define SPIRV_UNIMPLEMENTED(consumer, feature)                \
-  do {                                                        \
-    spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
-                  {static_cast<size_t>(__LINE__), 0, 0},      \
-                  "unimplemented: " feature);                 \
-  } while (0)
-
-// Logs an error message to the consumer saying the code location
-// should be unreachable.
-#define SPIRV_UNREACHABLE(consumer)                                      \
-  do {                                                                   \
-    spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__,            \
-                  {static_cast<size_t>(__LINE__), 0, 0}, "unreachable"); \
-  } while (0)
-
 // Helper macros for concatenating arguments.
 #define SPIRV_CONCATENATE(a, b) SPIRV_CONCATENATE_(a, b)
 #define SPIRV_CONCATENATE_(a, b) a##b
diff --git a/third_party/SPIRV-Tools/source/opt/mem_pass.cpp b/third_party/SPIRV-Tools/source/opt/mem_pass.cpp
index 9f95785..9972c4f 100644
--- a/third_party/SPIRV-Tools/source/opt/mem_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/mem_pass.cpp
@@ -76,6 +76,11 @@
 bool MemPass::IsPtr(uint32_t ptrId) {
   uint32_t varId = ptrId;
   Instruction* ptrInst = get_def_use_mgr()->GetDef(varId);
+  if (ptrInst->opcode() == spv::Op::OpFunction) {
+    // A function is not a pointer, but it's return type could be, which will
+    // erroneously lead to this function returning true later on
+    return false;
+  }
   while (ptrInst->opcode() == spv::Op::OpCopyObject) {
     varId = ptrInst->GetSingleWordInOperand(kCopyObjectOperandInIdx);
     ptrInst = get_def_use_mgr()->GetDef(varId);
diff --git a/third_party/SPIRV-Tools/source/opt/modify_maximal_reconvergence.cpp b/third_party/SPIRV-Tools/source/opt/modify_maximal_reconvergence.cpp
new file mode 100644
index 0000000..dd79b62
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/modify_maximal_reconvergence.cpp
@@ -0,0 +1,103 @@
+// Copyright (c) 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "modify_maximal_reconvergence.h"
+
+#include "source/opt/ir_context.h"
+#include "source/util/make_unique.h"
+
+namespace spvtools {
+namespace opt {
+
+Pass::Status ModifyMaximalReconvergence::Process() {
+  bool changed = false;
+  if (add_) {
+    changed = AddMaximalReconvergence();
+  } else {
+    changed = RemoveMaximalReconvergence();
+  }
+  return changed ? Pass::Status::SuccessWithChange
+                 : Pass::Status::SuccessWithoutChange;
+}
+
+bool ModifyMaximalReconvergence::AddMaximalReconvergence() {
+  bool changed = false;
+  bool has_extension = false;
+  bool has_shader =
+      context()->get_feature_mgr()->HasCapability(spv::Capability::Shader);
+  for (auto extension : context()->extensions()) {
+    if (extension.GetOperand(0).AsString() == "SPV_KHR_maximal_reconvergence") {
+      has_extension = true;
+      break;
+    }
+  }
+
+  std::unordered_set<uint32_t> entry_points_with_mode;
+  for (auto mode : get_module()->execution_modes()) {
+    if (spv::ExecutionMode(mode.GetSingleWordInOperand(1)) ==
+        spv::ExecutionMode::MaximallyReconvergesKHR) {
+      entry_points_with_mode.insert(mode.GetSingleWordInOperand(0));
+    }
+  }
+
+  for (auto entry_point : get_module()->entry_points()) {
+    const uint32_t id = entry_point.GetSingleWordInOperand(1);
+    if (!entry_points_with_mode.count(id)) {
+      changed = true;
+      if (!has_extension) {
+        context()->AddExtension("SPV_KHR_maximal_reconvergence");
+        has_extension = true;
+      }
+      if (!has_shader) {
+        context()->AddCapability(spv::Capability::Shader);
+        has_shader = true;
+      }
+      context()->AddExecutionMode(MakeUnique<Instruction>(
+          context(), spv::Op::OpExecutionMode, 0, 0,
+          std::initializer_list<Operand>{
+              {SPV_OPERAND_TYPE_ID, {id}},
+              {SPV_OPERAND_TYPE_EXECUTION_MODE,
+               {static_cast<uint32_t>(
+                   spv::ExecutionMode::MaximallyReconvergesKHR)}}}));
+      entry_points_with_mode.insert(id);
+    }
+  }
+
+  return changed;
+}
+
+bool ModifyMaximalReconvergence::RemoveMaximalReconvergence() {
+  bool changed = false;
+  std::vector<Instruction*> to_remove;
+  Instruction* mode = &*get_module()->execution_mode_begin();
+  while (mode) {
+    if (mode->opcode() != spv::Op::OpExecutionMode &&
+        mode->opcode() != spv::Op::OpExecutionModeId) {
+      break;
+    }
+    if (spv::ExecutionMode(mode->GetSingleWordInOperand(1)) ==
+        spv::ExecutionMode::MaximallyReconvergesKHR) {
+      mode = context()->KillInst(mode);
+      changed = true;
+    } else {
+      mode = mode->NextNode();
+    }
+  }
+
+  changed |=
+      context()->RemoveExtension(Extension::kSPV_KHR_maximal_reconvergence);
+  return changed;
+}
+}  // namespace opt
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/opt/modify_maximal_reconvergence.h b/third_party/SPIRV-Tools/source/opt/modify_maximal_reconvergence.h
new file mode 100644
index 0000000..8d9a698
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/modify_maximal_reconvergence.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_
+#define LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_
+
+#include "pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// Modifies entry points to either add or remove MaximallyReconvergesKHR
+//
+// This pass will either add or remove MaximallyReconvergesKHR to all entry
+// points in the module. When adding the execution mode, it does not attempt to
+// determine whether any ray tracing invocation repack instructions might be
+// executed because it is a runtime restriction. That is left to the user.
+class ModifyMaximalReconvergence : public Pass {
+ public:
+  const char* name() const override { return "modify-maximal-reconvergence"; }
+  Status Process() override;
+
+  explicit ModifyMaximalReconvergence(bool add = true) : Pass(), add_(add) {}
+
+  IRContext::Analysis GetPreservedAnalyses() override {
+    return IRContext::kAnalysisDefUse |
+           IRContext::kAnalysisInstrToBlockMapping |
+           IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
+           IRContext::kAnalysisCFG | IRContext::kAnalysisNameMap |
+           IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
+  }
+
+ private:
+  bool AddMaximalReconvergence();
+  bool RemoveMaximalReconvergence();
+
+  bool add_;
+};
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_
diff --git a/third_party/SPIRV-Tools/source/opt/module.h b/third_party/SPIRV-Tools/source/opt/module.h
index ed2f345..98c16dc 100644
--- a/third_party/SPIRV-Tools/source/opt/module.h
+++ b/third_party/SPIRV-Tools/source/opt/module.h
@@ -17,6 +17,7 @@
 
 #include <functional>
 #include <memory>
+#include <string_view>
 #include <unordered_map>
 #include <utility>
 #include <vector>
@@ -119,6 +120,9 @@
   // Appends a constant, global variable, or OpUndef instruction to this module.
   inline void AddGlobalValue(std::unique_ptr<Instruction> v);
 
+  // Prepends a function declaration to this module.
+  inline void AddFunctionDeclaration(std::unique_ptr<Function> f);
+
   // Appends a function to this module.
   inline void AddFunction(std::unique_ptr<Function> f);
 
@@ -379,6 +383,11 @@
   types_values_.push_back(std::move(v));
 }
 
+inline void Module::AddFunctionDeclaration(std::unique_ptr<Function> f) {
+  // function declarations must come before function definitions.
+  functions_.emplace(functions_.begin(), std::move(f));
+}
+
 inline void Module::AddFunction(std::unique_ptr<Function> f) {
   functions_.emplace_back(std::move(f));
 }
diff --git a/third_party/SPIRV-Tools/source/opt/optimizer.cpp b/third_party/SPIRV-Tools/source/opt/optimizer.cpp
index 46a92dd..c4c2b0f 100644
--- a/third_party/SPIRV-Tools/source/opt/optimizer.cpp
+++ b/third_party/SPIRV-Tools/source/opt/optimizer.cpp
@@ -15,6 +15,7 @@
 #include "spirv-tools/optimizer.hpp"
 
 #include <cassert>
+#include <charconv>
 #include <memory>
 #include <string>
 #include <unordered_map>
@@ -32,6 +33,15 @@
 
 namespace spvtools {
 
+std::vector<std::string> GetVectorOfStrings(const char** strings,
+                                            const size_t string_count) {
+  std::vector<std::string> result;
+  for (uint32_t i = 0; i < string_count; i++) {
+    result.emplace_back(strings[i]);
+  }
+  return result;
+}
+
 struct Optimizer::PassToken::Impl {
   Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {}
 
@@ -109,7 +119,7 @@
 // The legalization problem is essentially a very general copy propagation
 // problem.  The optimization we use are all used to either do copy propagation
 // or enable more copy propagation.
-Optimizer& Optimizer::RegisterLegalizationPasses() {
+Optimizer& Optimizer::RegisterLegalizationPasses(bool preserve_interface) {
   return
       // Wrap OpKill instructions so all other code can be inlined.
       RegisterPass(CreateWrapOpKillPass())
@@ -129,16 +139,16 @@
           // Propagate the value stored to the loads in very simple cases.
           .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
           .RegisterPass(CreateLocalSingleStoreElimPass())
-          .RegisterPass(CreateAggressiveDCEPass())
+          .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
           // Split up aggregates so they are easier to deal with.
           .RegisterPass(CreateScalarReplacementPass(0))
           // Remove loads and stores so everything is in intermediate values.
           // Takes care of copy propagation of non-members.
           .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
           .RegisterPass(CreateLocalSingleStoreElimPass())
-          .RegisterPass(CreateAggressiveDCEPass())
+          .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
           .RegisterPass(CreateLocalMultiStoreElimPass())
-          .RegisterPass(CreateAggressiveDCEPass())
+          .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
           // Propagate constants to get as many constant conditions on branches
           // as possible.
           .RegisterPass(CreateCCPPass())
@@ -147,7 +157,7 @@
           // Copy propagate members.  Cleans up code sequences generated by
           // scalar replacement.  Also important for removing OpPhi nodes.
           .RegisterPass(CreateSimplificationPass())
-          .RegisterPass(CreateAggressiveDCEPass())
+          .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
           .RegisterPass(CreateCopyPropagateArraysPass())
           // May need loop unrolling here see
           // https://github.com/Microsoft/DirectXShaderCompiler/pull/930
@@ -156,30 +166,36 @@
           .RegisterPass(CreateVectorDCEPass())
           .RegisterPass(CreateDeadInsertElimPass())
           .RegisterPass(CreateReduceLoadSizePass())
-          .RegisterPass(CreateAggressiveDCEPass())
-          .RegisterPass(CreateInterpolateFixupPass());
+          .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
+          .RegisterPass(CreateRemoveUnusedInterfaceVariablesPass())
+          .RegisterPass(CreateInterpolateFixupPass())
+          .RegisterPass(CreateInvocationInterlockPlacementPass());
 }
 
-Optimizer& Optimizer::RegisterPerformancePasses() {
+Optimizer& Optimizer::RegisterLegalizationPasses() {
+  return RegisterLegalizationPasses(false);
+}
+
+Optimizer& Optimizer::RegisterPerformancePasses(bool preserve_interface) {
   return RegisterPass(CreateWrapOpKillPass())
       .RegisterPass(CreateDeadBranchElimPass())
       .RegisterPass(CreateMergeReturnPass())
       .RegisterPass(CreateInlineExhaustivePass())
       .RegisterPass(CreateEliminateDeadFunctionsPass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreatePrivateToLocalPass())
       .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
       .RegisterPass(CreateLocalSingleStoreElimPass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateScalarReplacementPass())
       .RegisterPass(CreateLocalAccessChainConvertPass())
       .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
       .RegisterPass(CreateLocalSingleStoreElimPass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateLocalMultiStoreElimPass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateCCPPass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateLoopUnrollPass(true))
       .RegisterPass(CreateDeadBranchElimPass())
       .RegisterPass(CreateRedundancyEliminationPass())
@@ -189,9 +205,9 @@
       .RegisterPass(CreateLocalAccessChainConvertPass())
       .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
       .RegisterPass(CreateLocalSingleStoreElimPass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateSSARewritePass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateVectorDCEPass())
       .RegisterPass(CreateDeadInsertElimPass())
       .RegisterPass(CreateDeadBranchElimPass())
@@ -199,7 +215,7 @@
       .RegisterPass(CreateIfConversionPass())
       .RegisterPass(CreateCopyPropagateArraysPass())
       .RegisterPass(CreateReduceLoadSizePass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateBlockMergePass())
       .RegisterPass(CreateRedundancyEliminationPass())
       .RegisterPass(CreateDeadBranchElimPass())
@@ -207,7 +223,11 @@
       .RegisterPass(CreateSimplificationPass());
 }
 
-Optimizer& Optimizer::RegisterSizePasses() {
+Optimizer& Optimizer::RegisterPerformancePasses() {
+  return RegisterPerformancePasses(false);
+}
+
+Optimizer& Optimizer::RegisterSizePasses(bool preserve_interface) {
   return RegisterPass(CreateWrapOpKillPass())
       .RegisterPass(CreateDeadBranchElimPass())
       .RegisterPass(CreateMergeReturnPass())
@@ -224,12 +244,12 @@
       .RegisterPass(CreateLocalSingleStoreElimPass())
       .RegisterPass(CreateIfConversionPass())
       .RegisterPass(CreateSimplificationPass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateDeadBranchElimPass())
       .RegisterPass(CreateBlockMergePass())
       .RegisterPass(CreateLocalAccessChainConvertPass())
       .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateCopyPropagateArraysPass())
       .RegisterPass(CreateVectorDCEPass())
       .RegisterPass(CreateDeadInsertElimPass())
@@ -239,13 +259,20 @@
       .RegisterPass(CreateLocalMultiStoreElimPass())
       .RegisterPass(CreateRedundancyEliminationPass())
       .RegisterPass(CreateSimplificationPass())
-      .RegisterPass(CreateAggressiveDCEPass())
+      .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
       .RegisterPass(CreateCFGCleanupPass());
 }
 
+Optimizer& Optimizer::RegisterSizePasses() { return RegisterSizePasses(false); }
+
 bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags) {
+  return RegisterPassesFromFlags(flags, false);
+}
+
+bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags,
+                                        bool preserve_interface) {
   for (const auto& flag : flags) {
-    if (!RegisterPassFromFlag(flag)) {
+    if (!RegisterPassFromFlag(flag, preserve_interface)) {
       return false;
     }
   }
@@ -269,6 +296,11 @@
 }
 
 bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
+  return RegisterPassFromFlag(flag, false);
+}
+
+bool Optimizer::RegisterPassFromFlag(const std::string& flag,
+                                     bool preserve_interface) {
   if (!FlagHasValidForm(flag)) {
     return false;
   }
@@ -330,7 +362,7 @@
   } else if (pass_name == "descriptor-scalar-replacement") {
     RegisterPass(CreateDescriptorScalarReplacementPass());
   } else if (pass_name == "eliminate-dead-code-aggressive") {
-    RegisterPass(CreateAggressiveDCEPass());
+    RegisterPass(CreateAggressiveDCEPass(preserve_interface));
   } else if (pass_name == "eliminate-insert-extract") {
     RegisterPass(CreateInsertExtractElimPass());
   } else if (pass_name == "eliminate-local-single-block") {
@@ -419,32 +451,26 @@
     RegisterPass(CreateWorkaround1209Pass());
   } else if (pass_name == "replace-invalid-opcode") {
     RegisterPass(CreateReplaceInvalidOpcodePass());
-  } else if (pass_name == "inst-bindless-check") {
-    RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false));
+  } else if (pass_name == "inst-bindless-check" ||
+             pass_name == "inst-desc-idx-check" ||
+             pass_name == "inst-buff-oob-check") {
+    // preserve legacy names
+    RegisterPass(CreateInstBindlessCheckPass(23));
     RegisterPass(CreateSimplificationPass());
     RegisterPass(CreateDeadBranchElimPass());
     RegisterPass(CreateBlockMergePass());
-    RegisterPass(CreateAggressiveDCEPass(true));
-  } else if (pass_name == "inst-desc-idx-check") {
-    RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true));
-    RegisterPass(CreateSimplificationPass());
-    RegisterPass(CreateDeadBranchElimPass());
-    RegisterPass(CreateBlockMergePass());
-    RegisterPass(CreateAggressiveDCEPass(true));
-  } else if (pass_name == "inst-buff-oob-check") {
-    RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true));
-    RegisterPass(CreateSimplificationPass());
-    RegisterPass(CreateDeadBranchElimPass());
-    RegisterPass(CreateBlockMergePass());
-    RegisterPass(CreateAggressiveDCEPass(true));
   } else if (pass_name == "inst-buff-addr-check") {
-    RegisterPass(CreateInstBuffAddrCheckPass(7, 23));
-    RegisterPass(CreateAggressiveDCEPass(true));
+    RegisterPass(CreateInstBuffAddrCheckPass(23));
   } else if (pass_name == "convert-relaxed-to-half") {
     RegisterPass(CreateConvertRelaxedToHalfPass());
   } else if (pass_name == "relax-float-ops") {
     RegisterPass(CreateRelaxFloatOpsPass());
   } else if (pass_name == "inst-debug-printf") {
+    // This private option is not for user consumption.
+    // It is here to assist in debugging and fixing the debug printf
+    // instrumentation pass.
+    // For users who wish to utilize debug printf, see the white paper at
+    // https://www.lunarg.com/wp-content/uploads/2021/08/Using-Debug-Printf-02August2021.pdf
     RegisterPass(CreateInstDebugPrintfPass(7, 23));
   } else if (pass_name == "simplify-instructions") {
     RegisterPass(CreateSimplificationPass());
@@ -507,11 +533,11 @@
   } else if (pass_name == "fix-storage-class") {
     RegisterPass(CreateFixStorageClassPass());
   } else if (pass_name == "O") {
-    RegisterPerformancePasses();
+    RegisterPerformancePasses(preserve_interface);
   } else if (pass_name == "Os") {
-    RegisterSizePasses();
+    RegisterSizePasses(preserve_interface);
   } else if (pass_name == "legalize-hlsl") {
-    RegisterLegalizationPasses();
+    RegisterLegalizationPasses(preserve_interface);
   } else if (pass_name == "remove-unused-interface-variables") {
     RegisterPass(CreateRemoveUnusedInterfaceVariablesPass());
   } else if (pass_name == "graphics-robust-access") {
@@ -548,6 +574,58 @@
              pass_args.c_str());
       return false;
     }
+  } else if (pass_name == "switch-descriptorset") {
+    if (pass_args.size() == 0) {
+      Error(consumer(), nullptr, {},
+            "--switch-descriptorset requires a from:to argument.");
+      return false;
+    }
+    uint32_t from_set = 0, to_set = 0;
+    const char* start = pass_args.data();
+    const char* end = pass_args.data() + pass_args.size();
+
+    auto result = std::from_chars(start, end, from_set);
+    if (result.ec != std::errc()) {
+      Errorf(consumer(), nullptr, {},
+             "Invalid argument for --switch-descriptorset: %s",
+             pass_args.c_str());
+      return false;
+    }
+    start = result.ptr;
+    if (start[0] != ':') {
+      Errorf(consumer(), nullptr, {},
+             "Invalid argument for --switch-descriptorset: %s",
+             pass_args.c_str());
+      return false;
+    }
+    start++;
+    result = std::from_chars(start, end, to_set);
+    if (result.ec != std::errc() || result.ptr != end) {
+      Errorf(consumer(), nullptr, {},
+             "Invalid argument for --switch-descriptorset: %s",
+             pass_args.c_str());
+      return false;
+    }
+    RegisterPass(CreateSwitchDescriptorSetPass(from_set, to_set));
+  } else if (pass_name == "modify-maximal-reconvergence") {
+    if (pass_args.size() == 0) {
+      Error(consumer(), nullptr, {},
+            "--modify-maximal-reconvergence requires an argument");
+      return false;
+    }
+    if (pass_args == "add") {
+      RegisterPass(CreateModifyMaximalReconvergencePass(true));
+    } else if (pass_args == "remove") {
+      RegisterPass(CreateModifyMaximalReconvergencePass(false));
+    } else {
+      Errorf(consumer(), nullptr, {},
+             "Invalid argument for --modify-maximal-reconvergence: %s (must be "
+             "'add' or 'remove')",
+             pass_args.c_str());
+      return false;
+    }
+  } else if (pass_name == "trim-capabilities") {
+    RegisterPass(CreateTrimCapabilitiesPass());
   } else {
     Errorf(consumer(), nullptr, {},
            "Unknown flag '--%s'. Use --help for a list of valid flags",
@@ -945,14 +1023,9 @@
       MakeUnique<opt::UpgradeMemoryModel>());
 }
 
-Optimizer::PassToken CreateInstBindlessCheckPass(
-    uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
-    bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
+Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t shader_id) {
   return MakeUnique<Optimizer::PassToken::Impl>(
-      MakeUnique<opt::InstBindlessCheckPass>(
-          desc_set, shader_id, desc_length_enable, desc_init_enable,
-          buff_oob_enable, texbuff_oob_enable,
-          desc_length_enable || desc_init_enable || buff_oob_enable));
+      MakeUnique<opt::InstBindlessCheckPass>(shader_id));
 }
 
 Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
@@ -961,10 +1034,9 @@
       MakeUnique<opt::InstDebugPrintfPass>(desc_set, shader_id));
 }
 
-Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
-                                                 uint32_t shader_id) {
+Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t shader_id) {
   return MakeUnique<Optimizer::PassToken::Impl>(
-      MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id));
+      MakeUnique<opt::InstBuffAddrCheckPass>(shader_id));
 }
 
 Optimizer::PassToken CreateConvertRelaxedToHalfPass() {
@@ -1074,6 +1146,26 @@
   return MakeUnique<Optimizer::PassToken::Impl>(
       MakeUnique<opt::FixFuncCallArgumentsPass>());
 }
+
+Optimizer::PassToken CreateTrimCapabilitiesPass() {
+  return MakeUnique<Optimizer::PassToken::Impl>(
+      MakeUnique<opt::TrimCapabilitiesPass>());
+}
+
+Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t from, uint32_t to) {
+  return MakeUnique<Optimizer::PassToken::Impl>(
+      MakeUnique<opt::SwitchDescriptorSetPass>(from, to));
+}
+
+Optimizer::PassToken CreateInvocationInterlockPlacementPass() {
+  return MakeUnique<Optimizer::PassToken::Impl>(
+      MakeUnique<opt::InvocationInterlockPlacementPass>());
+}
+
+Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add) {
+  return MakeUnique<Optimizer::PassToken::Impl>(
+      MakeUnique<opt::ModifyMaximalReconvergence>(add));
+}
 }  // namespace spvtools
 
 extern "C" {
@@ -1122,13 +1214,19 @@
 
 SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags(
     spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) {
-  std::vector<std::string> opt_flags;
-  for (uint32_t i = 0; i < flag_count; i++) {
-    opt_flags.emplace_back(flags[i]);
-  }
+  std::vector<std::string> opt_flags =
+      spvtools::GetVectorOfStrings(flags, flag_count);
+  return reinterpret_cast<spvtools::Optimizer*>(optimizer)
+      ->RegisterPassesFromFlags(opt_flags, false);
+}
 
-  return reinterpret_cast<spvtools::Optimizer*>(optimizer)->
-      RegisterPassesFromFlags(opt_flags);
+SPIRV_TOOLS_EXPORT bool
+spvOptimizerRegisterPassesFromFlagsWhilePreservingTheInterface(
+    spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) {
+  std::vector<std::string> opt_flags =
+      spvtools::GetVectorOfStrings(flags, flag_count);
+  return reinterpret_cast<spvtools::Optimizer*>(optimizer)
+      ->RegisterPassesFromFlags(opt_flags, true);
 }
 
 SPIRV_TOOLS_EXPORT
diff --git a/third_party/SPIRV-Tools/source/opt/passes.h b/third_party/SPIRV-Tools/source/opt/passes.h
index eb3b1e5..9d027fb 100644
--- a/third_party/SPIRV-Tools/source/opt/passes.h
+++ b/third_party/SPIRV-Tools/source/opt/passes.h
@@ -53,6 +53,7 @@
 #include "source/opt/inst_debug_printf_pass.h"
 #include "source/opt/interface_var_sroa.h"
 #include "source/opt/interp_fixup_pass.h"
+#include "source/opt/invocation_interlock_placement_pass.h"
 #include "source/opt/licm_pass.h"
 #include "source/opt/local_access_chain_convert_pass.h"
 #include "source/opt/local_redundancy_elimination.h"
@@ -64,6 +65,7 @@
 #include "source/opt/loop_unroller.h"
 #include "source/opt/loop_unswitch_pass.h"
 #include "source/opt/merge_return_pass.h"
+#include "source/opt/modify_maximal_reconvergence.h"
 #include "source/opt/null_pass.h"
 #include "source/opt/private_to_local_pass.h"
 #include "source/opt/reduce_load_size.h"
@@ -82,6 +84,8 @@
 #include "source/opt/strength_reduction_pass.h"
 #include "source/opt/strip_debug_info_pass.h"
 #include "source/opt/strip_nonsemantic_info_pass.h"
+#include "source/opt/switch_descriptorset_pass.h"
+#include "source/opt/trim_capabilities_pass.h"
 #include "source/opt/unify_const_pass.h"
 #include "source/opt/upgrade_memory_model.h"
 #include "source/opt/vector_dce.h"
diff --git a/third_party/SPIRV-Tools/source/opt/switch_descriptorset_pass.cpp b/third_party/SPIRV-Tools/source/opt/switch_descriptorset_pass.cpp
new file mode 100644
index 0000000..f07c917
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/switch_descriptorset_pass.cpp
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/switch_descriptorset_pass.h"
+
+#include "source/opt/ir_builder.h"
+#include "source/util/string_utils.h"
+
+namespace spvtools {
+namespace opt {
+
+Pass::Status SwitchDescriptorSetPass::Process() {
+  Status status = Status::SuccessWithoutChange;
+  auto* deco_mgr = context()->get_decoration_mgr();
+
+  for (Instruction& var : context()->types_values()) {
+    if (var.opcode() != spv::Op::OpVariable) {
+      continue;
+    }
+    auto decos = deco_mgr->GetDecorationsFor(var.result_id(), false);
+    for (const auto& deco : decos) {
+      spv::Decoration d = spv::Decoration(deco->GetSingleWordInOperand(1u));
+      if (d == spv::Decoration::DescriptorSet &&
+          deco->GetSingleWordInOperand(2u) == ds_from_) {
+        deco->SetInOperand(2u, {ds_to_});
+        status = Status::SuccessWithChange;
+        break;
+      }
+    }
+  }
+  return status;
+}
+
+}  // namespace opt
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/opt/switch_descriptorset_pass.h b/third_party/SPIRV-Tools/source/opt/switch_descriptorset_pass.h
new file mode 100644
index 0000000..2084e9c
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/switch_descriptorset_pass.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2023 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <cstdio>
+#include <memory>
+#include <queue>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class SwitchDescriptorSetPass : public Pass {
+ public:
+  SwitchDescriptorSetPass(uint32_t ds_from, uint32_t ds_to)
+      : ds_from_(ds_from), ds_to_(ds_to) {}
+
+  const char* name() const override { return "switch-descriptorset"; }
+
+  Status Process() override;
+
+  IRContext::Analysis GetPreservedAnalyses() override {
+    // this pass preserves everything except decorations
+    uint32_t mask = ((IRContext::kAnalysisEnd << 1) - 1);
+    mask &= ~static_cast<uint32_t>(IRContext::kAnalysisDecorations);
+    return static_cast<IRContext::Analysis>(mask);
+  }
+
+ private:
+  uint32_t ds_from_;
+  uint32_t ds_to_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/opt/trim_capabilities_pass.cpp b/third_party/SPIRV-Tools/source/opt/trim_capabilities_pass.cpp
new file mode 100644
index 0000000..24f9e46
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/trim_capabilities_pass.cpp
@@ -0,0 +1,649 @@
+// Copyright (c) 2023 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/trim_capabilities_pass.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <functional>
+#include <optional>
+#include <queue>
+#include <stack>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "source/enum_set.h"
+#include "source/enum_string_mapping.h"
+#include "source/opt/ir_context.h"
+#include "source/opt/reflect.h"
+#include "source/spirv_target_env.h"
+#include "source/util/string_utils.h"
+
+namespace spvtools {
+namespace opt {
+
+namespace {
+constexpr uint32_t kOpTypeFloatSizeIndex = 0;
+constexpr uint32_t kOpTypePointerStorageClassIndex = 0;
+constexpr uint32_t kTypeArrayTypeIndex = 0;
+constexpr uint32_t kOpTypeScalarBitWidthIndex = 0;
+constexpr uint32_t kTypePointerTypeIdInIndex = 1;
+constexpr uint32_t kOpTypeIntSizeIndex = 0;
+constexpr uint32_t kOpTypeImageDimIndex = 1;
+constexpr uint32_t kOpTypeImageArrayedIndex = kOpTypeImageDimIndex + 2;
+constexpr uint32_t kOpTypeImageMSIndex = kOpTypeImageArrayedIndex + 1;
+constexpr uint32_t kOpTypeImageSampledIndex = kOpTypeImageMSIndex + 1;
+constexpr uint32_t kOpTypeImageFormatIndex = kOpTypeImageSampledIndex + 1;
+constexpr uint32_t kOpImageReadImageIndex = 0;
+constexpr uint32_t kOpImageSparseReadImageIndex = 0;
+
+// DFS visit of the type defined by `instruction`.
+// If `condition` is true, children of the current node are visited.
+// If `condition` is false, the children of the current node are ignored.
+template <class UnaryPredicate>
+static void DFSWhile(const Instruction* instruction, UnaryPredicate condition) {
+  std::stack<uint32_t> instructions_to_visit;
+  instructions_to_visit.push(instruction->result_id());
+  const auto* def_use_mgr = instruction->context()->get_def_use_mgr();
+
+  while (!instructions_to_visit.empty()) {
+    const Instruction* item = def_use_mgr->GetDef(instructions_to_visit.top());
+    instructions_to_visit.pop();
+
+    if (!condition(item)) {
+      continue;
+    }
+
+    if (item->opcode() == spv::Op::OpTypePointer) {
+      instructions_to_visit.push(
+          item->GetSingleWordInOperand(kTypePointerTypeIdInIndex));
+      continue;
+    }
+
+    if (item->opcode() == spv::Op::OpTypeMatrix ||
+        item->opcode() == spv::Op::OpTypeVector ||
+        item->opcode() == spv::Op::OpTypeArray ||
+        item->opcode() == spv::Op::OpTypeRuntimeArray) {
+      instructions_to_visit.push(
+          item->GetSingleWordInOperand(kTypeArrayTypeIndex));
+      continue;
+    }
+
+    if (item->opcode() == spv::Op::OpTypeStruct) {
+      item->ForEachInOperand([&instructions_to_visit](const uint32_t* op_id) {
+        instructions_to_visit.push(*op_id);
+      });
+      continue;
+    }
+  }
+}
+
+// Walks the type defined by `instruction` (OpType* only).
+// Returns `true` if any call to `predicate` with the type/subtype returns true.
+template <class UnaryPredicate>
+static bool AnyTypeOf(const Instruction* instruction,
+                      UnaryPredicate predicate) {
+  assert(IsTypeInst(instruction->opcode()) &&
+         "AnyTypeOf called with a non-type instruction.");
+
+  bool found_one = false;
+  DFSWhile(instruction, [&found_one, predicate](const Instruction* node) {
+    if (found_one || predicate(node)) {
+      found_one = true;
+      return false;
+    }
+
+    return true;
+  });
+  return found_one;
+}
+
+static bool is16bitType(const Instruction* instruction) {
+  if (instruction->opcode() != spv::Op::OpTypeInt &&
+      instruction->opcode() != spv::Op::OpTypeFloat) {
+    return false;
+  }
+
+  return instruction->GetSingleWordInOperand(kOpTypeScalarBitWidthIndex) == 16;
+}
+
+static bool Has16BitCapability(const FeatureManager* feature_manager) {
+  const CapabilitySet& capabilities = feature_manager->GetCapabilities();
+  return capabilities.contains(spv::Capability::Float16) ||
+         capabilities.contains(spv::Capability::Int16);
+}
+
+}  // namespace
+
+// ============== Begin opcode handler implementations. =======================
+//
+// Adding support for a new capability should only require adding a new handler,
+// and updating the
+// kSupportedCapabilities/kUntouchableCapabilities/kFordiddenCapabilities lists.
+//
+// Handler names follow the following convention:
+//  Handler_<Opcode>_<Capability>()
+
+static std::optional<spv::Capability> Handler_OpTypeFloat_Float16(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpTypeFloat &&
+         "This handler only support OpTypeFloat opcodes.");
+
+  const uint32_t size =
+      instruction->GetSingleWordInOperand(kOpTypeFloatSizeIndex);
+  return size == 16 ? std::optional(spv::Capability::Float16) : std::nullopt;
+}
+
+static std::optional<spv::Capability> Handler_OpTypeFloat_Float64(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpTypeFloat &&
+         "This handler only support OpTypeFloat opcodes.");
+
+  const uint32_t size =
+      instruction->GetSingleWordInOperand(kOpTypeFloatSizeIndex);
+  return size == 64 ? std::optional(spv::Capability::Float64) : std::nullopt;
+}
+
+static std::optional<spv::Capability>
+Handler_OpTypePointer_StorageInputOutput16(const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpTypePointer &&
+         "This handler only support OpTypePointer opcodes.");
+
+  // This capability is only required if the variable has an Input/Output
+  // storage class.
+  spv::StorageClass storage_class = spv::StorageClass(
+      instruction->GetSingleWordInOperand(kOpTypePointerStorageClassIndex));
+  if (storage_class != spv::StorageClass::Input &&
+      storage_class != spv::StorageClass::Output) {
+    return std::nullopt;
+  }
+
+  if (!Has16BitCapability(instruction->context()->get_feature_mgr())) {
+    return std::nullopt;
+  }
+
+  return AnyTypeOf(instruction, is16bitType)
+             ? std::optional(spv::Capability::StorageInputOutput16)
+             : std::nullopt;
+}
+
+static std::optional<spv::Capability>
+Handler_OpTypePointer_StoragePushConstant16(const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpTypePointer &&
+         "This handler only support OpTypePointer opcodes.");
+
+  // This capability is only required if the variable has a PushConstant storage
+  // class.
+  spv::StorageClass storage_class = spv::StorageClass(
+      instruction->GetSingleWordInOperand(kOpTypePointerStorageClassIndex));
+  if (storage_class != spv::StorageClass::PushConstant) {
+    return std::nullopt;
+  }
+
+  if (!Has16BitCapability(instruction->context()->get_feature_mgr())) {
+    return std::nullopt;
+  }
+
+  return AnyTypeOf(instruction, is16bitType)
+             ? std::optional(spv::Capability::StoragePushConstant16)
+             : std::nullopt;
+}
+
+static std::optional<spv::Capability>
+Handler_OpTypePointer_StorageUniformBufferBlock16(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpTypePointer &&
+         "This handler only support OpTypePointer opcodes.");
+
+  // This capability is only required if the variable has a Uniform storage
+  // class.
+  spv::StorageClass storage_class = spv::StorageClass(
+      instruction->GetSingleWordInOperand(kOpTypePointerStorageClassIndex));
+  if (storage_class != spv::StorageClass::Uniform) {
+    return std::nullopt;
+  }
+
+  if (!Has16BitCapability(instruction->context()->get_feature_mgr())) {
+    return std::nullopt;
+  }
+
+  const auto* decoration_mgr = instruction->context()->get_decoration_mgr();
+  const bool matchesCondition =
+      AnyTypeOf(instruction, [decoration_mgr](const Instruction* item) {
+        if (!decoration_mgr->HasDecoration(item->result_id(),
+                                           spv::Decoration::BufferBlock)) {
+          return false;
+        }
+
+        return AnyTypeOf(item, is16bitType);
+      });
+
+  return matchesCondition
+             ? std::optional(spv::Capability::StorageUniformBufferBlock16)
+             : std::nullopt;
+}
+
+static std::optional<spv::Capability> Handler_OpTypePointer_StorageUniform16(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpTypePointer &&
+         "This handler only support OpTypePointer opcodes.");
+
+  // This capability is only required if the variable has a Uniform storage
+  // class.
+  spv::StorageClass storage_class = spv::StorageClass(
+      instruction->GetSingleWordInOperand(kOpTypePointerStorageClassIndex));
+  if (storage_class != spv::StorageClass::Uniform) {
+    return std::nullopt;
+  }
+
+  const auto* feature_manager = instruction->context()->get_feature_mgr();
+  if (!Has16BitCapability(feature_manager)) {
+    return std::nullopt;
+  }
+
+  const bool hasBufferBlockCapability =
+      feature_manager->GetCapabilities().contains(
+          spv::Capability::StorageUniformBufferBlock16);
+  const auto* decoration_mgr = instruction->context()->get_decoration_mgr();
+  bool found16bitType = false;
+
+  DFSWhile(instruction, [decoration_mgr, hasBufferBlockCapability,
+                         &found16bitType](const Instruction* item) {
+    if (found16bitType) {
+      return false;
+    }
+
+    if (hasBufferBlockCapability &&
+        decoration_mgr->HasDecoration(item->result_id(),
+                                      spv::Decoration::BufferBlock)) {
+      return false;
+    }
+
+    if (is16bitType(item)) {
+      found16bitType = true;
+      return false;
+    }
+
+    return true;
+  });
+
+  return found16bitType ? std::optional(spv::Capability::StorageUniform16)
+                        : std::nullopt;
+}
+
+static std::optional<spv::Capability> Handler_OpTypeInt_Int16(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpTypeInt &&
+         "This handler only support OpTypeInt opcodes.");
+
+  const uint32_t size =
+      instruction->GetSingleWordInOperand(kOpTypeIntSizeIndex);
+  return size == 16 ? std::optional(spv::Capability::Int16) : std::nullopt;
+}
+
+static std::optional<spv::Capability> Handler_OpTypeInt_Int64(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpTypeInt &&
+         "This handler only support OpTypeInt opcodes.");
+
+  const uint32_t size =
+      instruction->GetSingleWordInOperand(kOpTypeIntSizeIndex);
+  return size == 64 ? std::optional(spv::Capability::Int64) : std::nullopt;
+}
+
+static std::optional<spv::Capability> Handler_OpTypeImage_ImageMSArray(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpTypeImage &&
+         "This handler only support OpTypeImage opcodes.");
+
+  const uint32_t arrayed =
+      instruction->GetSingleWordInOperand(kOpTypeImageArrayedIndex);
+  const uint32_t ms = instruction->GetSingleWordInOperand(kOpTypeImageMSIndex);
+  const uint32_t sampled =
+      instruction->GetSingleWordInOperand(kOpTypeImageSampledIndex);
+
+  return arrayed == 1 && sampled == 2 && ms == 1
+             ? std::optional(spv::Capability::ImageMSArray)
+             : std::nullopt;
+}
+
+static std::optional<spv::Capability>
+Handler_OpImageRead_StorageImageReadWithoutFormat(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpImageRead &&
+         "This handler only support OpImageRead opcodes.");
+  const auto* def_use_mgr = instruction->context()->get_def_use_mgr();
+
+  const uint32_t image_index =
+      instruction->GetSingleWordInOperand(kOpImageReadImageIndex);
+  const uint32_t type_index = def_use_mgr->GetDef(image_index)->type_id();
+  const Instruction* type = def_use_mgr->GetDef(type_index);
+  const uint32_t dim = type->GetSingleWordInOperand(kOpTypeImageDimIndex);
+  const uint32_t format = type->GetSingleWordInOperand(kOpTypeImageFormatIndex);
+
+  const bool is_unknown = spv::ImageFormat(format) == spv::ImageFormat::Unknown;
+  const bool requires_capability_for_unknown =
+      spv::Dim(dim) != spv::Dim::SubpassData;
+  return is_unknown && requires_capability_for_unknown
+             ? std::optional(spv::Capability::StorageImageReadWithoutFormat)
+             : std::nullopt;
+}
+
+static std::optional<spv::Capability>
+Handler_OpImageSparseRead_StorageImageReadWithoutFormat(
+    const Instruction* instruction) {
+  assert(instruction->opcode() == spv::Op::OpImageSparseRead &&
+         "This handler only support OpImageSparseRead opcodes.");
+  const auto* def_use_mgr = instruction->context()->get_def_use_mgr();
+
+  const uint32_t image_index =
+      instruction->GetSingleWordInOperand(kOpImageSparseReadImageIndex);
+  const uint32_t type_index = def_use_mgr->GetDef(image_index)->type_id();
+  const Instruction* type = def_use_mgr->GetDef(type_index);
+  const uint32_t format = type->GetSingleWordInOperand(kOpTypeImageFormatIndex);
+
+  return spv::ImageFormat(format) == spv::ImageFormat::Unknown
+             ? std::optional(spv::Capability::StorageImageReadWithoutFormat)
+             : std::nullopt;
+}
+
+// Opcode of interest to determine capabilities requirements.
+constexpr std::array<std::pair<spv::Op, OpcodeHandler>, 12> kOpcodeHandlers{{
+    // clang-format off
+    {spv::Op::OpImageRead,         Handler_OpImageRead_StorageImageReadWithoutFormat},
+    {spv::Op::OpImageSparseRead,   Handler_OpImageSparseRead_StorageImageReadWithoutFormat},
+    {spv::Op::OpTypeFloat,         Handler_OpTypeFloat_Float16 },
+    {spv::Op::OpTypeFloat,         Handler_OpTypeFloat_Float64 },
+    {spv::Op::OpTypeImage,         Handler_OpTypeImage_ImageMSArray},
+    {spv::Op::OpTypeInt,           Handler_OpTypeInt_Int16 },
+    {spv::Op::OpTypeInt,           Handler_OpTypeInt_Int64 },
+    {spv::Op::OpTypePointer,       Handler_OpTypePointer_StorageInputOutput16},
+    {spv::Op::OpTypePointer,       Handler_OpTypePointer_StoragePushConstant16},
+    {spv::Op::OpTypePointer,       Handler_OpTypePointer_StorageUniform16},
+    {spv::Op::OpTypePointer,       Handler_OpTypePointer_StorageUniform16},
+    {spv::Op::OpTypePointer,       Handler_OpTypePointer_StorageUniformBufferBlock16},
+    // clang-format on
+}};
+
+// ==============  End opcode handler implementations.  =======================
+
+namespace {
+ExtensionSet getExtensionsRelatedTo(const CapabilitySet& capabilities,
+                                    const AssemblyGrammar& grammar) {
+  ExtensionSet output;
+  const spv_operand_desc_t* desc = nullptr;
+  for (auto capability : capabilities) {
+    if (SPV_SUCCESS != grammar.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
+                                             static_cast<uint32_t>(capability),
+                                             &desc)) {
+      continue;
+    }
+
+    for (uint32_t i = 0; i < desc->numExtensions; ++i) {
+      output.insert(desc->extensions[i]);
+    }
+  }
+
+  return output;
+}
+}  // namespace
+
+TrimCapabilitiesPass::TrimCapabilitiesPass()
+    : supportedCapabilities_(
+          TrimCapabilitiesPass::kSupportedCapabilities.cbegin(),
+          TrimCapabilitiesPass::kSupportedCapabilities.cend()),
+      forbiddenCapabilities_(
+          TrimCapabilitiesPass::kForbiddenCapabilities.cbegin(),
+          TrimCapabilitiesPass::kForbiddenCapabilities.cend()),
+      untouchableCapabilities_(
+          TrimCapabilitiesPass::kUntouchableCapabilities.cbegin(),
+          TrimCapabilitiesPass::kUntouchableCapabilities.cend()),
+      opcodeHandlers_(kOpcodeHandlers.cbegin(), kOpcodeHandlers.cend()) {}
+
+void TrimCapabilitiesPass::addInstructionRequirementsForOpcode(
+    spv::Op opcode, CapabilitySet* capabilities,
+    ExtensionSet* extensions) const {
+  // Ignoring OpBeginInvocationInterlockEXT and OpEndInvocationInterlockEXT
+  // because they have three possible capabilities, only one of which is needed
+  if (opcode == spv::Op::OpBeginInvocationInterlockEXT ||
+      opcode == spv::Op::OpEndInvocationInterlockEXT) {
+    return;
+  }
+
+  const spv_opcode_desc_t* desc = {};
+  auto result = context()->grammar().lookupOpcode(opcode, &desc);
+  if (result != SPV_SUCCESS) {
+    return;
+  }
+
+  addSupportedCapabilitiesToSet(desc, capabilities);
+  addSupportedExtensionsToSet(desc, extensions);
+}
+
+void TrimCapabilitiesPass::addInstructionRequirementsForOperand(
+    const Operand& operand, CapabilitySet* capabilities,
+    ExtensionSet* extensions) const {
+  // No supported capability relies on a 2+-word operand.
+  if (operand.words.size() != 1) {
+    return;
+  }
+
+  // No supported capability relies on a literal string operand or an ID.
+  if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING ||
+      operand.type == SPV_OPERAND_TYPE_ID ||
+      operand.type == SPV_OPERAND_TYPE_RESULT_ID) {
+    return;
+  }
+
+  // If the Vulkan memory model is declared and any instruction uses Device
+  // scope, the VulkanMemoryModelDeviceScope capability must be declared. This
+  // rule cannot be covered by the grammar, so must be checked explicitly.
+  if (operand.type == SPV_OPERAND_TYPE_SCOPE_ID) {
+    const Instruction* memory_model = context()->GetMemoryModel();
+    if (memory_model && memory_model->GetSingleWordInOperand(1u) ==
+                            uint32_t(spv::MemoryModel::Vulkan)) {
+      capabilities->insert(spv::Capability::VulkanMemoryModelDeviceScope);
+    }
+  }
+
+  // case 1: Operand is a single value, can directly lookup.
+  if (!spvOperandIsConcreteMask(operand.type)) {
+    const spv_operand_desc_t* desc = {};
+    auto result = context()->grammar().lookupOperand(operand.type,
+                                                     operand.words[0], &desc);
+    if (result != SPV_SUCCESS) {
+      return;
+    }
+    addSupportedCapabilitiesToSet(desc, capabilities);
+    addSupportedExtensionsToSet(desc, extensions);
+    return;
+  }
+
+  // case 2: operand can be a bitmask, we need to decompose the lookup.
+  for (uint32_t i = 0; i < 32; i++) {
+    const uint32_t mask = (1 << i) & operand.words[0];
+    if (!mask) {
+      continue;
+    }
+
+    const spv_operand_desc_t* desc = {};
+    auto result = context()->grammar().lookupOperand(operand.type, mask, &desc);
+    if (result != SPV_SUCCESS) {
+      continue;
+    }
+
+    addSupportedCapabilitiesToSet(desc, capabilities);
+    addSupportedExtensionsToSet(desc, extensions);
+  }
+}
+
+void TrimCapabilitiesPass::addInstructionRequirements(
+    Instruction* instruction, CapabilitySet* capabilities,
+    ExtensionSet* extensions) const {
+  // Ignoring OpCapability and OpExtension instructions.
+  if (instruction->opcode() == spv::Op::OpCapability ||
+      instruction->opcode() == spv::Op::OpExtension) {
+    return;
+  }
+
+  addInstructionRequirementsForOpcode(instruction->opcode(), capabilities,
+                                      extensions);
+
+  // Second case: one of the opcode operand is gated by a capability.
+  const uint32_t operandCount = instruction->NumOperands();
+  for (uint32_t i = 0; i < operandCount; i++) {
+    addInstructionRequirementsForOperand(instruction->GetOperand(i),
+                                         capabilities, extensions);
+  }
+
+  // Last case: some complex logic needs to be run to determine capabilities.
+  auto[begin, end] = opcodeHandlers_.equal_range(instruction->opcode());
+  for (auto it = begin; it != end; it++) {
+    const OpcodeHandler handler = it->second;
+    auto result = handler(instruction);
+    if (!result.has_value()) {
+      continue;
+    }
+
+    capabilities->insert(*result);
+  }
+}
+
+void TrimCapabilitiesPass::AddExtensionsForOperand(
+    const spv_operand_type_t type, const uint32_t value,
+    ExtensionSet* extensions) const {
+  const spv_operand_desc_t* desc = nullptr;
+  spv_result_t result = context()->grammar().lookupOperand(type, value, &desc);
+  if (result != SPV_SUCCESS) {
+    return;
+  }
+  addSupportedExtensionsToSet(desc, extensions);
+}
+
+std::pair<CapabilitySet, ExtensionSet>
+TrimCapabilitiesPass::DetermineRequiredCapabilitiesAndExtensions() const {
+  CapabilitySet required_capabilities;
+  ExtensionSet required_extensions;
+
+  get_module()->ForEachInst([&](Instruction* instruction) {
+    addInstructionRequirements(instruction, &required_capabilities,
+                               &required_extensions);
+  });
+
+  for (auto capability : required_capabilities) {
+    AddExtensionsForOperand(SPV_OPERAND_TYPE_CAPABILITY,
+                            static_cast<uint32_t>(capability),
+                            &required_extensions);
+  }
+
+#if !defined(NDEBUG)
+  // Debug only. We check the outputted required capabilities against the
+  // supported capabilities list. The supported capabilities list is useful for
+  // API users to quickly determine if they can use the pass or not. But this
+  // list has to remain up-to-date with the pass code. If we can detect a
+  // capability as required, but it's not listed, it means the list is
+  // out-of-sync. This method is not ideal, but should cover most cases.
+  {
+    for (auto capability : required_capabilities) {
+      assert(supportedCapabilities_.contains(capability) &&
+             "Module is using a capability that is not listed as supported.");
+    }
+  }
+#endif
+
+  return std::make_pair(std::move(required_capabilities),
+                        std::move(required_extensions));
+}
+
+Pass::Status TrimCapabilitiesPass::TrimUnrequiredCapabilities(
+    const CapabilitySet& required_capabilities) const {
+  const FeatureManager* feature_manager = context()->get_feature_mgr();
+  CapabilitySet capabilities_to_trim;
+  for (auto capability : feature_manager->GetCapabilities()) {
+    // Some capabilities cannot be safely removed. Leaving them untouched.
+    if (untouchableCapabilities_.contains(capability)) {
+      continue;
+    }
+
+    // If the capability is unsupported, don't trim it.
+    if (!supportedCapabilities_.contains(capability)) {
+      continue;
+    }
+
+    if (required_capabilities.contains(capability)) {
+      continue;
+    }
+
+    capabilities_to_trim.insert(capability);
+  }
+
+  for (auto capability : capabilities_to_trim) {
+    context()->RemoveCapability(capability);
+  }
+
+  return capabilities_to_trim.size() == 0 ? Pass::Status::SuccessWithoutChange
+                                          : Pass::Status::SuccessWithChange;
+}
+
+Pass::Status TrimCapabilitiesPass::TrimUnrequiredExtensions(
+    const ExtensionSet& required_extensions) const {
+  const auto supported_extensions =
+      getExtensionsRelatedTo(supportedCapabilities_, context()->grammar());
+
+  bool modified_module = false;
+  for (auto extension : supported_extensions) {
+    if (required_extensions.contains(extension)) {
+      continue;
+    }
+
+    if (context()->RemoveExtension(extension)) {
+      modified_module = true;
+    }
+  }
+
+  return modified_module ? Pass::Status::SuccessWithChange
+                         : Pass::Status::SuccessWithoutChange;
+}
+
+bool TrimCapabilitiesPass::HasForbiddenCapabilities() const {
+  // EnumSet.HasAnyOf returns `true` if the given set is empty.
+  if (forbiddenCapabilities_.size() == 0) {
+    return false;
+  }
+
+  const auto& capabilities = context()->get_feature_mgr()->GetCapabilities();
+  return capabilities.HasAnyOf(forbiddenCapabilities_);
+}
+
+Pass::Status TrimCapabilitiesPass::Process() {
+  if (HasForbiddenCapabilities()) {
+    return Status::SuccessWithoutChange;
+  }
+
+  auto[required_capabilities, required_extensions] =
+      DetermineRequiredCapabilitiesAndExtensions();
+
+  Pass::Status capStatus = TrimUnrequiredCapabilities(required_capabilities);
+  Pass::Status extStatus = TrimUnrequiredExtensions(required_extensions);
+
+  return capStatus == Pass::Status::SuccessWithChange ||
+                 extStatus == Pass::Status::SuccessWithChange
+             ? Pass::Status::SuccessWithChange
+             : Pass::Status::SuccessWithoutChange;
+}
+
+}  // namespace opt
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/opt/trim_capabilities_pass.h b/third_party/SPIRV-Tools/source/opt/trim_capabilities_pass.h
new file mode 100644
index 0000000..81c07b8
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/trim_capabilities_pass.h
@@ -0,0 +1,205 @@
+// Copyright (c) 2023 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_TRIM_CAPABILITIES_PASS_H_
+#define SOURCE_OPT_TRIM_CAPABILITIES_PASS_H_
+
+#include <algorithm>
+#include <array>
+#include <functional>
+#include <optional>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "source/enum_set.h"
+#include "source/extensions.h"
+#include "source/opt/ir_context.h"
+#include "source/opt/module.h"
+#include "source/opt/pass.h"
+#include "source/spirv_target_env.h"
+
+namespace spvtools {
+namespace opt {
+
+// This is required for NDK build. The unordered_set/unordered_map
+// implementation don't work with class enums.
+struct ClassEnumHash {
+  std::size_t operator()(spv::Capability value) const {
+    using StoringType = typename std::underlying_type_t<spv::Capability>;
+    return std::hash<StoringType>{}(static_cast<StoringType>(value));
+  }
+
+  std::size_t operator()(spv::Op value) const {
+    using StoringType = typename std::underlying_type_t<spv::Op>;
+    return std::hash<StoringType>{}(static_cast<StoringType>(value));
+  }
+};
+
+// An opcode handler is a function which, given an instruction, returns either
+// the required capability, or nothing.
+// Each handler checks one case for a capability requirement.
+//
+// Example:
+//  - `OpTypeImage` can have operand `A` operand which requires capability 1
+//  - `OpTypeImage` can also have operand `B` which requires capability 2.
+//    -> We have 2 handlers: `Handler_OpTypeImage_1` and
+//    `Handler_OpTypeImage_2`.
+using OpcodeHandler =
+    std::optional<spv::Capability> (*)(const Instruction* instruction);
+
+// This pass tried to remove superfluous capabilities declared in the module.
+// - If all the capabilities listed by an extension are removed, the extension
+//   is also trimmed.
+// - If the module countains any capability listed in `kForbiddenCapabilities`,
+//   the module is left untouched.
+// - No capabilities listed in `kUntouchableCapabilities` are trimmed, even when
+//   not used.
+// - Only capabilitied listed in `kSupportedCapabilities` are supported.
+// - If the module contains unsupported capabilities, results might be
+//   incorrect.
+class TrimCapabilitiesPass : public Pass {
+ private:
+  // All the capabilities supported by this optimization pass. If your module
+  // contains unsupported instruction, the pass could yield bad results.
+  static constexpr std::array kSupportedCapabilities{
+      // clang-format off
+      spv::Capability::ComputeDerivativeGroupLinearNV,
+      spv::Capability::ComputeDerivativeGroupQuadsNV,
+      spv::Capability::Float16,
+      spv::Capability::Float64,
+      spv::Capability::FragmentShaderPixelInterlockEXT,
+      spv::Capability::FragmentShaderSampleInterlockEXT,
+      spv::Capability::FragmentShaderShadingRateInterlockEXT,
+      spv::Capability::Groups,
+      spv::Capability::ImageMSArray,
+      spv::Capability::Int16,
+      spv::Capability::Int64,
+      spv::Capability::Linkage,
+      spv::Capability::MinLod,
+      spv::Capability::PhysicalStorageBufferAddresses,
+      spv::Capability::RayQueryKHR,
+      spv::Capability::RayTracingKHR,
+      spv::Capability::RayTraversalPrimitiveCullingKHR,
+      spv::Capability::Shader,
+      spv::Capability::ShaderClockKHR,
+      spv::Capability::StorageImageReadWithoutFormat,
+      spv::Capability::StorageInputOutput16,
+      spv::Capability::StoragePushConstant16,
+      spv::Capability::StorageUniform16,
+      spv::Capability::StorageUniformBufferBlock16,
+      spv::Capability::VulkanMemoryModelDeviceScope,
+      spv::Capability::GroupNonUniformPartitionedNV
+      // clang-format on
+  };
+
+  // Those capabilities disable all transformation of the module.
+  static constexpr std::array kForbiddenCapabilities{
+      spv::Capability::Linkage,
+  };
+
+  // Those capabilities are never removed from a module because we cannot
+  // guess from the SPIR-V only if they are required or not.
+  static constexpr std::array kUntouchableCapabilities{
+      spv::Capability::Shader,
+  };
+
+ public:
+  TrimCapabilitiesPass();
+  TrimCapabilitiesPass(const TrimCapabilitiesPass&) = delete;
+  TrimCapabilitiesPass(TrimCapabilitiesPass&&) = delete;
+
+ private:
+  // Inserts every capability listed by `descriptor` this pass supports into
+  // `output`. Expects a Descriptor like `spv_opcode_desc_t` or
+  // `spv_operand_desc_t`.
+  template <class Descriptor>
+  inline void addSupportedCapabilitiesToSet(const Descriptor* const descriptor,
+                                            CapabilitySet* output) const {
+    const uint32_t capabilityCount = descriptor->numCapabilities;
+    for (uint32_t i = 0; i < capabilityCount; ++i) {
+      const auto capability = descriptor->capabilities[i];
+      if (supportedCapabilities_.contains(capability)) {
+        output->insert(capability);
+      }
+    }
+  }
+
+  // Inserts every extension listed by `descriptor` required by the module into
+  // `output`. Expects a Descriptor like `spv_opcode_desc_t` or
+  // `spv_operand_desc_t`.
+  template <class Descriptor>
+  inline void addSupportedExtensionsToSet(const Descriptor* const descriptor,
+                                          ExtensionSet* output) const {
+    if (descriptor->minVersion <=
+        spvVersionForTargetEnv(context()->GetTargetEnv())) {
+      return;
+    }
+    output->insert(descriptor->extensions,
+                   descriptor->extensions + descriptor->numExtensions);
+  }
+
+  void addInstructionRequirementsForOpcode(spv::Op opcode,
+                                           CapabilitySet* capabilities,
+                                           ExtensionSet* extensions) const;
+  void addInstructionRequirementsForOperand(const Operand& operand,
+                                            CapabilitySet* capabilities,
+                                            ExtensionSet* extensions) const;
+
+  // Given an `instruction`, determines the capabilities it requires, and output
+  // them in `capabilities`. The returned capabilities form a subset of
+  // kSupportedCapabilities.
+  void addInstructionRequirements(Instruction* instruction,
+                                  CapabilitySet* capabilities,
+                                  ExtensionSet* extensions) const;
+
+  // Given an operand `type` and `value`, adds the extensions it would require
+  // to `extensions`.
+  void AddExtensionsForOperand(const spv_operand_type_t type,
+                               const uint32_t value,
+                               ExtensionSet* extensions) const;
+
+  // Returns the list of required capabilities and extensions for the module.
+  // The returned capabilities form a subset of kSupportedCapabilities.
+  std::pair<CapabilitySet, ExtensionSet>
+  DetermineRequiredCapabilitiesAndExtensions() const;
+
+  // Trims capabilities not listed in `required_capabilities` if possible.
+  // Returns whether or not the module was modified.
+  Pass::Status TrimUnrequiredCapabilities(
+      const CapabilitySet& required_capabilities) const;
+
+  // Trims extensions not listed in `required_extensions` if supported by this
+  // pass. An extensions is considered supported as soon as one capability this
+  // pass support requires it.
+  Pass::Status TrimUnrequiredExtensions(
+      const ExtensionSet& required_extensions) const;
+
+  // Returns if the analyzed module contains any forbidden capability.
+  bool HasForbiddenCapabilities() const;
+
+ public:
+  const char* name() const override { return "trim-capabilities"; }
+  Status Process() override;
+
+ private:
+  const CapabilitySet supportedCapabilities_;
+  const CapabilitySet forbiddenCapabilities_;
+  const CapabilitySet untouchableCapabilities_;
+  const std::unordered_multimap<spv::Op, OpcodeHandler, ClassEnumHash>
+      opcodeHandlers_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+#endif  // SOURCE_OPT_TRIM_CAPABILITIES_H_
diff --git a/third_party/SPIRV-Tools/source/opt/type_manager.cpp b/third_party/SPIRV-Tools/source/opt/type_manager.cpp
index 1b1aead..7b609bc 100644
--- a/third_party/SPIRV-Tools/source/opt/type_manager.cpp
+++ b/third_party/SPIRV-Tools/source/opt/type_manager.cpp
@@ -423,6 +423,23 @@
               {SPV_OPERAND_TYPE_ID, {coop_mat->columns_id()}}});
       break;
     }
+    case Type::kCooperativeMatrixKHR: {
+      auto coop_mat = type->AsCooperativeMatrixKHR();
+      uint32_t const component_type =
+          GetTypeInstruction(coop_mat->component_type());
+      if (component_type == 0) {
+        return 0;
+      }
+      typeInst = MakeUnique<Instruction>(
+          context(), spv::Op::OpTypeCooperativeMatrixKHR, 0, id,
+          std::initializer_list<Operand>{
+              {SPV_OPERAND_TYPE_ID, {component_type}},
+              {SPV_OPERAND_TYPE_SCOPE_ID, {coop_mat->scope_id()}},
+              {SPV_OPERAND_TYPE_ID, {coop_mat->rows_id()}},
+              {SPV_OPERAND_TYPE_ID, {coop_mat->columns_id()}},
+              {SPV_OPERAND_TYPE_ID, {coop_mat->use_id()}}});
+      break;
+    }
     default:
       assert(false && "Unexpected type");
       break;
@@ -500,13 +517,24 @@
   context()->get_def_use_mgr()->AnalyzeInstUse(inst);
 }
 
-Type* TypeManager::RebuildType(const Type& type) {
+Type* TypeManager::RebuildType(uint32_t type_id, const Type& type) {
+  assert(type_id != 0);
+
   // The comparison and hash on the type pool will avoid inserting the rebuilt
   // type if an equivalent type already exists. The rebuilt type will be deleted
   // when it goes out of scope at the end of the function in that case. Repeated
   // insertions of the same Type will, at most, keep one corresponding object in
   // the type pool.
   std::unique_ptr<Type> rebuilt_ty;
+
+  // If |type_id| is already present in the type pool, return the existing type.
+  // This saves extra work in the type builder and prevents running into
+  // circular issues (https://github.com/KhronosGroup/SPIRV-Tools/issues/5623).
+  Type* pool_ty = GetType(type_id);
+  if (pool_ty != nullptr) {
+    return pool_ty;
+  }
+
   switch (type.kind()) {
 #define DefineNoSubtypeCase(kind)             \
   case Type::k##kind:                         \
@@ -533,43 +561,46 @@
     case Type::kVector: {
       const Vector* vec_ty = type.AsVector();
       const Type* ele_ty = vec_ty->element_type();
-      rebuilt_ty =
-          MakeUnique<Vector>(RebuildType(*ele_ty), vec_ty->element_count());
+      rebuilt_ty = MakeUnique<Vector>(RebuildType(GetId(ele_ty), *ele_ty),
+                                      vec_ty->element_count());
       break;
     }
     case Type::kMatrix: {
       const Matrix* mat_ty = type.AsMatrix();
       const Type* ele_ty = mat_ty->element_type();
-      rebuilt_ty =
-          MakeUnique<Matrix>(RebuildType(*ele_ty), mat_ty->element_count());
+      rebuilt_ty = MakeUnique<Matrix>(RebuildType(GetId(ele_ty), *ele_ty),
+                                      mat_ty->element_count());
       break;
     }
     case Type::kImage: {
       const Image* image_ty = type.AsImage();
       const Type* ele_ty = image_ty->sampled_type();
-      rebuilt_ty =
-          MakeUnique<Image>(RebuildType(*ele_ty), image_ty->dim(),
-                            image_ty->depth(), image_ty->is_arrayed(),
-                            image_ty->is_multisampled(), image_ty->sampled(),
-                            image_ty->format(), image_ty->access_qualifier());
+      rebuilt_ty = MakeUnique<Image>(
+          RebuildType(GetId(ele_ty), *ele_ty), image_ty->dim(),
+          image_ty->depth(), image_ty->is_arrayed(),
+          image_ty->is_multisampled(), image_ty->sampled(), image_ty->format(),
+          image_ty->access_qualifier());
       break;
     }
     case Type::kSampledImage: {
       const SampledImage* image_ty = type.AsSampledImage();
       const Type* ele_ty = image_ty->image_type();
-      rebuilt_ty = MakeUnique<SampledImage>(RebuildType(*ele_ty));
+      rebuilt_ty =
+          MakeUnique<SampledImage>(RebuildType(GetId(ele_ty), *ele_ty));
       break;
     }
     case Type::kArray: {
       const Array* array_ty = type.AsArray();
-      rebuilt_ty =
-          MakeUnique<Array>(array_ty->element_type(), array_ty->length_info());
+      const Type* ele_ty = array_ty->element_type();
+      rebuilt_ty = MakeUnique<Array>(RebuildType(GetId(ele_ty), *ele_ty),
+                                     array_ty->length_info());
       break;
     }
     case Type::kRuntimeArray: {
       const RuntimeArray* array_ty = type.AsRuntimeArray();
       const Type* ele_ty = array_ty->element_type();
-      rebuilt_ty = MakeUnique<RuntimeArray>(RebuildType(*ele_ty));
+      rebuilt_ty =
+          MakeUnique<RuntimeArray>(RebuildType(GetId(ele_ty), *ele_ty));
       break;
     }
     case Type::kStruct: {
@@ -577,7 +608,7 @@
       std::vector<const Type*> subtypes;
       subtypes.reserve(struct_ty->element_types().size());
       for (const auto* ele_ty : struct_ty->element_types()) {
-        subtypes.push_back(RebuildType(*ele_ty));
+        subtypes.push_back(RebuildType(GetId(ele_ty), *ele_ty));
       }
       rebuilt_ty = MakeUnique<Struct>(subtypes);
       Struct* rebuilt_struct = rebuilt_ty->AsStruct();
@@ -594,7 +625,7 @@
     case Type::kPointer: {
       const Pointer* pointer_ty = type.AsPointer();
       const Type* ele_ty = pointer_ty->pointee_type();
-      rebuilt_ty = MakeUnique<Pointer>(RebuildType(*ele_ty),
+      rebuilt_ty = MakeUnique<Pointer>(RebuildType(GetId(ele_ty), *ele_ty),
                                        pointer_ty->storage_class());
       break;
     }
@@ -604,9 +635,10 @@
       std::vector<const Type*> param_types;
       param_types.reserve(function_ty->param_types().size());
       for (const auto* param_ty : function_ty->param_types()) {
-        param_types.push_back(RebuildType(*param_ty));
+        param_types.push_back(RebuildType(GetId(param_ty), *param_ty));
       }
-      rebuilt_ty = MakeUnique<Function>(RebuildType(*ret_ty), param_types);
+      rebuilt_ty = MakeUnique<Function>(RebuildType(GetId(ret_ty), *ret_ty),
+                                        param_types);
       break;
     }
     case Type::kForwardPointer: {
@@ -616,7 +648,7 @@
       const Pointer* target_ptr = forward_ptr_ty->target_pointer();
       if (target_ptr) {
         rebuilt_ty->AsForwardPointer()->SetTargetPointer(
-            RebuildType(*target_ptr)->AsPointer());
+            RebuildType(GetId(target_ptr), *target_ptr)->AsPointer());
       }
       break;
     }
@@ -624,8 +656,17 @@
       const CooperativeMatrixNV* cm_type = type.AsCooperativeMatrixNV();
       const Type* component_type = cm_type->component_type();
       rebuilt_ty = MakeUnique<CooperativeMatrixNV>(
-          RebuildType(*component_type), cm_type->scope_id(), cm_type->rows_id(),
-          cm_type->columns_id());
+          RebuildType(GetId(component_type), *component_type),
+          cm_type->scope_id(), cm_type->rows_id(), cm_type->columns_id());
+      break;
+    }
+    case Type::kCooperativeMatrixKHR: {
+      const CooperativeMatrixKHR* cm_type = type.AsCooperativeMatrixKHR();
+      const Type* component_type = cm_type->component_type();
+      rebuilt_ty = MakeUnique<CooperativeMatrixKHR>(
+          RebuildType(GetId(component_type), *component_type),
+          cm_type->scope_id(), cm_type->rows_id(), cm_type->columns_id(),
+          cm_type->use_id());
       break;
     }
     default:
@@ -644,7 +685,7 @@
 void TypeManager::RegisterType(uint32_t id, const Type& type) {
   // Rebuild |type| so it and all its constituent types are owned by the type
   // pool.
-  Type* rebuilt = RebuildType(type);
+  Type* rebuilt = RebuildType(id, type);
   assert(rebuilt->IsSame(&type));
   id_to_type_[id] = rebuilt;
   if (GetId(rebuilt) == 0) {
@@ -863,6 +904,12 @@
                                      inst.GetSingleWordInOperand(2),
                                      inst.GetSingleWordInOperand(3));
       break;
+    case spv::Op::OpTypeCooperativeMatrixKHR:
+      type = new CooperativeMatrixKHR(
+          GetType(inst.GetSingleWordInOperand(0)),
+          inst.GetSingleWordInOperand(1), inst.GetSingleWordInOperand(2),
+          inst.GetSingleWordInOperand(3), inst.GetSingleWordInOperand(4));
+      break;
     case spv::Op::OpTypeRayQueryKHR:
       type = new RayQueryKHR();
       break;
@@ -870,7 +917,7 @@
       type = new HitObjectNV();
       break;
     default:
-      SPIRV_UNIMPLEMENTED(consumer_, "unhandled type");
+      assert(false && "Type not handled by the type manager.");
       break;
   }
 
@@ -912,12 +959,10 @@
       }
       if (Struct* st = type->AsStruct()) {
         st->AddMemberDecoration(index, std::move(data));
-      } else {
-        SPIRV_UNIMPLEMENTED(consumer_, "OpMemberDecorate non-struct type");
       }
     } break;
     default:
-      SPIRV_UNREACHABLE(consumer_);
+      assert(false && "Unexpected opcode for a decoration instruction.");
       break;
   }
 }
diff --git a/third_party/SPIRV-Tools/source/opt/type_manager.h b/third_party/SPIRV-Tools/source/opt/type_manager.h
index c49e193..948b691 100644
--- a/third_party/SPIRV-Tools/source/opt/type_manager.h
+++ b/third_party/SPIRV-Tools/source/opt/type_manager.h
@@ -144,18 +144,17 @@
   // |type| (e.g. should be called in loop of |type|'s decorations).
   void AttachDecoration(const Instruction& inst, Type* type);
 
-  Type* GetUIntType() {
-    Integer int_type(32, false);
-    return GetRegisteredType(&int_type);
-  }
+  Type* GetUIntType() { return GetIntType(32, false); }
 
   uint32_t GetUIntTypeId() { return GetTypeInstruction(GetUIntType()); }
 
-  Type* GetSIntType() {
-    Integer int_type(32, true);
+  Type* GetIntType(int32_t bitWidth, bool isSigned) {
+    Integer int_type(bitWidth, isSigned);
     return GetRegisteredType(&int_type);
   }
 
+  Type* GetSIntType() { return GetIntType(32, true); }
+
   uint32_t GetSIntTypeId() { return GetTypeInstruction(GetSIntType()); }
 
   Type* GetFloatType() {
@@ -261,7 +260,9 @@
   // Returns an equivalent pointer to |type| built in terms of pointers owned by
   // |type_pool_|. For example, if |type| is a vec3 of bool, it will be rebuilt
   // replacing the bool subtype with one owned by |type_pool_|.
-  Type* RebuildType(const Type& type);
+  //
+  // The re-built type will have ID |type_id|.
+  Type* RebuildType(uint32_t type_id, const Type& type);
 
   // Completes the incomplete type |type|, by replaces all references to
   // ForwardPointer by the defining Pointer.
diff --git a/third_party/SPIRV-Tools/source/opt/types.cpp b/third_party/SPIRV-Tools/source/opt/types.cpp
index 49eec9b..b18b8cb 100644
--- a/third_party/SPIRV-Tools/source/opt/types.cpp
+++ b/third_party/SPIRV-Tools/source/opt/types.cpp
@@ -128,6 +128,7 @@
     DeclareKindCase(NamedBarrier);
     DeclareKindCase(AccelerationStructureNV);
     DeclareKindCase(CooperativeMatrixNV);
+    DeclareKindCase(CooperativeMatrixKHR);
     DeclareKindCase(RayQueryKHR);
     DeclareKindCase(HitObjectNV);
 #undef DeclareKindCase
@@ -175,6 +176,7 @@
     DeclareKindCase(NamedBarrier);
     DeclareKindCase(AccelerationStructureNV);
     DeclareKindCase(CooperativeMatrixNV);
+    DeclareKindCase(CooperativeMatrixKHR);
     DeclareKindCase(RayQueryKHR);
     DeclareKindCase(HitObjectNV);
 #undef DeclareKindCase
@@ -230,6 +232,7 @@
     DeclareKindCase(NamedBarrier);
     DeclareKindCase(AccelerationStructureNV);
     DeclareKindCase(CooperativeMatrixNV);
+    DeclareKindCase(CooperativeMatrixKHR);
     DeclareKindCase(RayQueryKHR);
     DeclareKindCase(HitObjectNV);
 #undef DeclareKindCase
@@ -708,6 +711,45 @@
          columns_id_ == mt->columns_id_ && HasSameDecorations(that);
 }
 
+CooperativeMatrixKHR::CooperativeMatrixKHR(const Type* type,
+                                           const uint32_t scope,
+                                           const uint32_t rows,
+                                           const uint32_t columns,
+                                           const uint32_t use)
+    : Type(kCooperativeMatrixKHR),
+      component_type_(type),
+      scope_id_(scope),
+      rows_id_(rows),
+      columns_id_(columns),
+      use_id_(use) {
+  assert(type != nullptr);
+  assert(scope != 0);
+  assert(rows != 0);
+  assert(columns != 0);
+}
+
+std::string CooperativeMatrixKHR::str() const {
+  std::ostringstream oss;
+  oss << "<" << component_type_->str() << ", " << scope_id_ << ", " << rows_id_
+      << ", " << columns_id_ << ", " << use_id_ << ">";
+  return oss.str();
+}
+
+size_t CooperativeMatrixKHR::ComputeExtraStateHash(size_t hash,
+                                                   SeenTypes* seen) const {
+  hash = hash_combine(hash, scope_id_, rows_id_, columns_id_, use_id_);
+  return component_type_->ComputeHashValue(hash, seen);
+}
+
+bool CooperativeMatrixKHR::IsSameImpl(const Type* that,
+                                      IsSameCache* seen) const {
+  const CooperativeMatrixKHR* mt = that->AsCooperativeMatrixKHR();
+  if (!mt) return false;
+  return component_type_->IsSameImpl(mt->component_type_, seen) &&
+         scope_id_ == mt->scope_id_ && rows_id_ == mt->rows_id_ &&
+         columns_id_ == mt->columns_id_ && HasSameDecorations(that);
+}
+
 }  // namespace analysis
 }  // namespace opt
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/opt/types.h b/third_party/SPIRV-Tools/source/opt/types.h
index 26c058c..16a948c 100644
--- a/third_party/SPIRV-Tools/source/opt/types.h
+++ b/third_party/SPIRV-Tools/source/opt/types.h
@@ -60,6 +60,7 @@
 class NamedBarrier;
 class AccelerationStructureNV;
 class CooperativeMatrixNV;
+class CooperativeMatrixKHR;
 class RayQueryKHR;
 class HitObjectNV;
 
@@ -100,6 +101,7 @@
     kNamedBarrier,
     kAccelerationStructureNV,
     kCooperativeMatrixNV,
+    kCooperativeMatrixKHR,
     kRayQueryKHR,
     kHitObjectNV,
     kLast
@@ -201,6 +203,7 @@
   DeclareCastMethod(NamedBarrier)
   DeclareCastMethod(AccelerationStructureNV)
   DeclareCastMethod(CooperativeMatrixNV)
+  DeclareCastMethod(CooperativeMatrixKHR)
   DeclareCastMethod(RayQueryKHR)
   DeclareCastMethod(HitObjectNV)
 #undef DeclareCastMethod
@@ -624,6 +627,38 @@
   const uint32_t columns_id_;
 };
 
+class CooperativeMatrixKHR : public Type {
+ public:
+  CooperativeMatrixKHR(const Type* type, const uint32_t scope,
+                       const uint32_t rows, const uint32_t columns,
+                       const uint32_t use);
+  CooperativeMatrixKHR(const CooperativeMatrixKHR&) = default;
+
+  std::string str() const override;
+
+  CooperativeMatrixKHR* AsCooperativeMatrixKHR() override { return this; }
+  const CooperativeMatrixKHR* AsCooperativeMatrixKHR() const override {
+    return this;
+  }
+
+  size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
+
+  const Type* component_type() const { return component_type_; }
+  uint32_t scope_id() const { return scope_id_; }
+  uint32_t rows_id() const { return rows_id_; }
+  uint32_t columns_id() const { return columns_id_; }
+  uint32_t use_id() const { return use_id_; }
+
+ private:
+  bool IsSameImpl(const Type* that, IsSameCache*) const override;
+
+  const Type* component_type_;
+  const uint32_t scope_id_;
+  const uint32_t rows_id_;
+  const uint32_t columns_id_;
+  const uint32_t use_id_;
+};
+
 #define DefineParameterlessType(type, name)                                \
   class type : public Type {                                               \
    public:                                                                 \
diff --git a/third_party/SPIRV-Tools/source/parsed_operand.cpp b/third_party/SPIRV-Tools/source/parsed_operand.cpp
index 5f8e94d..cc33f8b 100644
--- a/third_party/SPIRV-Tools/source/parsed_operand.cpp
+++ b/third_party/SPIRV-Tools/source/parsed_operand.cpp
@@ -24,6 +24,7 @@
 void EmitNumericLiteral(std::ostream* out, const spv_parsed_instruction_t& inst,
                         const spv_parsed_operand_t& operand) {
   if (operand.type != SPV_OPERAND_TYPE_LITERAL_INTEGER &&
+      operand.type != SPV_OPERAND_TYPE_LITERAL_FLOAT &&
       operand.type != SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER &&
       operand.type != SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER &&
       operand.type != SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER)
diff --git a/third_party/SPIRV-Tools/source/print.cpp b/third_party/SPIRV-Tools/source/print.cpp
index 6c94e2b..f36812e 100644
--- a/third_party/SPIRV-Tools/source/print.cpp
+++ b/third_party/SPIRV-Tools/source/print.cpp
@@ -17,7 +17,7 @@
 #if defined(SPIRV_ANDROID) || defined(SPIRV_LINUX) || defined(SPIRV_MAC) || \
     defined(SPIRV_IOS) || defined(SPIRV_TVOS) || defined(SPIRV_FREEBSD) ||  \
     defined(SPIRV_OPENBSD) || defined(SPIRV_EMSCRIPTEN) ||                  \
-    defined(SPIRV_FUCHSIA) || defined(SPIRV_GNU)
+    defined(SPIRV_FUCHSIA) || defined(SPIRV_GNU) || defined(SPIRV_QNX)
 namespace spvtools {
 
 clr::reset::operator const char*() { return "\x1b[0m"; }
diff --git a/third_party/SPIRV-Tools/source/table.h b/third_party/SPIRV-Tools/source/table.h
index 8097f13..4f1dc1f 100644
--- a/third_party/SPIRV-Tools/source/table.h
+++ b/third_party/SPIRV-Tools/source/table.h
@@ -74,7 +74,7 @@
   const uint32_t ext_inst;
   const uint32_t numCapabilities;
   const spv::Capability* capabilities;
-  const spv_operand_type_t operandTypes[16];  // TODO: Smaller/larger?
+  const spv_operand_type_t operandTypes[40];  // vksp needs at least 40
 } spv_ext_inst_desc_t;
 
 typedef struct spv_ext_inst_group_t {
diff --git a/third_party/SPIRV-Tools/source/text.cpp b/third_party/SPIRV-Tools/source/text.cpp
index 8f77d62..263bacd 100644
--- a/third_party/SPIRV-Tools/source/text.cpp
+++ b/third_party/SPIRV-Tools/source/text.cpp
@@ -312,6 +312,17 @@
       }
     } break;
 
+    case SPV_OPERAND_TYPE_LITERAL_FLOAT: {
+      // The current operand is a 32-bit float.
+      // That's just how the grammar works.
+      spvtools::IdType expected_type = {
+          32, false, spvtools::IdTypeClass::kScalarFloatType};
+      if (auto error = context->binaryEncodeNumericLiteral(
+              textValue, error_code_for_literals, expected_type, pInst)) {
+        return error;
+      }
+    } break;
+
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
       // This is a context-independent literal number which can be a 32-bit
       // number of floating point value.
@@ -400,9 +411,11 @@
     case SPV_OPERAND_TYPE_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
+    case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
     case SPV_OPERAND_TYPE_SELECTION_CONTROL:
     case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
-    case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: {
+    case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
+    case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: {
       uint32_t value;
       if (auto error = grammar.parseMaskOperand(type, textValue, &value)) {
         return context->diagnostic(error)
@@ -544,7 +557,8 @@
     std::string equal_sign;
     error = context->getWord(&equal_sign, &nextPosition);
     if ("=" != equal_sign)
-      return context->diagnostic() << "'=' expected after result id.";
+      return context->diagnostic() << "'=' expected after result id but found '"
+                                   << equal_sign << "'.";
 
     // The <opcode> after the '=' sign.
     context->setPosition(nextPosition);
diff --git a/third_party/SPIRV-Tools/source/val/validate.cpp b/third_party/SPIRV-Tools/source/val/validate.cpp
index e73e466..3236807 100644
--- a/third_party/SPIRV-Tools/source/val/validate.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate.cpp
@@ -141,6 +141,13 @@
     }
   }
 
+  if (auto error = ValidateFloatControls2(_)) {
+    return error;
+  }
+  if (auto error = ValidateDuplicateExecutionModes(_)) {
+    return error;
+  }
+
   return SPV_SUCCESS;
 }
 
@@ -381,6 +388,8 @@
   for (const auto& inst : vstate->ordered_instructions()) {
     if (auto error = ValidateExecutionLimitations(*vstate, &inst)) return error;
     if (auto error = ValidateSmallTypeUses(*vstate, &inst)) return error;
+    if (auto error = ValidateQCOMImageProcessingTextureUsages(*vstate, &inst))
+      return error;
   }
 
   return SPV_SUCCESS;
diff --git a/third_party/SPIRV-Tools/source/val/validate.h b/third_party/SPIRV-Tools/source/val/validate.h
index 2cd229f..78093ce 100644
--- a/third_party/SPIRV-Tools/source/val/validate.h
+++ b/third_party/SPIRV-Tools/source/val/validate.h
@@ -82,6 +82,25 @@
 /// @return SPV_SUCCESS if no errors are found.
 spv_result_t ValidateInterfaces(ValidationState_t& _);
 
+/// @brief Validates entry point call tree requirements of
+/// SPV_KHR_float_controls2
+///
+/// Checks that no entry point using FPFastMathDefault uses:
+/// * FPFastMathMode Fast
+/// * NoContraction
+///
+/// @param[in] _ the validation state of the module
+///
+/// @return SPV_SUCCESS if no errors are found.
+spv_result_t ValidateFloatControls2(ValidationState_t& _);
+
+/// @brief Validates duplicated execution modes for each entry point.
+///
+/// @param[in] _ the validation state of the module
+///
+/// @return SPV_SUCCESS if no errors are found.
+spv_result_t ValidateDuplicateExecutionModes(ValidationState_t& _);
+
 /// @brief Validates memory instructions
 ///
 /// @param[in] _ the validation state of the module
@@ -220,6 +239,14 @@
 spv_result_t ValidateSmallTypeUses(ValidationState_t& _,
                                    const Instruction* inst);
 
+/// Validates restricted uses of QCOM decorated textures
+///
+/// The textures that are decorated with some of QCOM image processing
+/// decorations must be used in the specified QCOM image processing built-in
+/// functions and not used in any other image functions.
+spv_result_t ValidateQCOMImageProcessingTextureUsages(ValidationState_t& _,
+                                                      const Instruction* inst);
+
 /// @brief Validate the ID's within a SPIR-V binary
 ///
 /// @param[in] pInstructions array of instructions
diff --git a/third_party/SPIRV-Tools/source/val/validate_annotation.cpp b/third_party/SPIRV-Tools/source/val/validate_annotation.cpp
index 73d0285..dac3585 100644
--- a/third_party/SPIRV-Tools/source/val/validate_annotation.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_annotation.cpp
@@ -161,7 +161,8 @@
     case spv::Decoration::RestrictPointer:
     case spv::Decoration::AliasedPointer:
       if (target->opcode() != spv::Op::OpVariable &&
-          target->opcode() != spv::Op::OpFunctionParameter) {
+          target->opcode() != spv::Op::OpFunctionParameter &&
+          target->opcode() != spv::Op::OpRawAccessChainNV) {
         return fail(0) << "must be a memory object declaration";
       }
       if (_.GetIdOpcode(target->type_id()) != spv::Op::OpTypePointer) {
@@ -267,6 +268,34 @@
     }
   }
 
+  if (decoration == spv::Decoration::FPFastMathMode) {
+    if (_.HasDecoration(target_id, spv::Decoration::NoContraction)) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "FPFastMathMode and NoContraction cannot decorate the same "
+                "target";
+    }
+    auto mask = inst->GetOperandAs<spv::FPFastMathModeMask>(2);
+    if ((mask & spv::FPFastMathModeMask::AllowTransform) !=
+            spv::FPFastMathModeMask::MaskNone &&
+        ((mask & (spv::FPFastMathModeMask::AllowContract |
+                  spv::FPFastMathModeMask::AllowReassoc)) !=
+         (spv::FPFastMathModeMask::AllowContract |
+          spv::FPFastMathModeMask::AllowReassoc))) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "AllowReassoc and AllowContract must be specified when "
+                "AllowTransform is specified";
+    }
+  }
+
+  // This is checked from both sides since we register decorations as we go.
+  if (decoration == spv::Decoration::NoContraction) {
+    if (_.HasDecoration(target_id, spv::Decoration::FPFastMathMode)) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "FPFastMathMode and NoContraction cannot decorate the same "
+                "target";
+    }
+  }
+
   if (DecorationTakesIdParameters(decoration)) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
            << "Decorations taking ID parameters may not be used with "
diff --git a/third_party/SPIRV-Tools/source/val/validate_arithmetics.cpp b/third_party/SPIRV-Tools/source/val/validate_arithmetics.cpp
index 4e7dd5e..b608a85 100644
--- a/third_party/SPIRV-Tools/source/val/validate_arithmetics.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_arithmetics.cpp
@@ -42,14 +42,29 @@
            opcode != spv::Op::OpFMod);
       if (!_.IsFloatScalarType(result_type) &&
           !_.IsFloatVectorType(result_type) &&
-          !(supportsCoopMat && _.IsFloatCooperativeMatrixType(result_type)))
+          !(supportsCoopMat && _.IsFloatCooperativeMatrixType(result_type)) &&
+          !(opcode == spv::Op::OpFMul &&
+            _.IsCooperativeMatrixKHRType(result_type) &&
+            _.IsFloatCooperativeMatrixType(result_type)))
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected floating scalar or vector type as Result Type: "
                << spvOpcodeString(opcode);
 
       for (size_t operand_index = 2; operand_index < inst->operands().size();
            ++operand_index) {
-        if (_.GetOperandTypeId(inst, operand_index) != result_type)
+        if (supportsCoopMat && _.IsCooperativeMatrixKHRType(result_type)) {
+          const uint32_t type_id = _.GetOperandTypeId(inst, operand_index);
+          if (!_.IsCooperativeMatrixKHRType(type_id) ||
+              !_.IsFloatCooperativeMatrixType(type_id)) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << "Expected arithmetic operands to be of Result Type: "
+                   << spvOpcodeString(opcode) << " operand index "
+                   << operand_index;
+          }
+          spv_result_t ret =
+              _.CooperativeMatrixShapesMatch(inst, type_id, result_type);
+          if (ret != SPV_SUCCESS) return ret;
+        } else if (_.GetOperandTypeId(inst, operand_index) != result_type)
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
                  << "Expected arithmetic operands to be of Result Type: "
                  << spvOpcodeString(opcode) << " operand index "
@@ -71,7 +86,19 @@
 
       for (size_t operand_index = 2; operand_index < inst->operands().size();
            ++operand_index) {
-        if (_.GetOperandTypeId(inst, operand_index) != result_type)
+        if (supportsCoopMat && _.IsCooperativeMatrixKHRType(result_type)) {
+          const uint32_t type_id = _.GetOperandTypeId(inst, operand_index);
+          if (!_.IsCooperativeMatrixKHRType(type_id) ||
+              !_.IsUnsignedIntCooperativeMatrixType(type_id)) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << "Expected arithmetic operands to be of Result Type: "
+                   << spvOpcodeString(opcode) << " operand index "
+                   << operand_index;
+          }
+          spv_result_t ret =
+              _.CooperativeMatrixShapesMatch(inst, type_id, result_type);
+          if (ret != SPV_SUCCESS) return ret;
+        } else if (_.GetOperandTypeId(inst, operand_index) != result_type)
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
                  << "Expected arithmetic operands to be of Result Type: "
                  << spvOpcodeString(opcode) << " operand index "
@@ -91,7 +118,10 @@
           (opcode != spv::Op::OpIMul && opcode != spv::Op::OpSRem &&
            opcode != spv::Op::OpSMod);
       if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) &&
-          !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type)))
+          !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type)) &&
+          !(opcode == spv::Op::OpIMul &&
+            _.IsCooperativeMatrixKHRType(result_type) &&
+            _.IsIntCooperativeMatrixType(result_type)))
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected int scalar or vector type as Result Type: "
                << spvOpcodeString(opcode);
@@ -102,9 +132,26 @@
       for (size_t operand_index = 2; operand_index < inst->operands().size();
            ++operand_index) {
         const uint32_t type_id = _.GetOperandTypeId(inst, operand_index);
+
+        if (supportsCoopMat && _.IsCooperativeMatrixKHRType(result_type)) {
+          if (!_.IsCooperativeMatrixKHRType(type_id) ||
+              !_.IsIntCooperativeMatrixType(type_id)) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << "Expected arithmetic operands to be of Result Type: "
+                   << spvOpcodeString(opcode) << " operand index "
+                   << operand_index;
+          }
+          spv_result_t ret =
+              _.CooperativeMatrixShapesMatch(inst, type_id, result_type);
+          if (ret != SPV_SUCCESS) return ret;
+        }
+
         if (!type_id ||
             (!_.IsIntScalarType(type_id) && !_.IsIntVectorType(type_id) &&
-             !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type))))
+             !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type)) &&
+             !(opcode == spv::Op::OpIMul &&
+               _.IsCooperativeMatrixKHRType(result_type) &&
+               _.IsIntCooperativeMatrixType(result_type))))
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
                  << "Expected int scalar or vector type as operand: "
                  << spvOpcodeString(opcode) << " operand index "
@@ -187,7 +234,7 @@
 
     case spv::Op::OpMatrixTimesScalar: {
       if (!_.IsFloatMatrixType(result_type) &&
-          !_.IsCooperativeMatrixType(result_type))
+          !(_.IsCooperativeMatrixType(result_type)))
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected float matrix type as Result Type: "
                << spvOpcodeString(opcode);
@@ -459,22 +506,108 @@
       const uint32_t B_type_id = _.GetOperandTypeId(inst, 3);
       const uint32_t C_type_id = _.GetOperandTypeId(inst, 4);
 
-      if (!_.IsCooperativeMatrixType(A_type_id)) {
+      if (!_.IsCooperativeMatrixNVType(A_type_id)) {
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected cooperative matrix type as A Type: "
                << spvOpcodeString(opcode);
       }
-      if (!_.IsCooperativeMatrixType(B_type_id)) {
+      if (!_.IsCooperativeMatrixNVType(B_type_id)) {
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected cooperative matrix type as B Type: "
                << spvOpcodeString(opcode);
       }
-      if (!_.IsCooperativeMatrixType(C_type_id)) {
+      if (!_.IsCooperativeMatrixNVType(C_type_id)) {
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected cooperative matrix type as C Type: "
                << spvOpcodeString(opcode);
       }
-      if (!_.IsCooperativeMatrixType(D_type_id)) {
+      if (!_.IsCooperativeMatrixNVType(D_type_id)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Expected cooperative matrix type as Result Type: "
+               << spvOpcodeString(opcode);
+      }
+
+      const auto A = _.FindDef(A_type_id);
+      const auto B = _.FindDef(B_type_id);
+      const auto C = _.FindDef(C_type_id);
+      const auto D = _.FindDef(D_type_id);
+
+      std::tuple<bool, bool, uint32_t> A_scope, B_scope, C_scope, D_scope,
+          A_rows, B_rows, C_rows, D_rows, A_cols, B_cols, C_cols, D_cols;
+
+      A_scope = _.EvalInt32IfConst(A->GetOperandAs<uint32_t>(2));
+      B_scope = _.EvalInt32IfConst(B->GetOperandAs<uint32_t>(2));
+      C_scope = _.EvalInt32IfConst(C->GetOperandAs<uint32_t>(2));
+      D_scope = _.EvalInt32IfConst(D->GetOperandAs<uint32_t>(2));
+
+      A_rows = _.EvalInt32IfConst(A->GetOperandAs<uint32_t>(3));
+      B_rows = _.EvalInt32IfConst(B->GetOperandAs<uint32_t>(3));
+      C_rows = _.EvalInt32IfConst(C->GetOperandAs<uint32_t>(3));
+      D_rows = _.EvalInt32IfConst(D->GetOperandAs<uint32_t>(3));
+
+      A_cols = _.EvalInt32IfConst(A->GetOperandAs<uint32_t>(4));
+      B_cols = _.EvalInt32IfConst(B->GetOperandAs<uint32_t>(4));
+      C_cols = _.EvalInt32IfConst(C->GetOperandAs<uint32_t>(4));
+      D_cols = _.EvalInt32IfConst(D->GetOperandAs<uint32_t>(4));
+
+      const auto notEqual = [](std::tuple<bool, bool, uint32_t> X,
+                               std::tuple<bool, bool, uint32_t> Y) {
+        return (std::get<1>(X) && std::get<1>(Y) &&
+                std::get<2>(X) != std::get<2>(Y));
+      };
+
+      if (notEqual(A_scope, B_scope) || notEqual(A_scope, C_scope) ||
+          notEqual(A_scope, D_scope) || notEqual(B_scope, C_scope) ||
+          notEqual(B_scope, D_scope) || notEqual(C_scope, D_scope)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Cooperative matrix scopes must match: "
+               << spvOpcodeString(opcode);
+      }
+
+      if (notEqual(A_rows, C_rows) || notEqual(A_rows, D_rows) ||
+          notEqual(C_rows, D_rows)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Cooperative matrix 'M' mismatch: "
+               << spvOpcodeString(opcode);
+      }
+
+      if (notEqual(B_cols, C_cols) || notEqual(B_cols, D_cols) ||
+          notEqual(C_cols, D_cols)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Cooperative matrix 'N' mismatch: "
+               << spvOpcodeString(opcode);
+      }
+
+      if (notEqual(A_cols, B_rows)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Cooperative matrix 'K' mismatch: "
+               << spvOpcodeString(opcode);
+      }
+      break;
+    }
+
+    case spv::Op::OpCooperativeMatrixMulAddKHR: {
+      const uint32_t D_type_id = _.GetOperandTypeId(inst, 1);
+      const uint32_t A_type_id = _.GetOperandTypeId(inst, 2);
+      const uint32_t B_type_id = _.GetOperandTypeId(inst, 3);
+      const uint32_t C_type_id = _.GetOperandTypeId(inst, 4);
+
+      if (!_.IsCooperativeMatrixAType(A_type_id)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Cooperative matrix type must be A Type: "
+               << spvOpcodeString(opcode);
+      }
+      if (!_.IsCooperativeMatrixBType(B_type_id)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Cooperative matrix type must be B Type: "
+               << spvOpcodeString(opcode);
+      }
+      if (!_.IsCooperativeMatrixAccType(C_type_id)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Cooperative matrix type must be Accumulator Type: "
+               << spvOpcodeString(opcode);
+      }
+      if (!_.IsCooperativeMatrixKHRType(D_type_id)) {
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected cooperative matrix type as Result Type: "
                << spvOpcodeString(opcode);
diff --git a/third_party/SPIRV-Tools/source/val/validate_atomics.cpp b/third_party/SPIRV-Tools/source/val/validate_atomics.cpp
index b745a9e..8ddef17 100644
--- a/third_party/SPIRV-Tools/source/val/validate_atomics.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_atomics.cpp
@@ -144,12 +144,13 @@
     case spv::Op::OpAtomicFlagClear: {
       const uint32_t result_type = inst->type_id();
 
-      // All current atomics only are scalar result
       // Validate return type first so can just check if pointer type is same
       // (if applicable)
       if (HasReturnType(opcode)) {
         if (HasOnlyFloatReturnType(opcode) &&
-            !_.IsFloatScalarType(result_type)) {
+            (!(_.HasCapability(spv::Capability::AtomicFloat16VectorNV) &&
+               _.IsFloat16Vector2Or4Type(result_type)) &&
+             !_.IsFloatScalarType(result_type))) {
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
                  << spvOpcodeString(opcode)
                  << ": expected Result Type to be float scalar type";
@@ -160,6 +161,9 @@
                  << ": expected Result Type to be integer scalar type";
         } else if (HasIntOrFloatReturnType(opcode) &&
                    !_.IsFloatScalarType(result_type) &&
+                   !(opcode == spv::Op::OpAtomicExchange &&
+                     _.HasCapability(spv::Capability::AtomicFloat16VectorNV) &&
+                     _.IsFloat16Vector2Or4Type(result_type)) &&
                    !_.IsIntScalarType(result_type)) {
           return _.diag(SPV_ERROR_INVALID_DATA, inst)
                  << spvOpcodeString(opcode)
@@ -222,12 +226,21 @@
 
         if (opcode == spv::Op::OpAtomicFAddEXT) {
           // result type being float checked already
-          if ((_.GetBitWidth(result_type) == 16) &&
-              (!_.HasCapability(spv::Capability::AtomicFloat16AddEXT))) {
-            return _.diag(SPV_ERROR_INVALID_DATA, inst)
-                   << spvOpcodeString(opcode)
-                   << ": float add atomics require the AtomicFloat32AddEXT "
-                      "capability";
+          if (_.GetBitWidth(result_type) == 16) {
+            if (_.IsFloat16Vector2Or4Type(result_type)) {
+              if (!_.HasCapability(spv::Capability::AtomicFloat16VectorNV))
+                return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                       << spvOpcodeString(opcode)
+                       << ": float vector atomics require the "
+                          "AtomicFloat16VectorNV capability";
+            } else {
+              if (!_.HasCapability(spv::Capability::AtomicFloat16AddEXT)) {
+                return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                       << spvOpcodeString(opcode)
+                       << ": float add atomics require the AtomicFloat32AddEXT "
+                          "capability";
+              }
+            }
           }
           if ((_.GetBitWidth(result_type) == 32) &&
               (!_.HasCapability(spv::Capability::AtomicFloat32AddEXT))) {
@@ -245,12 +258,21 @@
           }
         } else if (opcode == spv::Op::OpAtomicFMinEXT ||
                    opcode == spv::Op::OpAtomicFMaxEXT) {
-          if ((_.GetBitWidth(result_type) == 16) &&
-              (!_.HasCapability(spv::Capability::AtomicFloat16MinMaxEXT))) {
-            return _.diag(SPV_ERROR_INVALID_DATA, inst)
-                   << spvOpcodeString(opcode)
-                   << ": float min/max atomics require the "
-                      "AtomicFloat16MinMaxEXT capability";
+          if (_.GetBitWidth(result_type) == 16) {
+            if (_.IsFloat16Vector2Or4Type(result_type)) {
+              if (!_.HasCapability(spv::Capability::AtomicFloat16VectorNV))
+                return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                       << spvOpcodeString(opcode)
+                       << ": float vector atomics require the "
+                          "AtomicFloat16VectorNV capability";
+            } else {
+              if (!_.HasCapability(spv::Capability::AtomicFloat16MinMaxEXT)) {
+                return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                       << spvOpcodeString(opcode)
+                       << ": float min/max atomics require the "
+                          "AtomicFloat16MinMaxEXT capability";
+              }
+            }
           }
           if ((_.GetBitWidth(result_type) == 32) &&
               (!_.HasCapability(spv::Capability::AtomicFloat32MinMaxEXT))) {
diff --git a/third_party/SPIRV-Tools/source/val/validate_builtins.cpp b/third_party/SPIRV-Tools/source/val/validate_builtins.cpp
index 3e81712..a7e9942 100644
--- a/third_party/SPIRV-Tools/source/val/validate_builtins.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_builtins.cpp
@@ -118,13 +118,15 @@
   VUIDErrorMax,
 } VUIDError;
 
-const static uint32_t NumVUIDBuiltins = 36;
+const static uint32_t NumVUIDBuiltins = 39;
 
 typedef struct {
   spv::BuiltIn builtIn;
   uint32_t vuid[VUIDErrorMax];  // execution mode, storage class, type VUIDs
 } BuiltinVUIDMapping;
 
+// Many built-ins have the same checks (Storage Class, Type, etc)
+// This table provides a nice LUT for the VUIDs
 std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
     // clang-format off
     {spv::BuiltIn::SubgroupEqMask,            {0,    4370, 4371}},
@@ -163,8 +165,11 @@
     {spv::BuiltIn::CullMaskKHR,               {6735, 6736, 6737}},
     {spv::BuiltIn::BaryCoordKHR,              {4154, 4155, 4156}},
     {spv::BuiltIn::BaryCoordNoPerspKHR,       {4160, 4161, 4162}},
-    // clang-format off
-} };
+    {spv::BuiltIn::PrimitivePointIndicesEXT,  {7041, 7043, 7044}},
+    {spv::BuiltIn::PrimitiveLineIndicesEXT,   {7047, 7049, 7050}},
+    {spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}},
+    // clang-format on
+}};
 
 uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) {
   uint32_t vuid = 0;
@@ -356,6 +361,9 @@
   spv_result_t ValidateRayTracingBuiltinsAtDefinition(
       const Decoration& decoration, const Instruction& inst);
 
+  spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition(
+      const Decoration& decoration, const Instruction& inst);
+
   // The following section contains functions which are called when id defined
   // by |referenced_inst| is
   // 1. referenced by |referenced_from_inst|
@@ -546,6 +554,11 @@
       const Instruction& referenced_inst,
       const Instruction& referenced_from_inst);
 
+  spv_result_t ValidateMeshShadingEXTBuiltinsAtReference(
+      const Decoration& decoration, const Instruction& built_in_inst,
+      const Instruction& referenced_inst,
+      const Instruction& referenced_from_inst);
+
   // Validates that |built_in_inst| is not (even indirectly) referenced from
   // within a function which can be called with |execution_model|.
   //
@@ -581,6 +594,10 @@
   spv_result_t ValidateI32Arr(
       const Decoration& decoration, const Instruction& inst,
       const std::function<spv_result_t(const std::string& message)>& diag);
+  spv_result_t ValidateArrayedI32Vec(
+      const Decoration& decoration, const Instruction& inst,
+      uint32_t num_components,
+      const std::function<spv_result_t(const std::string& message)>& diag);
   spv_result_t ValidateOptionalArrayedI32(
       const Decoration& decoration, const Instruction& inst,
       const std::function<spv_result_t(const std::string& message)>& diag);
@@ -909,6 +926,45 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t BuiltInsValidator::ValidateArrayedI32Vec(
+    const Decoration& decoration, const Instruction& inst,
+    uint32_t num_components,
+    const std::function<spv_result_t(const std::string& message)>& diag) {
+  uint32_t underlying_type = 0;
+  if (spv_result_t error =
+          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
+    return error;
+  }
+
+  const Instruction* const type_inst = _.FindDef(underlying_type);
+  if (type_inst->opcode() != spv::Op::OpTypeArray) {
+    return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
+  }
+
+  const uint32_t component_type = type_inst->word(2);
+  if (!_.IsIntVectorType(component_type)) {
+    return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
+  }
+
+  const uint32_t actual_num_components = _.GetDimension(component_type);
+  if (_.GetDimension(component_type) != num_components) {
+    std::ostringstream ss;
+    ss << GetDefinitionDesc(decoration, inst) << " has "
+       << actual_num_components << " components.";
+    return diag(ss.str());
+  }
+
+  const uint32_t bit_width = _.GetBitWidth(component_type);
+  if (bit_width != 32) {
+    std::ostringstream ss;
+    ss << GetDefinitionDesc(decoration, inst)
+       << " has components with bit width " << bit_width << ".";
+    return diag(ss.str());
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec(
     const Decoration& decoration, const Instruction& inst,
     uint32_t num_components,
@@ -1064,7 +1120,7 @@
 
   if (num_components != 0) {
     uint64_t actual_num_components = 0;
-    if (!_.GetConstantValUint64(type_inst->word(3), &actual_num_components)) {
+    if (!_.EvalConstantValUint64(type_inst->word(3), &actual_num_components)) {
       assert(0 && "Array type definition is corrupt");
     }
     if (actual_num_components != num_components) {
@@ -4108,6 +4164,119 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
+    const Decoration& decoration, const Instruction& inst) {
+  if (spvIsVulkanEnv(_.context()->target_env)) {
+    const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
+    uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+    if (builtin == spv::BuiltIn::PrimitivePointIndicesEXT) {
+      if (spv_result_t error = ValidateI32Arr(
+              decoration, inst,
+              [this, &inst, &decoration,
+               &vuid](const std::string& message) -> spv_result_t {
+                return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                       << _.VkErrorID(vuid) << "According to the "
+                       << spvLogStringForEnv(_.context()->target_env)
+                       << " spec BuiltIn "
+                       << _.grammar().lookupOperandName(
+                              SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
+                       << " variable needs to be a 32-bit int array."
+                       << message;
+              })) {
+        return error;
+      }
+    }
+    if (builtin == spv::BuiltIn::PrimitiveLineIndicesEXT) {
+      if (spv_result_t error = ValidateArrayedI32Vec(
+              decoration, inst, 2,
+              [this, &inst, &decoration,
+               &vuid](const std::string& message) -> spv_result_t {
+                return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                       << _.VkErrorID(vuid) << "According to the "
+                       << spvLogStringForEnv(_.context()->target_env)
+                       << " spec BuiltIn "
+                       << _.grammar().lookupOperandName(
+                              SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
+                       << " variable needs to be a 2-component 32-bit int "
+                          "array."
+                       << message;
+              })) {
+        return error;
+      }
+    }
+    if (builtin == spv::BuiltIn::PrimitiveTriangleIndicesEXT) {
+      if (spv_result_t error = ValidateArrayedI32Vec(
+              decoration, inst, 3,
+              [this, &inst, &decoration,
+               &vuid](const std::string& message) -> spv_result_t {
+                return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                       << _.VkErrorID(vuid) << "According to the "
+                       << spvLogStringForEnv(_.context()->target_env)
+                       << " spec BuiltIn "
+                       << _.grammar().lookupOperandName(
+                              SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
+                       << " variable needs to be a 3-component 32-bit int "
+                          "array."
+                       << message;
+              })) {
+        return error;
+      }
+    }
+  }
+  // Seed at reference checks with this built-in.
+  return ValidateMeshShadingEXTBuiltinsAtReference(decoration, inst, inst,
+                                                   inst);
+}
+
+spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference(
+    const Decoration& decoration, const Instruction& built_in_inst,
+    const Instruction& referenced_inst,
+    const Instruction& referenced_from_inst) {
+  if (spvIsVulkanEnv(_.context()->target_env)) {
+    const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
+    const spv::StorageClass storage_class =
+        GetStorageClass(referenced_from_inst);
+    if (storage_class != spv::StorageClass::Max &&
+        storage_class != spv::StorageClass::Output) {
+      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
+      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
+             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
+             << " spec allows BuiltIn "
+             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                              uint32_t(builtin))
+             << " to be only used for variables with Output storage class. "
+             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
+                                 referenced_from_inst)
+             << " " << GetStorageClassDesc(referenced_from_inst);
+    }
+
+    for (const spv::ExecutionModel execution_model : execution_models_) {
+      if (execution_model != spv::ExecutionModel::MeshEXT) {
+        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
+        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
+               << _.VkErrorID(vuid)
+               << spvLogStringForEnv(_.context()->target_env)
+               << " spec allows BuiltIn "
+               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                                uint32_t(builtin))
+               << " to be used only with MeshEXT execution model. "
+               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
+                                   referenced_from_inst, execution_model);
+      }
+    }
+  }
+
+  if (function_id_ == 0) {
+    // Propagate this rule to all dependant ids in the global scope.
+    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
+        std::bind(&BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference,
+                  this, decoration, built_in_inst, referenced_from_inst,
+                  std::placeholders::_1));
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
     const Decoration& decoration, const Instruction& inst) {
   const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]);
@@ -4283,6 +4452,11 @@
     case spv::BuiltIn::CullMaskKHR: {
       return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
     }
+    case spv::BuiltIn::PrimitivePointIndicesEXT:
+    case spv::BuiltIn::PrimitiveLineIndicesEXT:
+    case spv::BuiltIn::PrimitiveTriangleIndicesEXT: {
+      return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst);
+    }
     case spv::BuiltIn::PrimitiveShadingRateKHR: {
       return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
     }
diff --git a/third_party/SPIRV-Tools/source/val/validate_capability.cpp b/third_party/SPIRV-Tools/source/val/validate_capability.cpp
index 98dab42..81d2ad5 100644
--- a/third_party/SPIRV-Tools/source/val/validate_capability.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_capability.cpp
@@ -240,7 +240,7 @@
 
   ExtensionSet operand_exts(operand_desc->numExtensions,
                             operand_desc->extensions);
-  if (operand_exts.IsEmpty()) return false;
+  if (operand_exts.empty()) return false;
 
   return _.HasAnyOfExtensions(operand_exts);
 }
diff --git a/third_party/SPIRV-Tools/source/val/validate_cfg.cpp b/third_party/SPIRV-Tools/source/val/validate_cfg.cpp
index 7b3f748..9b7161f 100644
--- a/third_party/SPIRV-Tools/source/val/validate_cfg.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_cfg.cpp
@@ -190,6 +190,8 @@
               "ID of an OpLabel instruction";
   }
 
+  // A similar requirement for SPV_KHR_maximal_reconvergence is deferred until
+  // entry point call trees have been reconrded.
   if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 6) && true_id == false_id) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
            << "In SPIR-V 1.6 or later, True Label and False Label must be "
@@ -875,6 +877,95 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t MaximalReconvergenceChecks(ValidationState_t& _) {
+  // Find all the entry points with the MaximallyReconvergencesKHR execution
+  // mode.
+  std::unordered_set<uint32_t> maximal_funcs;
+  std::unordered_set<uint32_t> maximal_entry_points;
+  for (auto entry_point : _.entry_points()) {
+    const auto* exec_modes = _.GetExecutionModes(entry_point);
+    if (exec_modes &&
+        exec_modes->count(spv::ExecutionMode::MaximallyReconvergesKHR)) {
+      maximal_entry_points.insert(entry_point);
+      maximal_funcs.insert(entry_point);
+    }
+  }
+
+  if (maximal_entry_points.empty()) {
+    return SPV_SUCCESS;
+  }
+
+  // Find all the functions reachable from a maximal reconvergence entry point.
+  for (const auto& func : _.functions()) {
+    const auto& entry_points = _.EntryPointReferences(func.id());
+    for (auto id : entry_points) {
+      if (maximal_entry_points.count(id)) {
+        maximal_funcs.insert(func.id());
+        break;
+      }
+    }
+  }
+
+  // Check for conditional branches with the same true and false targets.
+  for (const auto& inst : _.ordered_instructions()) {
+    if (inst.opcode() == spv::Op::OpBranchConditional) {
+      const auto true_id = inst.GetOperandAs<uint32_t>(1);
+      const auto false_id = inst.GetOperandAs<uint32_t>(2);
+      if (true_id == false_id && maximal_funcs.count(inst.function()->id())) {
+        return _.diag(SPV_ERROR_INVALID_ID, &inst)
+               << "In entry points using the MaximallyReconvergesKHR execution "
+                  "mode, True Label and False Label must be different labels";
+      }
+    }
+  }
+
+  // Check for invalid multiple predecessors. Only loop headers, continue
+  // targets, merge targets or switch targets or defaults may have multiple
+  // unique predecessors.
+  for (const auto& func : _.functions()) {
+    if (!maximal_funcs.count(func.id())) continue;
+
+    for (const auto* block : func.ordered_blocks()) {
+      std::unordered_set<uint32_t> unique_preds;
+      const auto* preds = block->predecessors();
+      if (!preds) continue;
+
+      for (const auto* pred : *preds) {
+        unique_preds.insert(pred->id());
+      }
+      if (unique_preds.size() < 2) continue;
+
+      const auto* terminator = block->terminator();
+      const auto index = terminator - &_.ordered_instructions()[0];
+      const auto* pre_terminator = &_.ordered_instructions()[index - 1];
+      if (pre_terminator->opcode() == spv::Op::OpLoopMerge) continue;
+
+      const auto* label = _.FindDef(block->id());
+      bool ok = false;
+      for (const auto& pair : label->uses()) {
+        const auto* use_inst = pair.first;
+        switch (use_inst->opcode()) {
+          case spv::Op::OpSelectionMerge:
+          case spv::Op::OpLoopMerge:
+          case spv::Op::OpSwitch:
+            ok = true;
+            break;
+          default:
+            break;
+        }
+      }
+      if (!ok) {
+        return _.diag(SPV_ERROR_INVALID_CFG, label)
+               << "In entry points using the MaximallyReconvergesKHR "
+                  "execution mode, this basic block must not have multiple "
+                  "unique predecessors";
+      }
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t PerformCfgChecks(ValidationState_t& _) {
   for (auto& function : _.functions()) {
     // Check all referenced blocks are defined within a function
@@ -999,6 +1090,11 @@
         return error;
     }
   }
+
+  if (auto error = MaximalReconvergenceChecks(_)) {
+    return error;
+  }
+
   return SPV_SUCCESS;
 }
 
diff --git a/third_party/SPIRV-Tools/source/val/validate_composites.cpp b/third_party/SPIRV-Tools/source/val/validate_composites.cpp
index 2b83c63..26486da 100644
--- a/third_party/SPIRV-Tools/source/val/validate_composites.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_composites.cpp
@@ -94,7 +94,7 @@
           break;
         }
 
-        if (!_.GetConstantValUint64(type_inst->word(3), &array_size)) {
+        if (!_.EvalConstantValUint64(type_inst->word(3), &array_size)) {
           assert(0 && "Array type definition is corrupt");
         }
         if (component_index >= array_size) {
@@ -122,6 +122,7 @@
         *member_type = type_inst->word(component_index + 2);
         break;
       }
+      case spv::Op::OpTypeCooperativeMatrixKHR:
       case spv::Op::OpTypeCooperativeMatrixNV: {
         *member_type = type_inst->word(2);
         break;
@@ -288,7 +289,7 @@
       }
 
       uint64_t array_size = 0;
-      if (!_.GetConstantValUint64(array_inst->word(3), &array_size)) {
+      if (!_.EvalConstantValUint64(array_inst->word(3), &array_size)) {
         assert(0 && "Array type definition is corrupt");
       }
 
@@ -335,6 +336,25 @@
 
       break;
     }
+    case spv::Op::OpTypeCooperativeMatrixKHR: {
+      const auto result_type_inst = _.FindDef(result_type);
+      assert(result_type_inst);
+      const auto component_type_id =
+          result_type_inst->GetOperandAs<uint32_t>(1);
+
+      if (3 != num_operands) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Must be only one constituent";
+      }
+
+      const uint32_t operand_type_id = _.GetOperandTypeId(inst, 2);
+
+      if (operand_type_id != component_type_id) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Expected Constituent type to be equal to the component type";
+      }
+      break;
+    }
     case spv::Op::OpTypeCooperativeMatrixNV: {
       const auto result_type_inst = _.FindDef(result_type);
       assert(result_type_inst);
diff --git a/third_party/SPIRV-Tools/source/val/validate_constants.cpp b/third_party/SPIRV-Tools/source/val/validate_constants.cpp
index 006e504..4deaa49 100644
--- a/third_party/SPIRV-Tools/source/val/validate_constants.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_constants.cpp
@@ -243,6 +243,7 @@
         }
       }
     } break;
+    case spv::Op::OpTypeCooperativeMatrixKHR:
     case spv::Op::OpTypeCooperativeMatrixNV: {
       if (1 != constituent_count) {
         return _.diag(SPV_ERROR_INVALID_ID, inst)
@@ -310,6 +311,7 @@
     case spv::Op::OpTypeArray:
     case spv::Op::OpTypeMatrix:
     case spv::Op::OpTypeCooperativeMatrixNV:
+    case spv::Op::OpTypeCooperativeMatrixKHR:
     case spv::Op::OpTypeVector: {
       auto base_type = _.FindDef(instruction[2]);
       return base_type && IsTypeNullable(base_type->words(), _);
diff --git a/third_party/SPIRV-Tools/source/val/validate_conversion.cpp b/third_party/SPIRV-Tools/source/val/validate_conversion.cpp
index 476c1fe..b2892a8 100644
--- a/third_party/SPIRV-Tools/source/val/validate_conversion.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_conversion.cpp
@@ -473,7 +473,10 @@
       const bool input_is_pointer = _.IsPointerType(input_type);
       const bool input_is_int_scalar = _.IsIntScalarType(input_type);
 
-      if (!result_is_pointer && !result_is_int_scalar &&
+      const bool result_is_coopmat = _.IsCooperativeMatrixType(result_type);
+      const bool input_is_coopmat = _.IsCooperativeMatrixType(input_type);
+
+      if (!result_is_pointer && !result_is_int_scalar && !result_is_coopmat &&
           !_.IsIntVectorType(result_type) &&
           !_.IsFloatScalarType(result_type) &&
           !_.IsFloatVectorType(result_type))
@@ -481,13 +484,24 @@
                << "Expected Result Type to be a pointer or int or float vector "
                << "or scalar type: " << spvOpcodeString(opcode);
 
-      if (!input_is_pointer && !input_is_int_scalar &&
+      if (!input_is_pointer && !input_is_int_scalar && !input_is_coopmat &&
           !_.IsIntVectorType(input_type) && !_.IsFloatScalarType(input_type) &&
           !_.IsFloatVectorType(input_type))
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << "Expected input to be a pointer or int or float vector "
                << "or scalar: " << spvOpcodeString(opcode);
 
+      if (result_is_coopmat != input_is_coopmat)
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Cooperative matrix can only be cast to another cooperative "
+               << "matrix: " << spvOpcodeString(opcode);
+
+      if (result_is_coopmat) {
+        spv_result_t ret =
+            _.CooperativeMatrixShapesMatch(inst, result_type, input_type);
+        if (ret != SPV_SUCCESS) return ret;
+      }
+
       if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) ||
           _.HasExtension(kSPV_KHR_physical_storage_buffer)) {
         const bool result_is_int_vector = _.IsIntVectorType(result_type);
diff --git a/third_party/SPIRV-Tools/source/val/validate_decorations.cpp b/third_party/SPIRV-Tools/source/val/validate_decorations.cpp
index c1fca45..0a7df65 100644
--- a/third_party/SPIRV-Tools/source/val/validate_decorations.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_decorations.cpp
@@ -452,7 +452,16 @@
     return ds;
   };
 
-  const auto& members = getStructMembers(struct_id, vstate);
+  // If we are checking physical storage buffer pointers, we may not actually
+  // have a struct here. Instead, pretend we have a struct with a single member
+  // at offset 0.
+  const auto& struct_type = vstate.FindDef(struct_id);
+  std::vector<uint32_t> members;
+  if (struct_type->opcode() == spv::Op::OpTypeStruct) {
+    members = getStructMembers(struct_id, vstate);
+  } else {
+    members.push_back(struct_id);
+  }
 
   // To check for member overlaps, we want to traverse the members in
   // offset order.
@@ -461,31 +470,38 @@
     uint32_t offset;
   };
   std::vector<MemberOffsetPair> member_offsets;
-  member_offsets.reserve(members.size());
-  for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
-       memberIdx < numMembers; memberIdx++) {
-    uint32_t offset = 0xffffffff;
-    auto member_decorations =
-        vstate.id_member_decorations(struct_id, memberIdx);
-    for (auto decoration = member_decorations.begin;
-         decoration != member_decorations.end; ++decoration) {
-      assert(decoration->struct_member_index() == (int)memberIdx);
-      switch (decoration->dec_type()) {
-        case spv::Decoration::Offset:
-          offset = decoration->params()[0];
-          break;
-        default:
-          break;
+
+  // With physical storage buffers, we might be checking layouts that do not
+  // originate from a structure.
+  if (struct_type->opcode() == spv::Op::OpTypeStruct) {
+    member_offsets.reserve(members.size());
+    for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
+         memberIdx < numMembers; memberIdx++) {
+      uint32_t offset = 0xffffffff;
+      auto member_decorations =
+          vstate.id_member_decorations(struct_id, memberIdx);
+      for (auto decoration = member_decorations.begin;
+           decoration != member_decorations.end; ++decoration) {
+        assert(decoration->struct_member_index() == (int)memberIdx);
+        switch (decoration->dec_type()) {
+          case spv::Decoration::Offset:
+            offset = decoration->params()[0];
+            break;
+          default:
+            break;
+        }
       }
+      member_offsets.push_back(
+          MemberOffsetPair{memberIdx, incoming_offset + offset});
     }
-    member_offsets.push_back(
-        MemberOffsetPair{memberIdx, incoming_offset + offset});
+    std::stable_sort(
+        member_offsets.begin(), member_offsets.end(),
+        [](const MemberOffsetPair& lhs, const MemberOffsetPair& rhs) {
+          return lhs.offset < rhs.offset;
+        });
+  } else {
+    member_offsets.push_back({0, 0});
   }
-  std::stable_sort(
-      member_offsets.begin(), member_offsets.end(),
-      [](const MemberOffsetPair& lhs, const MemberOffsetPair& rhs) {
-        return lhs.offset < rhs.offset;
-      });
 
   // Now scan from lowest offset to highest offset.
   uint32_t nextValidOffset = 0;
@@ -906,9 +922,9 @@
         }
       }
 
-      if (vstate.HasCapability(
-              spv::Capability::WorkgroupMemoryExplicitLayoutKHR) &&
-          num_workgroup_variables > 0 &&
+      const bool workgroup_blocks_allowed = vstate.HasCapability(
+          spv::Capability::WorkgroupMemoryExplicitLayoutKHR);
+      if (workgroup_blocks_allowed && num_workgroup_variables > 0 &&
           num_workgroup_variables_with_block > 0) {
         if (num_workgroup_variables != num_workgroup_variables_with_block) {
           return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point))
@@ -929,6 +945,13 @@
                     "Entry point id "
                  << entry_point << " does not meet this requirement.";
         }
+      } else if (!workgroup_blocks_allowed &&
+                 num_workgroup_variables_with_block > 0) {
+        return vstate.diag(SPV_ERROR_INVALID_BINARY,
+                           vstate.FindDef(entry_point))
+               << "Workgroup Storage Class variables can't be decorated with "
+                  "Block unless declaring the WorkgroupMemoryExplicitLayoutKHR "
+                  "capability.";
       }
     }
   }
@@ -1023,6 +1046,8 @@
   std::unordered_set<uint32_t> uses_push_constant;
   for (const auto& inst : vstate.ordered_instructions()) {
     const auto& words = inst.words();
+    auto type_id = inst.type_id();
+    const Instruction* type_inst = vstate.FindDef(type_id);
     if (spv::Op::OpVariable == inst.opcode()) {
       const auto var_id = inst.id();
       // For storage class / decoration combinations, see Vulkan 14.5.4 "Offset
@@ -1276,6 +1301,23 @@
           }
         }
       }
+    } else if (type_inst && type_inst->opcode() == spv::Op::OpTypePointer &&
+               type_inst->GetOperandAs<spv::StorageClass>(1u) ==
+                   spv::StorageClass::PhysicalStorageBuffer) {
+      const bool scalar_block_layout = vstate.options()->scalar_block_layout;
+      MemberConstraints constraints;
+      const bool buffer = true;
+      const auto data_type_id = type_inst->GetOperandAs<uint32_t>(2u);
+      const auto* data_type_inst = vstate.FindDef(data_type_id);
+      if (data_type_inst->opcode() == spv::Op::OpTypeStruct) {
+        ComputeMemberConstraintsForStruct(&constraints, data_type_id,
+                                          LayoutConstraints(), vstate);
+      }
+      if (auto res = checkLayout(data_type_id, "PhysicalStorageBuffer", "Block",
+                                 !buffer, scalar_block_layout, 0, constraints,
+                                 vstate)) {
+        return res;
+      }
     }
   }
   return SPV_SUCCESS;
@@ -1283,21 +1325,14 @@
 
 // Returns true if |decoration| cannot be applied to the same id more than once.
 bool AtMostOncePerId(spv::Decoration decoration) {
-  return decoration == spv::Decoration::ArrayStride;
+  return decoration != spv::Decoration::UserSemantic &&
+         decoration != spv::Decoration::FuncParamAttr;
 }
 
 // Returns true if |decoration| cannot be applied to the same member more than
 // once.
 bool AtMostOncePerMember(spv::Decoration decoration) {
-  switch (decoration) {
-    case spv::Decoration::Offset:
-    case spv::Decoration::MatrixStride:
-    case spv::Decoration::RowMajor:
-    case spv::Decoration::ColMajor:
-      return true;
-    default:
-      return false;
-  }
+  return decoration != spv::Decoration::UserSemantic;
 }
 
 spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) {
@@ -1514,7 +1549,8 @@
     const auto opcode = inst.opcode();
     const auto type_id = inst.type_id();
     if (opcode != spv::Op::OpVariable &&
-        opcode != spv::Op::OpFunctionParameter) {
+        opcode != spv::Op::OpFunctionParameter &&
+        opcode != spv::Op::OpRawAccessChainNV) {
       return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
              << "Target of NonWritable decoration must be a memory object "
                 "declaration (a variable or a function parameter)";
@@ -1527,10 +1563,11 @@
         vstate.features().nonwritable_var_in_function_or_private) {
       // New permitted feature in SPIR-V 1.4.
     } else if (
-        // It may point to a UBO, SSBO, or storage image.
+        // It may point to a UBO, SSBO, storage image, or raw access chain.
         vstate.IsPointerToUniformBlock(type_id) ||
         vstate.IsPointerToStorageBuffer(type_id) ||
-        vstate.IsPointerToStorageImage(type_id)) {
+        vstate.IsPointerToStorageImage(type_id) ||
+        opcode == spv::Op::OpRawAccessChainNV) {
     } else {
       return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
              << "Target of NonWritable decoration is invalid: must point to a "
diff --git a/third_party/SPIRV-Tools/source/val/validate_extensions.cpp b/third_party/SPIRV-Tools/source/val/validate_extensions.cpp
index 0ac62bf..7b73c9c 100644
--- a/third_party/SPIRV-Tools/source/val/validate_extensions.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_extensions.cpp
@@ -482,8 +482,8 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t ValidateClspvReflectionArgumentOffsetBuffer(ValidationState_t& _,
-                                                         const Instruction* inst) {
+spv_result_t ValidateClspvReflectionArgumentOffsetBuffer(
+    ValidationState_t& _, const Instruction* inst) {
   const auto num_operands = inst->operands().size();
   if (auto error = ValidateKernelDecl(_, inst)) {
     return error;
@@ -802,7 +802,7 @@
 }
 
 spv_result_t ValidateClspvReflectionPrintfInfo(ValidationState_t& _,
-                                              const Instruction* inst) {
+                                               const Instruction* inst) {
   if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(4))) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
            << "PrintfID must be a 32-bit unsigned integer OpConstant";
@@ -823,8 +823,8 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t ValidateClspvReflectionPrintfStorageBuffer(ValidationState_t& _,
-                                                        const Instruction* inst) {
+spv_result_t ValidateClspvReflectionPrintfStorageBuffer(
+    ValidationState_t& _, const Instruction* inst) {
   if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(4))) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
            << "DescriptorSet must be a 32-bit unsigned integer OpConstant";
@@ -843,8 +843,8 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t ValidateClspvReflectionPrintfPushConstant(ValidationState_t& _,
-                                                       const Instruction* inst) {
+spv_result_t ValidateClspvReflectionPrintfPushConstant(
+    ValidationState_t& _, const Instruction* inst) {
   if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(4))) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
            << "Offset must be a 32-bit unsigned integer OpConstant";
@@ -3100,7 +3100,7 @@
 
           uint32_t vector_count = inst->word(6);
           uint64_t const_val;
-          if (!_.GetConstantValUint64(vector_count, &const_val)) {
+          if (!_.EvalConstantValUint64(vector_count, &const_val)) {
             return _.diag(SPV_ERROR_INVALID_DATA, inst)
                    << ext_inst_name()
                    << ": Vector Count must be 32-bit integer OpConstant";
@@ -3168,16 +3168,16 @@
           break;
         }
         case CommonDebugInfoDebugTypePointer: {
-          auto validate_base_type =
-              ValidateOperandBaseType(_, inst, 5, ext_inst_name);
+          auto validate_base_type = ValidateOperandDebugType(
+              _, "Base Type", inst, 5, ext_inst_name, false);
           if (validate_base_type != SPV_SUCCESS) return validate_base_type;
           CHECK_CONST_UINT_OPERAND("Storage Class", 6);
           CHECK_CONST_UINT_OPERAND("Flags", 7);
           break;
         }
         case CommonDebugInfoDebugTypeQualifier: {
-          auto validate_base_type =
-              ValidateOperandBaseType(_, inst, 5, ext_inst_name);
+          auto validate_base_type = ValidateOperandDebugType(
+              _, "Base Type", inst, 5, ext_inst_name, false);
           if (validate_base_type != SPV_SUCCESS) return validate_base_type;
           CHECK_CONST_UINT_OPERAND("Type Qualifier", 6);
           break;
@@ -3191,7 +3191,7 @@
           uint32_t component_count = inst->word(6);
           if (vulkanDebugInfo) {
             uint64_t const_val;
-            if (!_.GetConstantValUint64(component_count, &const_val)) {
+            if (!_.EvalConstantValUint64(component_count, &const_val)) {
               return _.diag(SPV_ERROR_INVALID_DATA, inst)
                      << ext_inst_name()
                      << ": Component Count must be 32-bit integer OpConstant";
diff --git a/third_party/SPIRV-Tools/source/val/validate_id.cpp b/third_party/SPIRV-Tools/source/val/validate_id.cpp
index 92a4e8e..bcfeb59 100644
--- a/third_party/SPIRV-Tools/source/val/validate_id.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_id.cpp
@@ -163,9 +163,12 @@
               !inst->IsDebugInfo() && !inst->IsNonSemantic() &&
               !spvOpcodeIsDecoration(opcode) && opcode != spv::Op::OpFunction &&
               opcode != spv::Op::OpCooperativeMatrixLengthNV &&
+              opcode != spv::Op::OpCooperativeMatrixLengthKHR &&
               !(opcode == spv::Op::OpSpecConstantOp &&
-                spv::Op(inst->word(3)) ==
-                    spv::Op::OpCooperativeMatrixLengthNV)) {
+                (spv::Op(inst->word(3)) ==
+                     spv::Op::OpCooperativeMatrixLengthNV ||
+                 spv::Op(inst->word(3)) ==
+                     spv::Op::OpCooperativeMatrixLengthKHR))) {
             return _.diag(SPV_ERROR_INVALID_ID, inst)
                    << "Operand " << _.getIdName(operand_word)
                    << " cannot be a type";
@@ -179,9 +182,12 @@
                      opcode != spv::Op::OpLoopMerge &&
                      opcode != spv::Op::OpFunction &&
                      opcode != spv::Op::OpCooperativeMatrixLengthNV &&
+                     opcode != spv::Op::OpCooperativeMatrixLengthKHR &&
                      !(opcode == spv::Op::OpSpecConstantOp &&
-                       spv::Op(inst->word(3)) ==
-                           spv::Op::OpCooperativeMatrixLengthNV)) {
+                       (spv::Op(inst->word(3)) ==
+                            spv::Op::OpCooperativeMatrixLengthNV ||
+                        spv::Op(inst->word(3)) ==
+                            spv::Op::OpCooperativeMatrixLengthKHR))) {
             return _.diag(SPV_ERROR_INVALID_ID, inst)
                    << "Operand " << _.getIdName(operand_word)
                    << " requires a type";
diff --git a/third_party/SPIRV-Tools/source/val/validate_image.cpp b/third_party/SPIRV-Tools/source/val/validate_image.cpp
index 733556b..a1a76ea 100644
--- a/third_party/SPIRV-Tools/source/val/validate_image.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_image.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 Google Inc.
+// Copyright (c) 2017 Google Inc.
 // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
 // reserved.
 //
@@ -297,7 +297,6 @@
                           spv::ImageOperandsMask::ConstOffsets |
                           spv::ImageOperandsMask::Offsets)) > 1) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
-           << _.VkErrorID(4662)
            << "Image Operands Offset, ConstOffset, ConstOffsets, Offsets "
               "cannot be used together";
   }
@@ -496,7 +495,7 @@
     }
 
     uint64_t array_size = 0;
-    if (!_.GetConstantValUint64(type_inst->word(3), &array_size)) {
+    if (!_.EvalConstantValUint64(type_inst->word(3), &array_size)) {
       assert(0 && "Array type definition is corrupt");
     }
 
@@ -694,16 +693,11 @@
              << "storage image";
     }
 
-    if (info.multisampled == 1 &&
+    if (info.multisampled == 1 && info.arrayed == 1 && info.sampled == 2 &&
         !_.HasCapability(spv::Capability::ImageMSArray)) {
-#if 0
-      // TODO(atgoo@github.com) The description of this rule in the spec
-      // is unclear and Glslang doesn't declare ImageMSArray. Need to clarify
-      // and reenable.
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
-          << "Capability ImageMSArray is required to access storage "
-          << "image";
-#endif
+             << "Capability ImageMSArray is required to access storage "
+             << "image";
     }
   } else if (info.sampled != 0) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -920,7 +914,15 @@
 
     if (info.dim == spv::Dim::SubpassData && info.arrayed != 0) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
-             << _.VkErrorID(6214) << "Dim SubpassData requires Arrayed to be 0";
+             << _.VkErrorID(6214)
+             << "Dim SubpassData requires Arrayed to be 0 in the Vulkan "
+                "environment";
+    }
+
+    if (info.dim == spv::Dim::Rect) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << _.VkErrorID(9638)
+             << "Dim must not be Rect in the Vulkan environment";
     }
   }
 
@@ -984,6 +986,14 @@
     case spv::Op::OpImageSparseGather:
     case spv::Op::OpImageSparseDrefGather:
     case spv::Op::OpCopyObject:
+    case spv::Op::OpImageSampleWeightedQCOM:
+    case spv::Op::OpImageBoxFilterQCOM:
+    case spv::Op::OpImageBlockMatchSSDQCOM:
+    case spv::Op::OpImageBlockMatchSADQCOM:
+    case spv::Op::OpImageBlockMatchWindowSADQCOM:
+    case spv::Op::OpImageBlockMatchWindowSSDQCOM:
+    case spv::Op::OpImageBlockMatchGatherSADQCOM:
+    case spv::Op::OpImageBlockMatchGatherSSDQCOM:
       return true;
     case spv::Op::OpStore:
       if (_.HasCapability(spv::Capability::BindlessTextureNV)) return true;
@@ -1087,6 +1097,18 @@
       }
     }
   }
+
+  const Instruction* ld_inst;
+  {
+    int t_idx = inst->GetOperandAs<int>(2);
+    ld_inst = _.FindDef(t_idx);
+  }
+
+  if (ld_inst->opcode() == spv::Op::OpLoad) {
+    int texture_id = ld_inst->GetOperandAs<int>(2);  // variable to load
+    _.RegisterQCOMImageProcessingTextureConsumer(texture_id, ld_inst, inst);
+  }
+
   return SPV_SUCCESS;
 }
 
@@ -1108,7 +1130,10 @@
   const auto ptr_type = result_type->GetOperandAs<uint32_t>(2);
   const auto ptr_opcode = _.GetIdOpcode(ptr_type);
   if (ptr_opcode != spv::Op::OpTypeInt && ptr_opcode != spv::Op::OpTypeFloat &&
-      ptr_opcode != spv::Op::OpTypeVoid) {
+      ptr_opcode != spv::Op::OpTypeVoid &&
+      !(ptr_opcode == spv::Op::OpTypeVector &&
+        _.HasCapability(spv::Capability::AtomicFloat16VectorNV) &&
+        _.IsFloat16Vector2Or4Type(ptr_type))) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
            << "Expected Result Type to be OpTypePointer whose Type operand "
               "must be a scalar numerical type or OpTypeVoid";
@@ -1132,7 +1157,14 @@
            << "Corrupt image type definition";
   }
 
-  if (info.sampled_type != ptr_type) {
+  if (info.sampled_type != ptr_type &&
+      !(_.HasCapability(spv::Capability::AtomicFloat16VectorNV) &&
+        _.IsFloat16Vector2Or4Type(ptr_type) &&
+        _.GetIdOpcode(info.sampled_type) == spv::Op::OpTypeFloat &&
+        ((_.GetDimension(ptr_type) == 2 &&
+          info.format == spv::ImageFormat::Rg16f) ||
+         (_.GetDimension(ptr_type) == 4 &&
+          info.format == spv::ImageFormat::Rgba16f)))) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
            << "Expected Image 'Sampled Type' to be the same as the Type "
               "pointed to by Result Type";
@@ -1190,7 +1222,7 @@
 
   if (info.multisampled == 0) {
     uint64_t ms = 0;
-    if (!_.GetConstantValUint64(inst->GetOperandAs<uint32_t>(4), &ms) ||
+    if (!_.EvalConstantValUint64(inst->GetOperandAs<uint32_t>(4), &ms) ||
         ms != 0) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
              << "Expected Sample for Image with MS 0 to be a valid <id> for "
@@ -1203,7 +1235,10 @@
         (info.format != spv::ImageFormat::R64ui) &&
         (info.format != spv::ImageFormat::R32f) &&
         (info.format != spv::ImageFormat::R32i) &&
-        (info.format != spv::ImageFormat::R32ui)) {
+        (info.format != spv::ImageFormat::R32ui) &&
+        !((info.format == spv::ImageFormat::Rg16f ||
+           info.format == spv::ImageFormat::Rgba16f) &&
+          _.HasCapability(spv::Capability::AtomicFloat16VectorNV))) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
              << _.VkErrorID(4658)
              << "Expected the Image Format in Image to be R64i, R64ui, R32f, "
@@ -2130,6 +2165,127 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t ValidateImageProcessingQCOMDecoration(ValidationState_t& _, int id,
+                                                   spv::Decoration decor) {
+  const Instruction* si_inst = nullptr;
+  const Instruction* ld_inst = _.FindDef(id);
+  bool is_intf_obj = (ld_inst->opcode() == spv::Op::OpSampledImage);
+  if (is_intf_obj == true) {
+    si_inst = ld_inst;
+    int t_idx = si_inst->GetOperandAs<int>(2);  // texture
+    ld_inst = _.FindDef(t_idx);
+  }
+  if (ld_inst->opcode() != spv::Op::OpLoad) {
+    return _.diag(SPV_ERROR_INVALID_DATA, ld_inst) << "Expect to see OpLoad";
+  }
+  int texture_id = ld_inst->GetOperandAs<int>(2);  // variable to load
+  if (!_.HasDecoration(texture_id, decor)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, ld_inst)
+           << "Missing decoration " << _.SpvDecorationString(decor);
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateImageProcessing2QCOMWindowDecoration(ValidationState_t& _,
+                                                          int id) {
+  const Instruction* ld_inst = _.FindDef(id);
+  bool is_intf_obj = (ld_inst->opcode() != spv::Op::OpSampledImage);
+  if (is_intf_obj == true) {
+    if (ld_inst->opcode() != spv::Op::OpLoad) {
+      return _.diag(SPV_ERROR_INVALID_DATA, ld_inst) << "Expect to see OpLoad";
+    }
+    int texture_id = ld_inst->GetOperandAs<int>(2);  // variable to load
+    spv::Decoration decor = spv::Decoration::BlockMatchTextureQCOM;
+    if (!_.HasDecoration(texture_id, decor)) {
+      return _.diag(SPV_ERROR_INVALID_DATA, ld_inst)
+             << "Missing decoration " << _.SpvDecorationString(decor);
+    }
+    decor = spv::Decoration::BlockMatchSamplerQCOM;
+    if (!_.HasDecoration(texture_id, decor)) {
+      return _.diag(SPV_ERROR_INVALID_DATA, ld_inst)
+             << "Missing decoration " << _.SpvDecorationString(decor);
+    }
+  } else {
+    const Instruction* si_inst = ld_inst;
+    int t_idx = si_inst->GetOperandAs<int>(2);  // texture
+    const Instruction* t_ld_inst = _.FindDef(t_idx);
+    if (t_ld_inst->opcode() != spv::Op::OpLoad) {
+      return _.diag(SPV_ERROR_INVALID_DATA, t_ld_inst)
+             << "Expect to see OpLoad";
+    }
+    int texture_id = t_ld_inst->GetOperandAs<int>(2);  // variable to load
+    spv::Decoration decor = spv::Decoration::BlockMatchTextureQCOM;
+    if (!_.HasDecoration(texture_id, decor)) {
+      return _.diag(SPV_ERROR_INVALID_DATA, ld_inst)
+             << "Missing decoration " << _.SpvDecorationString(decor);
+    }
+    int s_idx = si_inst->GetOperandAs<int>(3);  // sampler
+    const Instruction* s_ld_inst = _.FindDef(s_idx);
+    if (s_ld_inst->opcode() != spv::Op::OpLoad) {
+      return _.diag(SPV_ERROR_INVALID_DATA, s_ld_inst)
+             << "Expect to see OpLoad";
+    }
+    int sampler_id = s_ld_inst->GetOperandAs<int>(2);  // variable to load
+    decor = spv::Decoration::BlockMatchSamplerQCOM;
+    if (!_.HasDecoration(sampler_id, decor)) {
+      return _.diag(SPV_ERROR_INVALID_DATA, ld_inst)
+             << "Missing decoration " << _.SpvDecorationString(decor);
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateImageProcessingQCOM(ValidationState_t& _,
+                                         const Instruction* inst) {
+  spv_result_t res = SPV_SUCCESS;
+  const spv::Op opcode = inst->opcode();
+  switch (opcode) {
+    case spv::Op::OpImageSampleWeightedQCOM: {
+      int wi_idx = inst->GetOperandAs<int>(4);  // weight
+      res = ValidateImageProcessingQCOMDecoration(
+          _, wi_idx, spv::Decoration::WeightTextureQCOM);
+      break;
+    }
+    case spv::Op::OpImageBlockMatchSSDQCOM:
+    case spv::Op::OpImageBlockMatchSADQCOM: {
+      int tgt_idx = inst->GetOperandAs<int>(2);  // target
+      res = ValidateImageProcessingQCOMDecoration(
+          _, tgt_idx, spv::Decoration::BlockMatchTextureQCOM);
+      if (res != SPV_SUCCESS) break;
+      int ref_idx = inst->GetOperandAs<int>(4);  // reference
+      res = ValidateImageProcessingQCOMDecoration(
+          _, ref_idx, spv::Decoration::BlockMatchTextureQCOM);
+      break;
+    }
+    case spv::Op::OpImageBlockMatchWindowSSDQCOM:
+    case spv::Op::OpImageBlockMatchWindowSADQCOM: {
+      int tgt_idx = inst->GetOperandAs<int>(2);  // target
+      res = ValidateImageProcessing2QCOMWindowDecoration(_, tgt_idx);
+      if (res != SPV_SUCCESS) break;
+      int ref_idx = inst->GetOperandAs<int>(4);  // reference
+      res = ValidateImageProcessing2QCOMWindowDecoration(_, ref_idx);
+      break;
+    }
+    case spv::Op::OpImageBlockMatchGatherSSDQCOM:
+    case spv::Op::OpImageBlockMatchGatherSADQCOM: {
+      int tgt_idx = inst->GetOperandAs<int>(2);  // target
+      res = ValidateImageProcessingQCOMDecoration(
+          _, tgt_idx, spv::Decoration::BlockMatchTextureQCOM);
+      if (res != SPV_SUCCESS) break;
+      int ref_idx = inst->GetOperandAs<int>(4);  // reference
+      res = ValidateImageProcessingQCOMDecoration(
+          _, ref_idx, spv::Decoration::BlockMatchTextureQCOM);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return res;
+}
+
 }  // namespace
 
 // Validates correctness of image instructions.
@@ -2249,6 +2405,16 @@
     case spv::Op::OpImageSparseTexelsResident:
       return ValidateImageSparseTexelsResident(_, inst);
 
+    case spv::Op::OpImageSampleWeightedQCOM:
+    case spv::Op::OpImageBoxFilterQCOM:
+    case spv::Op::OpImageBlockMatchSSDQCOM:
+    case spv::Op::OpImageBlockMatchSADQCOM:
+    case spv::Op::OpImageBlockMatchWindowSADQCOM:
+    case spv::Op::OpImageBlockMatchWindowSSDQCOM:
+    case spv::Op::OpImageBlockMatchGatherSADQCOM:
+    case spv::Op::OpImageBlockMatchGatherSSDQCOM:
+      return ValidateImageProcessingQCOM(_, inst);
+
     default:
       break;
   }
@@ -2256,5 +2422,98 @@
   return SPV_SUCCESS;
 }
 
+bool IsImageInstruction(const spv::Op opcode) {
+  switch (opcode) {
+    case spv::Op::OpImageSampleImplicitLod:
+    case spv::Op::OpImageSampleDrefImplicitLod:
+    case spv::Op::OpImageSampleProjImplicitLod:
+    case spv::Op::OpImageSampleProjDrefImplicitLod:
+    case spv::Op::OpImageSparseSampleImplicitLod:
+    case spv::Op::OpImageSparseSampleDrefImplicitLod:
+    case spv::Op::OpImageSparseSampleProjImplicitLod:
+    case spv::Op::OpImageSparseSampleProjDrefImplicitLod:
+
+    case spv::Op::OpImageSampleExplicitLod:
+    case spv::Op::OpImageSampleDrefExplicitLod:
+    case spv::Op::OpImageSampleProjExplicitLod:
+    case spv::Op::OpImageSampleProjDrefExplicitLod:
+    case spv::Op::OpImageSparseSampleExplicitLod:
+    case spv::Op::OpImageSparseSampleDrefExplicitLod:
+    case spv::Op::OpImageSparseSampleProjExplicitLod:
+    case spv::Op::OpImageSparseSampleProjDrefExplicitLod:
+
+    case spv::Op::OpImage:
+    case spv::Op::OpImageFetch:
+    case spv::Op::OpImageSparseFetch:
+    case spv::Op::OpImageGather:
+    case spv::Op::OpImageDrefGather:
+    case spv::Op::OpImageSparseGather:
+    case spv::Op::OpImageSparseDrefGather:
+    case spv::Op::OpImageRead:
+    case spv::Op::OpImageSparseRead:
+    case spv::Op::OpImageWrite:
+
+    case spv::Op::OpImageQueryFormat:
+    case spv::Op::OpImageQueryOrder:
+    case spv::Op::OpImageQuerySizeLod:
+    case spv::Op::OpImageQuerySize:
+    case spv::Op::OpImageQueryLod:
+    case spv::Op::OpImageQueryLevels:
+    case spv::Op::OpImageQuerySamples:
+
+    case spv::Op::OpImageSampleWeightedQCOM:
+    case spv::Op::OpImageBoxFilterQCOM:
+    case spv::Op::OpImageBlockMatchSSDQCOM:
+    case spv::Op::OpImageBlockMatchSADQCOM:
+    case spv::Op::OpImageBlockMatchWindowSADQCOM:
+    case spv::Op::OpImageBlockMatchWindowSSDQCOM:
+    case spv::Op::OpImageBlockMatchGatherSADQCOM:
+    case spv::Op::OpImageBlockMatchGatherSSDQCOM:
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
+spv_result_t ValidateQCOMImageProcessingTextureUsages(ValidationState_t& _,
+                                                      const Instruction* inst) {
+  const spv::Op opcode = inst->opcode();
+  if (!IsImageInstruction(opcode)) return SPV_SUCCESS;
+
+  switch (opcode) {
+    case spv::Op::OpImageSampleWeightedQCOM:
+    case spv::Op::OpImageBoxFilterQCOM:
+    case spv::Op::OpImageBlockMatchSSDQCOM:
+    case spv::Op::OpImageBlockMatchSADQCOM:
+      break;
+    case spv::Op::OpImageBlockMatchWindowSADQCOM:
+    case spv::Op::OpImageBlockMatchWindowSSDQCOM:
+    case spv::Op::OpImageBlockMatchGatherSADQCOM:
+    case spv::Op::OpImageBlockMatchGatherSSDQCOM:
+      break;
+    default:
+      for (size_t i = 0; i < inst->operands().size(); ++i) {
+        int id = inst->GetOperandAs<int>(i);
+        const Instruction* operand_inst = _.FindDef(id);
+        if (operand_inst == nullptr) continue;
+        if (operand_inst->opcode() == spv::Op::OpLoad) {
+          if (_.IsQCOMImageProcessingTextureConsumer(id)) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << "Illegal use of QCOM image processing decorated texture";
+          }
+        }
+        if (operand_inst->opcode() == spv::Op::OpSampledImage) {
+          if (_.IsQCOMImageProcessingTextureConsumer(id)) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << "Illegal use of QCOM image processing decorated texture";
+          }
+        }
+      }
+      break;
+  }
+  return SPV_SUCCESS;
+}
+
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/val/validate_instruction.cpp b/third_party/SPIRV-Tools/source/val/validate_instruction.cpp
index fde6e52..5bc4d2c 100644
--- a/third_party/SPIRV-Tools/source/val/validate_instruction.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_instruction.cpp
@@ -38,14 +38,14 @@
 std::string ToString(const CapabilitySet& capabilities,
                      const AssemblyGrammar& grammar) {
   std::stringstream ss;
-  capabilities.ForEach([&grammar, &ss](spv::Capability cap) {
+  for (auto capability : capabilities) {
     spv_operand_desc desc;
     if (SPV_SUCCESS == grammar.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
-                                             uint32_t(cap), &desc))
+                                             uint32_t(capability), &desc))
       ss << desc->name << " ";
     else
-      ss << uint32_t(cap) << " ";
-  });
+      ss << uint32_t(capability) << " ";
+  }
   return ss.str();
 }
 
@@ -178,10 +178,11 @@
 
       // Vulkan API requires more capabilities on rounding mode.
       if (spvIsVulkanEnv(state.context()->target_env)) {
-        enabling_capabilities.Add(spv::Capability::StorageUniformBufferBlock16);
-        enabling_capabilities.Add(spv::Capability::StorageUniform16);
-        enabling_capabilities.Add(spv::Capability::StoragePushConstant16);
-        enabling_capabilities.Add(spv::Capability::StorageInputOutput16);
+        enabling_capabilities.insert(
+            spv::Capability::StorageUniformBufferBlock16);
+        enabling_capabilities.insert(spv::Capability::StorageUniform16);
+        enabling_capabilities.insert(spv::Capability::StoragePushConstant16);
+        enabling_capabilities.insert(spv::Capability::StorageInputOutput16);
       }
     } else {
       enabling_capabilities = state.grammar().filterCapsAgainstTargetEnv(
@@ -195,7 +196,7 @@
     if (inst->opcode() != spv::Op::OpCapability) {
       const bool enabled_by_cap =
           state.HasAnyOfCapabilities(enabling_capabilities);
-      if (!enabling_capabilities.IsEmpty() && !enabled_by_cap) {
+      if (!enabling_capabilities.empty() && !enabled_by_cap) {
         return state.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
                << "Operand " << which_operand << " of "
                << spvOpcodeString(inst->opcode())
@@ -303,7 +304,7 @@
   }
 
   ExtensionSet exts(inst_desc->numExtensions, inst_desc->extensions);
-  if (exts.IsEmpty()) {
+  if (exts.empty()) {
     // If no extensions can enable this instruction, then emit error
     // messages only concerning core SPIR-V versions if errors happen.
     if (min_version == ~0u) {
@@ -469,7 +470,8 @@
     }
     _.set_addressing_model(inst->GetOperandAs<spv::AddressingModel>(0));
     _.set_memory_model(inst->GetOperandAs<spv::MemoryModel>(1));
-  } else if (opcode == spv::Op::OpExecutionMode) {
+  } else if (opcode == spv::Op::OpExecutionMode ||
+             opcode == spv::Op::OpExecutionModeId) {
     const uint32_t entry_point = inst->word(1);
     _.RegisterExecutionModeForEntryPoint(entry_point,
                                          spv::ExecutionMode(inst->word(2)));
diff --git a/third_party/SPIRV-Tools/source/val/validate_interfaces.cpp b/third_party/SPIRV-Tools/source/val/validate_interfaces.cpp
index 3566698..ace548a 100644
--- a/third_party/SPIRV-Tools/source/val/validate_interfaces.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_interfaces.cpp
@@ -173,8 +173,19 @@
       }
       break;
     }
+    case spv::Op::OpTypePointer: {
+      if (_.addressing_model() ==
+              spv::AddressingModel::PhysicalStorageBuffer64 &&
+          type->GetOperandAs<spv::StorageClass>(1) ==
+              spv::StorageClass::PhysicalStorageBuffer) {
+        *num_locations = 1;
+        break;
+      }
+      [[fallthrough]];
+    }
     default:
-      break;
+      return _.diag(SPV_ERROR_INVALID_DATA, type)
+             << "Invalid type to assign a location";
   }
 
   return SPV_SUCCESS;
@@ -206,6 +217,14 @@
       // Skip the array.
       return NumConsumedComponents(_,
                                    _.FindDef(type->GetOperandAs<uint32_t>(1)));
+    case spv::Op::OpTypePointer:
+      if (_.addressing_model() ==
+              spv::AddressingModel::PhysicalStorageBuffer64 &&
+          type->GetOperandAs<spv::StorageClass>(1) ==
+              spv::StorageClass::PhysicalStorageBuffer) {
+        return 2;
+      }
+      break;
     default:
       // This is an error that is validated elsewhere.
       break;
@@ -235,37 +254,24 @@
   // equal. Also track Patch and PerTaskNV decorations.
   bool has_location = false;
   uint32_t location = 0;
-  bool has_component = false;
   uint32_t component = 0;
   bool has_index = false;
   uint32_t index = 0;
   bool has_patch = false;
   bool has_per_task_nv = false;
   bool has_per_vertex_khr = false;
+  // Duplicate Location, Component, Index are checked elsewhere.
   for (auto& dec : _.id_decorations(variable->id())) {
     if (dec.dec_type() == spv::Decoration::Location) {
-      if (has_location && dec.params()[0] != location) {
-        return _.diag(SPV_ERROR_INVALID_DATA, variable)
-               << "Variable has conflicting location decorations";
-      }
       has_location = true;
       location = dec.params()[0];
     } else if (dec.dec_type() == spv::Decoration::Component) {
-      if (has_component && dec.params()[0] != component) {
-        return _.diag(SPV_ERROR_INVALID_DATA, variable)
-               << "Variable has conflicting component decorations";
-      }
-      has_component = true;
       component = dec.params()[0];
     } else if (dec.dec_type() == spv::Decoration::Index) {
       if (!is_output || !is_fragment) {
         return _.diag(SPV_ERROR_INVALID_DATA, variable)
                << "Index can only be applied to Fragment output variables";
       }
-      if (has_index && dec.params()[0] != index) {
-        return _.diag(SPV_ERROR_INVALID_DATA, variable)
-               << "Variable has conflicting index decorations";
-      }
       has_index = true;
       index = dec.params()[0];
     } else if (dec.dec_type() == spv::Decoration::BuiltIn) {
@@ -363,12 +369,12 @@
       sub_type = _.FindDef(sub_type_id);
     }
 
-    for (uint32_t array_idx = 0; array_idx < array_size; ++array_idx) {
-      uint32_t num_locations = 0;
-      if (auto error = NumConsumedLocations(_, sub_type, &num_locations))
-        return error;
+    uint32_t num_locations = 0;
+    if (auto error = NumConsumedLocations(_, sub_type, &num_locations))
+      return error;
+    uint32_t num_components = NumConsumedComponents(_, sub_type);
 
-      uint32_t num_components = NumConsumedComponents(_, sub_type);
+    for (uint32_t array_idx = 0; array_idx < array_size; ++array_idx) {
       uint32_t array_location = location + (num_locations * array_idx);
       uint32_t start = array_location * 4;
       if (kMaxLocations <= start) {
@@ -388,6 +394,7 @@
       for (uint32_t i = start; i < end; ++i) {
         if (!locs->insert(i).second) {
           return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+                 << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
                  << "Entry-point has conflicting " << storage_class
                  << " location assignment at location " << i / 4
                  << ", component " << i % 4;
@@ -459,6 +466,7 @@
             uint32_t check = 4 * l + c;
             if (!locations->insert(check).second) {
               return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+                     << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
                      << "Entry-point has conflicting " << storage_class
                      << " location assignment at location " << l
                      << ", component " << c;
@@ -476,6 +484,7 @@
         for (uint32_t l = start; l < end; ++l) {
           if (!locations->insert(l).second) {
             return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+                   << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
                    << "Entry-point has conflicting " << storage_class
                    << " location assignment at location " << l / 4
                    << ", component " << l % 4;
@@ -536,6 +545,64 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t ValidateStorageClass(ValidationState_t& _,
+                                  const Instruction* entry_point) {
+  bool has_push_constant = false;
+  bool has_ray_payload = false;
+  bool has_hit_attribute = false;
+  bool has_callable_data = false;
+  for (uint32_t i = 3; i < entry_point->operands().size(); ++i) {
+    auto interface_id = entry_point->GetOperandAs<uint32_t>(i);
+    auto interface_var = _.FindDef(interface_id);
+    auto storage_class = interface_var->GetOperandAs<spv::StorageClass>(2);
+    switch (storage_class) {
+      case spv::StorageClass::PushConstant: {
+        if (has_push_constant) {
+          return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+                 << _.VkErrorID(6673)
+                 << "Entry-point has more than one variable with the "
+                    "PushConstant storage class in the interface";
+        }
+        has_push_constant = true;
+        break;
+      }
+      case spv::StorageClass::IncomingRayPayloadKHR: {
+        if (has_ray_payload) {
+          return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+                 << _.VkErrorID(4700)
+                 << "Entry-point has more than one variable with the "
+                    "IncomingRayPayloadKHR storage class in the interface";
+        }
+        has_ray_payload = true;
+        break;
+      }
+      case spv::StorageClass::HitAttributeKHR: {
+        if (has_hit_attribute) {
+          return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+                 << _.VkErrorID(4702)
+                 << "Entry-point has more than one variable with the "
+                    "HitAttributeKHR storage class in the interface";
+        }
+        has_hit_attribute = true;
+        break;
+      }
+      case spv::StorageClass::IncomingCallableDataKHR: {
+        if (has_callable_data) {
+          return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+                 << _.VkErrorID(4706)
+                 << "Entry-point has more than one variable with the "
+                    "IncomingCallableDataKHR storage class in the interface";
+        }
+        has_callable_data = true;
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  return SPV_SUCCESS;
+}
+
 }  // namespace
 
 spv_result_t ValidateInterfaces(ValidationState_t& _) {
@@ -554,6 +621,9 @@
         if (auto error = ValidateLocations(_, &inst)) {
           return error;
         }
+        if (auto error = ValidateStorageClass(_, &inst)) {
+          return error;
+        }
       }
       if (inst.opcode() == spv::Op::OpTypeVoid) break;
     }
diff --git a/third_party/SPIRV-Tools/source/val/validate_memory.cpp b/third_party/SPIRV-Tools/source/val/validate_memory.cpp
index 5f7358c..2d6715f 100644
--- a/third_party/SPIRV-Tools/source/val/validate_memory.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_memory.cpp
@@ -204,6 +204,7 @@
 
   switch (storage->opcode()) {
     case spv::Op::OpTypeCooperativeMatrixNV:
+    case spv::Op::OpTypeCooperativeMatrixKHR:
       return true;
     case spv::Op::OpTypeArray:
     case spv::Op::OpTypeRuntimeArray:
@@ -232,6 +233,7 @@
   spv::StorageClass src_sc = spv::StorageClass::Max;
   switch (inst->opcode()) {
     case spv::Op::OpCooperativeMatrixLoadNV:
+    case spv::Op::OpCooperativeMatrixLoadKHR:
     case spv::Op::OpLoad: {
       auto load_pointer = _.FindDef(inst->GetOperandAs<uint32_t>(2));
       auto load_pointer_type = _.FindDef(load_pointer->type_id());
@@ -239,6 +241,7 @@
       break;
     }
     case spv::Op::OpCooperativeMatrixStoreNV:
+    case spv::Op::OpCooperativeMatrixStoreKHR:
     case spv::Op::OpStore: {
       auto store_pointer = _.FindDef(inst->GetOperandAs<uint32_t>(0));
       auto store_pointer_type = _.FindDef(store_pointer->type_id());
@@ -326,7 +329,8 @@
   const uint32_t mask = inst->GetOperandAs<uint32_t>(index);
   if (mask & uint32_t(spv::MemoryAccessMask::MakePointerAvailableKHR)) {
     if (inst->opcode() == spv::Op::OpLoad ||
-        inst->opcode() == spv::Op::OpCooperativeMatrixLoadNV) {
+        inst->opcode() == spv::Op::OpCooperativeMatrixLoadNV ||
+        inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) {
       return _.diag(SPV_ERROR_INVALID_ID, inst)
              << "MakePointerAvailableKHR cannot be used with OpLoad.";
     }
@@ -442,6 +446,7 @@
       storage_class != spv::StorageClass::CrossWorkgroup &&
       storage_class != spv::StorageClass::Private &&
       storage_class != spv::StorageClass::Function &&
+      storage_class != spv::StorageClass::UniformConstant &&
       storage_class != spv::StorageClass::RayPayloadKHR &&
       storage_class != spv::StorageClass::IncomingRayPayloadKHR &&
       storage_class != spv::StorageClass::HitAttributeKHR &&
@@ -475,8 +480,8 @@
                   "can only be used with non-externally visible shader Storage "
                   "Classes: Workgroup, CrossWorkgroup, Private, Function, "
                   "Input, Output, RayPayloadKHR, IncomingRayPayloadKHR, "
-                  "HitAttributeKHR, CallableDataKHR, or "
-                  "IncomingCallableDataKHR";
+                  "HitAttributeKHR, CallableDataKHR, "
+                  "IncomingCallableDataKHR, or UniformConstant";
       }
     }
   }
@@ -961,6 +966,8 @@
     }
   }
 
+  _.RegisterQCOMImageProcessingTextureConsumer(pointer_id, inst, nullptr);
+
   return SPV_SUCCESS;
 }
 
@@ -1356,6 +1363,7 @@
       case spv::Op::OpTypeMatrix:
       case spv::Op::OpTypeVector:
       case spv::Op::OpTypeCooperativeMatrixNV:
+      case spv::Op::OpTypeCooperativeMatrixKHR:
       case spv::Op::OpTypeArray:
       case spv::Op::OpTypeRuntimeArray: {
         // In OpTypeMatrix, OpTypeVector, spv::Op::OpTypeCooperativeMatrixNV,
@@ -1366,33 +1374,30 @@
       case spv::Op::OpTypeStruct: {
         // In case of structures, there is an additional constraint on the
         // index: the index must be an OpConstant.
-        if (spv::Op::OpConstant != cur_word_instr->opcode()) {
+        int64_t cur_index;
+        if (!_.EvalConstantValInt64(cur_word, &cur_index)) {
           return _.diag(SPV_ERROR_INVALID_ID, cur_word_instr)
                  << "The <id> passed to " << instr_name
                  << " to index into a "
                     "structure must be an OpConstant.";
         }
-        // Get the index value from the OpConstant (word 3 of OpConstant).
-        // OpConstant could be a signed integer. But it's okay to treat it as
-        // unsigned because a negative constant int would never be seen as
-        // correct as a struct offset, since structs can't have more than 2
-        // billion members.
-        const uint32_t cur_index = cur_word_instr->word(3);
+
         // The index points to the struct member we want, therefore, the index
         // should be less than the number of struct members.
-        const uint32_t num_struct_members =
-            static_cast<uint32_t>(type_pointee->words().size() - 2);
-        if (cur_index >= num_struct_members) {
+        const int64_t num_struct_members =
+            static_cast<int64_t>(type_pointee->words().size() - 2);
+        if (cur_index >= num_struct_members || cur_index < 0) {
           return _.diag(SPV_ERROR_INVALID_ID, cur_word_instr)
                  << "Index is out of bounds: " << instr_name
-                 << " can not find index " << cur_index
+                 << " cannot find index " << cur_index
                  << " into the structure <id> "
                  << _.getIdName(type_pointee->id()) << ". This structure has "
                  << num_struct_members << " members. Largest valid index is "
                  << num_struct_members - 1 << ".";
         }
         // Struct members IDs start at word 2 of OpTypeStruct.
-        auto structMemberId = type_pointee->word(cur_index + 2);
+        const size_t word_index = static_cast<size_t>(cur_index) + 2;
+        auto structMemberId = type_pointee->word(word_index);
         type_pointee = _.FindDef(structMemberId);
         break;
       }
@@ -1405,7 +1410,7 @@
       }
     }
   }
-  // At this point, we have fully walked down from the base using the indeces.
+  // At this point, we have fully walked down from the base using the indices.
   // The type being pointed to should be the same as the result type.
   if (type_pointee->id() != result_type_pointee->id()) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
@@ -1422,6 +1427,126 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t ValidateRawAccessChain(ValidationState_t& _,
+                                    const Instruction* inst) {
+  std::string instr_name = "Op" + std::string(spvOpcodeString(inst->opcode()));
+
+  // The result type must be OpTypePointer.
+  const auto result_type = _.FindDef(inst->type_id());
+  if (spv::Op::OpTypePointer != result_type->opcode()) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "The Result Type of " << instr_name << " <id> "
+           << _.getIdName(inst->id()) << " must be OpTypePointer. Found Op"
+           << spvOpcodeString(result_type->opcode()) << '.';
+  }
+
+  // The pointed storage class must be valid.
+  const auto storage_class = result_type->GetOperandAs<spv::StorageClass>(1);
+  if (storage_class != spv::StorageClass::StorageBuffer &&
+      storage_class != spv::StorageClass::PhysicalStorageBuffer &&
+      storage_class != spv::StorageClass::Uniform) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "The Result Type of " << instr_name << " <id> "
+           << _.getIdName(inst->id())
+           << " must point to a storage class of "
+              "StorageBuffer, PhysicalStorageBuffer, or Uniform.";
+  }
+
+  // The pointed type must not be one in the list below.
+  const auto result_type_pointee =
+      _.FindDef(result_type->GetOperandAs<uint32_t>(2));
+  if (result_type_pointee->opcode() == spv::Op::OpTypeArray ||
+      result_type_pointee->opcode() == spv::Op::OpTypeMatrix ||
+      result_type_pointee->opcode() == spv::Op::OpTypeStruct) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "The Result Type of " << instr_name << " <id> "
+           << _.getIdName(inst->id())
+           << " must not point to "
+              "OpTypeArray, OpTypeMatrix, or OpTypeStruct.";
+  }
+
+  // Validate Stride is a OpConstant.
+  const auto stride = _.FindDef(inst->GetOperandAs<uint32_t>(3));
+  if (stride->opcode() != spv::Op::OpConstant) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "The Stride of " << instr_name << " <id> "
+           << _.getIdName(inst->id()) << " must be OpConstant. Found Op"
+           << spvOpcodeString(stride->opcode()) << '.';
+  }
+  // Stride type must be OpTypeInt
+  const auto stride_type = _.FindDef(stride->type_id());
+  if (stride_type->opcode() != spv::Op::OpTypeInt) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "The type of Stride of " << instr_name << " <id> "
+           << _.getIdName(inst->id()) << " must be OpTypeInt. Found Op"
+           << spvOpcodeString(stride_type->opcode()) << '.';
+  }
+
+  // Index and Offset type must be OpTypeInt with a width of 32
+  const auto ValidateType = [&](const char* name,
+                                int operandIndex) -> spv_result_t {
+    const auto value = _.FindDef(inst->GetOperandAs<uint32_t>(operandIndex));
+    const auto value_type = _.FindDef(value->type_id());
+    if (value_type->opcode() != spv::Op::OpTypeInt) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "The type of " << name << " of " << instr_name << " <id> "
+             << _.getIdName(inst->id()) << " must be OpTypeInt. Found Op"
+             << spvOpcodeString(value_type->opcode()) << '.';
+    }
+    const auto width = value_type->GetOperandAs<uint32_t>(1);
+    if (width != 32) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "The integer width of " << name << " of " << instr_name
+             << " <id> " << _.getIdName(inst->id()) << " must be 32. Found "
+             << width << '.';
+    }
+    return SPV_SUCCESS;
+  };
+  spv_result_t result;
+  result = ValidateType("Index", 4);
+  if (result != SPV_SUCCESS) {
+    return result;
+  }
+  result = ValidateType("Offset", 5);
+  if (result != SPV_SUCCESS) {
+    return result;
+  }
+
+  uint32_t access_operands = 0;
+  if (inst->operands().size() >= 7) {
+    access_operands = inst->GetOperandAs<uint32_t>(6);
+  }
+  if (access_operands &
+      uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerElementNV)) {
+    uint64_t stride_value = 0;
+    if (_.EvalConstantValUint64(stride->id(), &stride_value) &&
+        stride_value == 0) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "Stride must not be zero when per-element robustness is used.";
+    }
+  }
+  if (access_operands &
+          uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerComponentNV) ||
+      access_operands &
+          uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerElementNV)) {
+    if (storage_class == spv::StorageClass::PhysicalStorageBuffer) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "Storage class cannot be PhysicalStorageBuffer when "
+                "raw access chain robustness is used.";
+    }
+  }
+  if (access_operands &
+          uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerComponentNV) &&
+      access_operands &
+          uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerElementNV)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Per-component robustness and per-element robustness are "
+              "mutually exclusive.";
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t ValidatePtrAccessChain(ValidationState_t& _,
                                     const Instruction* inst) {
   if (_.addressing_model() == spv::AddressingModel::Logical) {
@@ -1553,9 +1678,15 @@
            << " must be OpTypeInt with width 32 and signedness 0.";
   }
 
+  bool isKhr = inst->opcode() == spv::Op::OpCooperativeMatrixLengthKHR;
   auto type_id = inst->GetOperandAs<uint32_t>(2);
   auto type = state.FindDef(type_id);
-  if (type->opcode() != spv::Op::OpTypeCooperativeMatrixNV) {
+  if (isKhr && type->opcode() != spv::Op::OpTypeCooperativeMatrixKHR) {
+    return state.diag(SPV_ERROR_INVALID_ID, inst)
+           << "The type in " << instr_name << " <id> "
+           << state.getIdName(type_id)
+           << " must be OpTypeCooperativeMatrixKHR.";
+  } else if (!isKhr && type->opcode() != spv::Op::OpTypeCooperativeMatrixNV) {
     return state.diag(SPV_ERROR_INVALID_ID, inst)
            << "The type in " << instr_name << " <id> "
            << state.getIdName(type_id) << " must be OpTypeCooperativeMatrixNV.";
@@ -1667,6 +1798,113 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _,
+                                                   const Instruction* inst) {
+  uint32_t type_id;
+  const char* opname;
+  if (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) {
+    type_id = inst->type_id();
+    opname = "spv::Op::OpCooperativeMatrixLoadKHR";
+  } else {
+    // get Object operand's type
+    type_id = _.FindDef(inst->GetOperandAs<uint32_t>(1))->type_id();
+    opname = "spv::Op::OpCooperativeMatrixStoreKHR";
+  }
+
+  auto matrix_type = _.FindDef(type_id);
+
+  if (matrix_type->opcode() != spv::Op::OpTypeCooperativeMatrixKHR) {
+    if (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "spv::Op::OpCooperativeMatrixLoadKHR Result Type <id> "
+             << _.getIdName(type_id) << " is not a cooperative matrix type.";
+    } else {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "spv::Op::OpCooperativeMatrixStoreKHR Object type <id> "
+             << _.getIdName(type_id) << " is not a cooperative matrix type.";
+    }
+  }
+
+  const auto pointer_index =
+      (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 2u : 0u;
+  const auto pointer_id = inst->GetOperandAs<uint32_t>(pointer_index);
+  const auto pointer = _.FindDef(pointer_id);
+  if (!pointer ||
+      ((_.addressing_model() == spv::AddressingModel::Logical) &&
+       ((!_.features().variable_pointers &&
+         !spvOpcodeReturnsLogicalPointer(pointer->opcode())) ||
+        (_.features().variable_pointers &&
+         !spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << opname << " Pointer <id> " << _.getIdName(pointer_id)
+           << " is not a logical pointer.";
+  }
+
+  const auto pointer_type_id = pointer->type_id();
+  const auto pointer_type = _.FindDef(pointer_type_id);
+  if (!pointer_type || pointer_type->opcode() != spv::Op::OpTypePointer) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << opname << " type for pointer <id> " << _.getIdName(pointer_id)
+           << " is not a pointer type.";
+  }
+
+  const auto storage_class_index = 1u;
+  const auto storage_class =
+      pointer_type->GetOperandAs<spv::StorageClass>(storage_class_index);
+
+  if (storage_class != spv::StorageClass::Workgroup &&
+      storage_class != spv::StorageClass::StorageBuffer &&
+      storage_class != spv::StorageClass::PhysicalStorageBuffer) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << _.VkErrorID(8973) << opname
+           << " storage class for pointer type <id> "
+           << _.getIdName(pointer_type_id)
+           << " is not Workgroup, StorageBuffer, or PhysicalStorageBuffer.";
+  }
+
+  const auto pointee_id = pointer_type->GetOperandAs<uint32_t>(2);
+  const auto pointee_type = _.FindDef(pointee_id);
+  if (!pointee_type || !(_.IsIntScalarOrVectorType(pointee_id) ||
+                         _.IsFloatScalarOrVectorType(pointee_id))) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << opname << " Pointer <id> " << _.getIdName(pointer->id())
+           << "s Type must be a scalar or vector type.";
+  }
+
+  const auto layout_index =
+      (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 3u : 2u;
+  const auto colmajor_id = inst->GetOperandAs<uint32_t>(layout_index);
+  const auto colmajor = _.FindDef(colmajor_id);
+  if (!colmajor || !_.IsIntScalarType(colmajor->type_id()) ||
+      !(spvOpcodeIsConstant(colmajor->opcode()) ||
+        spvOpcodeIsSpecConstant(colmajor->opcode()))) {
+    return _.diag(SPV_ERROR_INVALID_ID, inst)
+           << "MemoryLayout operand <id> " << _.getIdName(colmajor_id)
+           << " must be a 32-bit integer constant instruction.";
+  }
+
+  const auto stride_index =
+      (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 4u : 3u;
+  if (inst->operands().size() > stride_index) {
+    const auto stride_id = inst->GetOperandAs<uint32_t>(stride_index);
+    const auto stride = _.FindDef(stride_id);
+    if (!stride || !_.IsIntScalarType(stride->type_id())) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "Stride operand <id> " << _.getIdName(stride_id)
+             << " must be a scalar integer type.";
+    }
+  }
+
+  const auto memory_access_index =
+      (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 5u : 4u;
+  if (inst->operands().size() > memory_access_index) {
+    if (auto error = CheckMemoryAccess(_, inst, memory_access_index))
+      return error;
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t ValidatePtrComparison(ValidationState_t& _,
                                    const Instruction* inst) {
   if (_.addressing_model() == spv::AddressingModel::Logical &&
@@ -1748,6 +1986,9 @@
     case spv::Op::OpInBoundsPtrAccessChain:
       if (auto error = ValidateAccessChain(_, inst)) return error;
       break;
+    case spv::Op::OpRawAccessChainNV:
+      if (auto error = ValidateRawAccessChain(_, inst)) return error;
+      break;
     case spv::Op::OpArrayLength:
       if (auto error = ValidateArrayLength(_, inst)) return error;
       break;
@@ -1756,9 +1997,15 @@
       if (auto error = ValidateCooperativeMatrixLoadStoreNV(_, inst))
         return error;
       break;
+    case spv::Op::OpCooperativeMatrixLengthKHR:
     case spv::Op::OpCooperativeMatrixLengthNV:
       if (auto error = ValidateCooperativeMatrixLengthNV(_, inst)) return error;
       break;
+    case spv::Op::OpCooperativeMatrixLoadKHR:
+    case spv::Op::OpCooperativeMatrixStoreKHR:
+      if (auto error = ValidateCooperativeMatrixLoadStoreKHR(_, inst))
+        return error;
+      break;
     case spv::Op::OpPtrEqual:
     case spv::Op::OpPtrNotEqual:
     case spv::Op::OpPtrDiff:
diff --git a/third_party/SPIRV-Tools/source/val/validate_memory_semantics.cpp b/third_party/SPIRV-Tools/source/val/validate_memory_semantics.cpp
index c4f22a6..dab7b5a 100644
--- a/third_party/SPIRV-Tools/source/val/validate_memory_semantics.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_memory_semantics.cpp
@@ -203,15 +203,12 @@
                 "storage class";
     }
 
-#if 0
-    // TODO(atgoo@github.com): this check fails Vulkan CTS, reenable once fixed.
     if (opcode == spv::Op::OpControlBarrier && value && !includes_storage_class) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
-             << spvOpcodeString(opcode)
+             << _.VkErrorID(4650) << spvOpcodeString(opcode)
              << ": expected Memory Semantics to include a Vulkan-supported "
                 "storage class if Memory Semantics is not None";
     }
-#endif
   }
 
   if (opcode == spv::Op::OpAtomicFlagClear &&
diff --git a/third_party/SPIRV-Tools/source/val/validate_mode_setting.cpp b/third_party/SPIRV-Tools/source/val/validate_mode_setting.cpp
index d757d4f..8502fda 100644
--- a/third_party/SPIRV-Tools/source/val/validate_mode_setting.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_mode_setting.cpp
@@ -340,29 +340,93 @@
 
   const auto mode = inst->GetOperandAs<spv::ExecutionMode>(1);
   if (inst->opcode() == spv::Op::OpExecutionModeId) {
+    bool valid_mode = false;
+    switch (mode) {
+      case spv::ExecutionMode::SubgroupsPerWorkgroupId:
+      case spv::ExecutionMode::LocalSizeHintId:
+      case spv::ExecutionMode::LocalSizeId:
+      case spv::ExecutionMode::FPFastMathDefault:
+      case spv::ExecutionMode::MaximumRegistersIdINTEL:
+        valid_mode = true;
+        break;
+      default:
+        valid_mode = false;
+        break;
+    }
+    if (!valid_mode) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "OpExecutionModeId is only valid when the Mode operand is an "
+                "execution mode that takes Extra Operands that are id "
+                "operands.";
+    }
+
     size_t operand_count = inst->operands().size();
     for (size_t i = 2; i < operand_count; ++i) {
-      const auto operand_id = inst->GetOperandAs<uint32_t>(2);
+      const auto operand_id = inst->GetOperandAs<uint32_t>(i);
       const auto* operand_inst = _.FindDef(operand_id);
-      if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
-          mode == spv::ExecutionMode::LocalSizeHintId ||
-          mode == spv::ExecutionMode::LocalSizeId) {
-        if (!spvOpcodeIsConstant(operand_inst->opcode())) {
-          return _.diag(SPV_ERROR_INVALID_ID, inst)
-                 << "For OpExecutionModeId all Extra Operand ids must be "
-                    "constant "
-                    "instructions.";
-        }
-      } else {
-        return _.diag(SPV_ERROR_INVALID_ID, inst)
-               << "OpExecutionModeId is only valid when the Mode operand is an "
-                  "execution mode that takes Extra Operands that are id "
-                  "operands.";
+      switch (mode) {
+        case spv::ExecutionMode::SubgroupsPerWorkgroupId:
+        case spv::ExecutionMode::LocalSizeHintId:
+        case spv::ExecutionMode::LocalSizeId:
+          if (!spvOpcodeIsConstant(operand_inst->opcode())) {
+            return _.diag(SPV_ERROR_INVALID_ID, inst)
+                   << "For OpExecutionModeId all Extra Operand ids must be "
+                      "constant instructions.";
+          }
+          break;
+        case spv::ExecutionMode::FPFastMathDefault:
+          if (i == 2) {
+            if (!_.IsFloatScalarType(operand_id)) {
+              return _.diag(SPV_ERROR_INVALID_ID, inst)
+                     << "The Target Type operand must be a floating-point "
+                        "scalar type";
+            }
+          } else {
+            bool is_int32 = false;
+            bool is_const = false;
+            uint32_t value = 0;
+            std::tie(is_int32, is_const, value) =
+                _.EvalInt32IfConst(operand_id);
+            if (is_int32 && is_const) {
+              // Valid values include up to 0x00040000 (AllowTransform).
+              uint32_t invalid_mask = 0xfff80000;
+              if ((invalid_mask & value) != 0) {
+                return _.diag(SPV_ERROR_INVALID_ID, inst)
+                       << "The Fast Math Default operand is an invalid bitmask "
+                          "value";
+              }
+              if (value &
+                  static_cast<uint32_t>(spv::FPFastMathModeMask::Fast)) {
+                return _.diag(SPV_ERROR_INVALID_ID, inst)
+                       << "The Fast Math Default operand must not include Fast";
+              }
+              const auto reassoc_contract =
+                  spv::FPFastMathModeMask::AllowContract |
+                  spv::FPFastMathModeMask::AllowReassoc;
+              if ((value & static_cast<uint32_t>(
+                               spv::FPFastMathModeMask::AllowTransform)) != 0 &&
+                  ((value & static_cast<uint32_t>(reassoc_contract)) !=
+                   static_cast<uint32_t>(reassoc_contract))) {
+                return _.diag(SPV_ERROR_INVALID_ID, inst)
+                       << "The Fast Math Default operand must include "
+                          "AllowContract and AllowReassoc when AllowTransform "
+                          "is specified";
+              }
+            } else {
+              return _.diag(SPV_ERROR_INVALID_ID, inst)
+                     << "The Fast Math Default operand must be a "
+                        "non-specialization constant";
+            }
+          }
+          break;
+        default:
+          break;
       }
     }
   } else if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
              mode == spv::ExecutionMode::LocalSizeHintId ||
-             mode == spv::ExecutionMode::LocalSizeId) {
+             mode == spv::ExecutionMode::LocalSizeId ||
+             mode == spv::ExecutionMode::FPFastMathDefault) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
            << "OpExecutionMode is only valid when the Mode operand is an "
               "execution mode that takes no Extra Operands, or takes Extra "
@@ -494,6 +558,17 @@
                   "model.";
       }
       break;
+    case spv::ExecutionMode::QuadDerivativesKHR:
+      if (!std::all_of(models->begin(), models->end(),
+                       [](const spv::ExecutionModel& model) {
+                         return (model == spv::ExecutionModel::Fragment ||
+                                 model == spv::ExecutionModel::GLCompute);
+                       })) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Execution mode can only be used with the Fragment or "
+                  "GLCompute execution model.";
+      }
+      break;
     case spv::ExecutionMode::PixelCenterInteger:
     case spv::ExecutionMode::OriginUpperLeft:
     case spv::ExecutionMode::OriginLowerLeft:
@@ -518,6 +593,7 @@
     case spv::ExecutionMode::StencilRefUnchangedBackAMD:
     case spv::ExecutionMode::StencilRefGreaterBackAMD:
     case spv::ExecutionMode::StencilRefLessBackAMD:
+    case spv::ExecutionMode::RequireFullQuadsKHR:
       if (!std::all_of(models->begin(), models->end(),
                        [](const spv::ExecutionModel& model) {
                          return model == spv::ExecutionModel::Fragment;
@@ -579,6 +655,20 @@
       break;
   }
 
+  if (mode == spv::ExecutionMode::FPFastMathDefault) {
+    const auto* modes = _.GetExecutionModes(entry_point_id);
+    if (modes && modes->count(spv::ExecutionMode::ContractionOff)) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "FPFastMathDefault and ContractionOff execution modes cannot "
+                "be applied to the same entry point";
+    }
+    if (modes && modes->count(spv::ExecutionMode::SignedZeroInfNanPreserve)) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "FPFastMathDefault and SignedZeroInfNanPreserve execution "
+                "modes cannot be applied to the same entry point";
+    }
+  }
+
   if (spvIsVulkanEnv(_.context()->target_env)) {
     if (mode == spv::ExecutionMode::OriginLowerLeft) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -634,8 +724,91 @@
   return SPV_SUCCESS;
 }
 
+bool PerEntryExecutionMode(spv::ExecutionMode mode) {
+  switch (mode) {
+    // These execution modes can be specified multiple times per entry point.
+    case spv::ExecutionMode::DenormPreserve:
+    case spv::ExecutionMode::DenormFlushToZero:
+    case spv::ExecutionMode::SignedZeroInfNanPreserve:
+    case spv::ExecutionMode::RoundingModeRTE:
+    case spv::ExecutionMode::RoundingModeRTZ:
+    case spv::ExecutionMode::FPFastMathDefault:
+    case spv::ExecutionMode::RoundingModeRTPINTEL:
+    case spv::ExecutionMode::RoundingModeRTNINTEL:
+    case spv::ExecutionMode::FloatingPointModeALTINTEL:
+    case spv::ExecutionMode::FloatingPointModeIEEEINTEL:
+      return false;
+    default:
+      return true;
+  }
+}
+
 }  // namespace
 
+spv_result_t ValidateFloatControls2(ValidationState_t& _) {
+  std::unordered_set<uint32_t> fp_fast_math_default_entry_points;
+  for (auto entry_point : _.entry_points()) {
+    const auto* exec_modes = _.GetExecutionModes(entry_point);
+    if (exec_modes &&
+        exec_modes->count(spv::ExecutionMode::FPFastMathDefault)) {
+      fp_fast_math_default_entry_points.insert(entry_point);
+    }
+  }
+
+  std::vector<std::pair<const Instruction*, spv::Decoration>> worklist;
+  for (const auto& inst : _.ordered_instructions()) {
+    if (inst.opcode() != spv::Op::OpDecorate) {
+      continue;
+    }
+
+    const auto decoration = inst.GetOperandAs<spv::Decoration>(1);
+    const auto target_id = inst.GetOperandAs<uint32_t>(0);
+    const auto target = _.FindDef(target_id);
+    if (decoration == spv::Decoration::NoContraction) {
+      worklist.push_back(std::make_pair(target, decoration));
+    } else if (decoration == spv::Decoration::FPFastMathMode) {
+      auto mask = inst.GetOperandAs<spv::FPFastMathModeMask>(2);
+      if ((mask & spv::FPFastMathModeMask::Fast) !=
+          spv::FPFastMathModeMask::MaskNone) {
+        worklist.push_back(std::make_pair(target, decoration));
+      }
+    }
+  }
+
+  std::unordered_set<const Instruction*> visited;
+  while (!worklist.empty()) {
+    const auto inst = worklist.back().first;
+    const auto decoration = worklist.back().second;
+    worklist.pop_back();
+
+    if (!visited.insert(inst).second) {
+      continue;
+    }
+
+    const auto function = inst->function();
+    if (function) {
+      const auto& entry_points = _.FunctionEntryPoints(function->id());
+      for (auto entry_point : entry_points) {
+        if (fp_fast_math_default_entry_points.count(entry_point)) {
+          const std::string dec = decoration == spv::Decoration::NoContraction
+                                      ? "NoContraction"
+                                      : "FPFastMathMode Fast";
+          return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                 << dec
+                 << " cannot be used by an entry point with the "
+                    "FPFastMathDefault execution mode";
+        }
+      }
+    } else {
+      for (const auto& pair : inst->uses()) {
+        worklist.push_back(std::make_pair(pair.first, decoration));
+      }
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) {
   switch (inst->opcode()) {
     case spv::Op::OpEntryPoint:
@@ -654,5 +827,52 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t ValidateDuplicateExecutionModes(ValidationState_t& _) {
+  using PerEntryKey = std::tuple<spv::ExecutionMode, uint32_t>;
+  using PerOperandKey = std::tuple<spv::ExecutionMode, uint32_t, uint32_t>;
+  std::set<PerEntryKey> seen_per_entry;
+  std::set<PerOperandKey> seen_per_operand;
+
+  const auto lookupMode = [&_](spv::ExecutionMode mode) -> std::string {
+    spv_operand_desc desc = nullptr;
+    if (_.grammar().lookupOperand(SPV_OPERAND_TYPE_EXECUTION_MODE,
+                                  static_cast<uint32_t>(mode),
+                                  &desc) == SPV_SUCCESS) {
+      return std::string(desc->name);
+    }
+    return "Unknown";
+  };
+
+  for (const auto& inst : _.ordered_instructions()) {
+    if (inst.opcode() != spv::Op::OpExecutionMode &&
+        inst.opcode() != spv::Op::OpExecutionModeId) {
+      continue;
+    }
+
+    const auto entry = inst.GetOperandAs<uint32_t>(0);
+    const auto mode = inst.GetOperandAs<spv::ExecutionMode>(1);
+    if (PerEntryExecutionMode(mode)) {
+      if (!seen_per_entry.insert(std::make_tuple(mode, entry)).second) {
+        return _.diag(SPV_ERROR_INVALID_ID, &inst)
+               << lookupMode(mode)
+               << " execution mode must not be specified multiple times per "
+                  "entry point";
+      }
+    } else {
+      // Execution modes allowed multiple times all take a single operand.
+      const auto operand = inst.GetOperandAs<uint32_t>(2);
+      if (!seen_per_operand.insert(std::make_tuple(mode, entry, operand))
+               .second) {
+        return _.diag(SPV_ERROR_INVALID_ID, &inst)
+               << lookupMode(mode)
+               << " execution mode must not be specified multiple times for "
+                  "the same entry point and operands";
+      }
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/val/validate_non_uniform.cpp b/third_party/SPIRV-Tools/source/val/validate_non_uniform.cpp
index af04e76..75967d2 100644
--- a/third_party/SPIRV-Tools/source/val/validate_non_uniform.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_non_uniform.cpp
@@ -26,6 +26,207 @@
 namespace val {
 namespace {
 
+spv_result_t ValidateGroupNonUniformElect(ValidationState_t& _,
+                                          const Instruction* inst) {
+  if (!_.IsBoolScalarType(inst->type_id())) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be a boolean scalar type";
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateGroupNonUniformAnyAll(ValidationState_t& _,
+                                           const Instruction* inst) {
+  if (!_.IsBoolScalarType(inst->type_id())) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be a boolean scalar type";
+  }
+
+  if (!_.IsBoolScalarType(_.GetOperandTypeId(inst, 3))) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Predicate must be a boolean scalar type";
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateGroupNonUniformAllEqual(ValidationState_t& _,
+                                             const Instruction* inst) {
+  if (!_.IsBoolScalarType(inst->type_id())) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be a boolean scalar type";
+  }
+
+  const auto value_type = _.GetOperandTypeId(inst, 3);
+  if (!_.IsFloatScalarOrVectorType(value_type) &&
+      !_.IsIntScalarOrVectorType(value_type) &&
+      !_.IsBoolScalarOrVectorType(value_type)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Value must be a scalar or vector of integer, floating-point, or "
+              "boolean type";
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateGroupNonUniformBroadcastShuffle(ValidationState_t& _,
+                                                     const Instruction* inst) {
+  const auto type_id = inst->type_id();
+  if (!_.IsFloatScalarOrVectorType(type_id) &&
+      !_.IsIntScalarOrVectorType(type_id) &&
+      !_.IsBoolScalarOrVectorType(type_id)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be a scalar or vector of integer, floating-point, "
+              "or boolean type";
+  }
+
+  const auto value_type_id = _.GetOperandTypeId(inst, 3);
+  if (value_type_id != type_id) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "The type of Value must match the Result type";
+  }
+
+  const auto GetOperandName = [](const spv::Op opcode) {
+    std::string operand;
+    switch (opcode) {
+      case spv::Op::OpGroupNonUniformBroadcast:
+      case spv::Op::OpGroupNonUniformShuffle:
+        operand = "Id";
+        break;
+      case spv::Op::OpGroupNonUniformShuffleXor:
+        operand = "Mask";
+        break;
+      case spv::Op::OpGroupNonUniformQuadBroadcast:
+        operand = "Index";
+        break;
+      case spv::Op::OpGroupNonUniformQuadSwap:
+        operand = "Direction";
+        break;
+      case spv::Op::OpGroupNonUniformShuffleUp:
+      case spv::Op::OpGroupNonUniformShuffleDown:
+      default:
+        operand = "Delta";
+        break;
+    }
+    return operand;
+  };
+
+  const auto id_type_id = _.GetOperandTypeId(inst, 4);
+  if (!_.IsUnsignedIntScalarType(id_type_id)) {
+    std::string operand = GetOperandName(inst->opcode());
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << operand << " must be an unsigned integer scalar";
+  }
+
+  const bool should_be_constant =
+      inst->opcode() == spv::Op::OpGroupNonUniformQuadSwap ||
+      ((inst->opcode() == spv::Op::OpGroupNonUniformBroadcast ||
+        inst->opcode() == spv::Op::OpGroupNonUniformQuadBroadcast) &&
+       _.version() < SPV_SPIRV_VERSION_WORD(1, 5));
+  if (should_be_constant) {
+    const auto id_id = inst->GetOperandAs<uint32_t>(4);
+    const auto id_op = _.GetIdOpcode(id_id);
+    if (!spvOpcodeIsConstant(id_op)) {
+      std::string operand = GetOperandName(inst->opcode());
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "Before SPIR-V 1.5, " << operand
+             << " must be a constant instruction";
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateGroupNonUniformBroadcastFirst(ValidationState_t& _,
+                                                   const Instruction* inst) {
+  const auto type_id = inst->type_id();
+  if (!_.IsFloatScalarOrVectorType(type_id) &&
+      !_.IsIntScalarOrVectorType(type_id) &&
+      !_.IsBoolScalarOrVectorType(type_id)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be a scalar or vector of integer, floating-point, "
+              "or boolean type";
+  }
+
+  const auto value_type_id = _.GetOperandTypeId(inst, 3);
+  if (value_type_id != type_id) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "The type of Value must match the Result type";
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateGroupNonUniformBallot(ValidationState_t& _,
+                                           const Instruction* inst) {
+  if (!_.IsUnsignedIntVectorType(inst->type_id())) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be a 4-component unsigned integer vector";
+  }
+
+  if (_.GetDimension(inst->type_id()) != 4) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be a 4-component unsigned integer vector";
+  }
+
+  const auto pred_type_id = _.GetOperandTypeId(inst, 3);
+  if (!_.IsBoolScalarType(pred_type_id)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Predicate must be a boolean scalar";
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateGroupNonUniformInverseBallot(ValidationState_t& _,
+                                                  const Instruction* inst) {
+  if (!_.IsBoolScalarType(inst->type_id())) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be a boolean scalar";
+  }
+
+  const auto value_type_id = _.GetOperandTypeId(inst, 3);
+  if (!_.IsUnsignedIntVectorType(value_type_id)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Value must be a 4-component unsigned integer vector";
+  }
+
+  if (_.GetDimension(value_type_id) != 4) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Value must be a 4-component unsigned integer vector";
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateGroupNonUniformBallotBitExtract(ValidationState_t& _,
+                                                     const Instruction* inst) {
+  if (!_.IsBoolScalarType(inst->type_id())) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be a boolean scalar";
+  }
+
+  const auto value_type_id = _.GetOperandTypeId(inst, 3);
+  if (!_.IsUnsignedIntVectorType(value_type_id)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Value must be a 4-component unsigned integer vector";
+  }
+
+  if (_.GetDimension(value_type_id) != 4) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Value must be a 4-component unsigned integer vector";
+  }
+
+  const auto id_type_id = _.GetOperandTypeId(inst, 4);
+  if (!_.IsUnsignedIntScalarType(id_type_id)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Id must be an unsigned integer scalar";
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t ValidateGroupNonUniformBallotBitCount(ValidationState_t& _,
                                                    const Instruction* inst) {
   // Scope is already checked by ValidateExecutionScope() above.
@@ -60,6 +261,107 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t ValidateGroupNonUniformBallotFind(ValidationState_t& _,
+                                               const Instruction* inst) {
+  if (!_.IsUnsignedIntScalarType(inst->type_id())) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be an unsigned integer scalar";
+  }
+
+  const auto value_type_id = _.GetOperandTypeId(inst, 3);
+  if (!_.IsUnsignedIntVectorType(value_type_id)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Value must be a 4-component unsigned integer vector";
+  }
+
+  if (_.GetDimension(value_type_id) != 4) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Value must be a 4-component unsigned integer vector";
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t ValidateGroupNonUniformArithmetic(ValidationState_t& _,
+                                               const Instruction* inst) {
+  const bool is_unsigned = inst->opcode() == spv::Op::OpGroupNonUniformUMin ||
+                           inst->opcode() == spv::Op::OpGroupNonUniformUMax;
+  const bool is_float = inst->opcode() == spv::Op::OpGroupNonUniformFAdd ||
+                        inst->opcode() == spv::Op::OpGroupNonUniformFMul ||
+                        inst->opcode() == spv::Op::OpGroupNonUniformFMin ||
+                        inst->opcode() == spv::Op::OpGroupNonUniformFMax;
+  const bool is_bool = inst->opcode() == spv::Op::OpGroupNonUniformLogicalAnd ||
+                       inst->opcode() == spv::Op::OpGroupNonUniformLogicalOr ||
+                       inst->opcode() == spv::Op::OpGroupNonUniformLogicalXor;
+  if (is_float) {
+    if (!_.IsFloatScalarOrVectorType(inst->type_id())) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "Result must be a floating-point scalar or vector";
+    }
+  } else if (is_bool) {
+    if (!_.IsBoolScalarOrVectorType(inst->type_id())) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "Result must be a boolean scalar or vector";
+    }
+  } else if (is_unsigned) {
+    if (!_.IsUnsignedIntScalarOrVectorType(inst->type_id())) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "Result must be an unsigned integer scalar or vector";
+    }
+  } else if (!_.IsIntScalarOrVectorType(inst->type_id())) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "Result must be an integer scalar or vector";
+  }
+
+  const auto value_type_id = _.GetOperandTypeId(inst, 4);
+  if (value_type_id != inst->type_id()) {
+    return _.diag(SPV_ERROR_INVALID_DATA, inst)
+           << "The type of Value must match the Result type";
+  }
+
+  const auto group_op = inst->GetOperandAs<spv::GroupOperation>(3);
+  bool is_clustered_reduce = group_op == spv::GroupOperation::ClusteredReduce;
+  bool is_partitioned_nv =
+      group_op == spv::GroupOperation::PartitionedReduceNV ||
+      group_op == spv::GroupOperation::PartitionedInclusiveScanNV ||
+      group_op == spv::GroupOperation::PartitionedExclusiveScanNV;
+  if (inst->operands().size() <= 5) {
+    if (is_clustered_reduce) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "ClusterSize must be present when Operation is ClusteredReduce";
+    } else if (is_partitioned_nv) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "Ballot must be present when Operation is PartitionedReduceNV, "
+                "PartitionedInclusiveScanNV, or PartitionedExclusiveScanNV";
+    }
+  } else {
+    const auto operand_id = inst->GetOperandAs<uint32_t>(5);
+    const auto* operand = _.FindDef(operand_id);
+    if (is_partitioned_nv) {
+      if (!operand || !_.IsIntScalarOrVectorType(operand->type_id())) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Ballot must be a 4-component integer vector";
+      }
+
+      if (_.GetDimension(operand->type_id()) != 4) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Ballot must be a 4-component integer vector";
+      }
+    } else {
+      if (!operand || !_.IsUnsignedIntScalarType(operand->type_id())) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "ClusterSize must be an unsigned integer scalar";
+      }
+
+      if (!spvOpcodeIsConstant(operand->opcode())) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "ClusterSize must be a constant instruction";
+      }
+    }
+  }
+  return SPV_SUCCESS;
+}
+
 spv_result_t ValidateGroupNonUniformRotateKHR(ValidationState_t& _,
                                               const Instruction* inst) {
   // Scope is already checked by ValidateExecutionScope() above.
@@ -87,20 +389,25 @@
 
   if (inst->words().size() > 6) {
     const uint32_t cluster_size_op_id = inst->GetOperandAs<uint32_t>(5);
-    const uint32_t cluster_size_type = _.GetTypeId(cluster_size_op_id);
+    const Instruction* cluster_size_inst = _.FindDef(cluster_size_op_id);
+    const uint32_t cluster_size_type =
+        cluster_size_inst ? cluster_size_inst->type_id() : 0;
     if (!_.IsUnsignedIntScalarType(cluster_size_type)) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
              << "ClusterSize must be a scalar of integer type, whose "
                 "Signedness operand is 0.";
     }
 
-    uint64_t cluster_size;
-    if (!_.GetConstantValUint64(cluster_size_op_id, &cluster_size)) {
+    if (!spvOpcodeIsConstant(cluster_size_inst->opcode())) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
              << "ClusterSize must come from a constant instruction.";
     }
 
-    if ((cluster_size == 0) || ((cluster_size & (cluster_size - 1)) != 0)) {
+    uint64_t cluster_size;
+    const bool valid_const =
+        _.EvalConstantValUint64(cluster_size_op_id, &cluster_size);
+    if (valid_const &&
+        ((cluster_size == 0) || ((cluster_size & (cluster_size - 1)) != 0))) {
       return _.diag(SPV_WARNING, inst)
              << "Behavior is undefined unless ClusterSize is at least 1 and a "
                 "power of 2.";
@@ -120,15 +427,63 @@
   const spv::Op opcode = inst->opcode();
 
   if (spvOpcodeIsNonUniformGroupOperation(opcode)) {
-    const uint32_t execution_scope = inst->word(3);
-    if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
-      return error;
+    // OpGroupNonUniformQuadAllKHR and OpGroupNonUniformQuadAnyKHR don't have
+    // scope paramter
+    if ((opcode != spv::Op::OpGroupNonUniformQuadAllKHR) &&
+        (opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) {
+      const uint32_t execution_scope = inst->GetOperandAs<uint32_t>(2);
+      if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
+        return error;
+      }
     }
   }
 
   switch (opcode) {
+    case spv::Op::OpGroupNonUniformElect:
+      return ValidateGroupNonUniformElect(_, inst);
+    case spv::Op::OpGroupNonUniformAny:
+    case spv::Op::OpGroupNonUniformAll:
+      return ValidateGroupNonUniformAnyAll(_, inst);
+    case spv::Op::OpGroupNonUniformAllEqual:
+      return ValidateGroupNonUniformAllEqual(_, inst);
+    case spv::Op::OpGroupNonUniformBroadcast:
+    case spv::Op::OpGroupNonUniformShuffle:
+    case spv::Op::OpGroupNonUniformShuffleXor:
+    case spv::Op::OpGroupNonUniformShuffleUp:
+    case spv::Op::OpGroupNonUniformShuffleDown:
+    case spv::Op::OpGroupNonUniformQuadBroadcast:
+    case spv::Op::OpGroupNonUniformQuadSwap:
+      return ValidateGroupNonUniformBroadcastShuffle(_, inst);
+    case spv::Op::OpGroupNonUniformBroadcastFirst:
+      return ValidateGroupNonUniformBroadcastFirst(_, inst);
+    case spv::Op::OpGroupNonUniformBallot:
+      return ValidateGroupNonUniformBallot(_, inst);
+    case spv::Op::OpGroupNonUniformInverseBallot:
+      return ValidateGroupNonUniformInverseBallot(_, inst);
+    case spv::Op::OpGroupNonUniformBallotBitExtract:
+      return ValidateGroupNonUniformBallotBitExtract(_, inst);
     case spv::Op::OpGroupNonUniformBallotBitCount:
       return ValidateGroupNonUniformBallotBitCount(_, inst);
+    case spv::Op::OpGroupNonUniformBallotFindLSB:
+    case spv::Op::OpGroupNonUniformBallotFindMSB:
+      return ValidateGroupNonUniformBallotFind(_, inst);
+    case spv::Op::OpGroupNonUniformIAdd:
+    case spv::Op::OpGroupNonUniformFAdd:
+    case spv::Op::OpGroupNonUniformIMul:
+    case spv::Op::OpGroupNonUniformFMul:
+    case spv::Op::OpGroupNonUniformSMin:
+    case spv::Op::OpGroupNonUniformUMin:
+    case spv::Op::OpGroupNonUniformFMin:
+    case spv::Op::OpGroupNonUniformSMax:
+    case spv::Op::OpGroupNonUniformUMax:
+    case spv::Op::OpGroupNonUniformFMax:
+    case spv::Op::OpGroupNonUniformBitwiseAnd:
+    case spv::Op::OpGroupNonUniformBitwiseOr:
+    case spv::Op::OpGroupNonUniformBitwiseXor:
+    case spv::Op::OpGroupNonUniformLogicalAnd:
+    case spv::Op::OpGroupNonUniformLogicalOr:
+    case spv::Op::OpGroupNonUniformLogicalXor:
+      return ValidateGroupNonUniformArithmetic(_, inst);
     case spv::Op::OpGroupNonUniformRotateKHR:
       return ValidateGroupNonUniformRotateKHR(_, inst);
     default:
diff --git a/third_party/SPIRV-Tools/source/val/validate_scopes.cpp b/third_party/SPIRV-Tools/source/val/validate_scopes.cpp
index 40c49d1..6b49353 100644
--- a/third_party/SPIRV-Tools/source/val/validate_scopes.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_scopes.cpp
@@ -97,8 +97,10 @@
     // Vulkan 1.1 specific rules
     if (_.context()->target_env != SPV_ENV_VULKAN_1_0) {
       // Scope for Non Uniform Group Operations must be limited to Subgroup
-      if (spvOpcodeIsNonUniformGroupOperation(opcode) &&
-          value != spv::Scope::Subgroup) {
+      if ((spvOpcodeIsNonUniformGroupOperation(opcode) &&
+           (opcode != spv::Op::OpGroupNonUniformQuadAllKHR) &&
+           (opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) &&
+          (value != spv::Scope::Subgroup)) {
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << _.VkErrorID(4642) << spvOpcodeString(opcode)
                << ": in Vulkan environment Execution scope is limited to "
@@ -178,6 +180,8 @@
   // Scope for execution must be limited to Workgroup or Subgroup for
   // non-uniform operations
   if (spvOpcodeIsNonUniformGroupOperation(opcode) &&
+      opcode != spv::Op::OpGroupNonUniformQuadAllKHR &&
+      opcode != spv::Op::OpGroupNonUniformQuadAnyKHR &&
       value != spv::Scope::Subgroup && value != spv::Scope::Workgroup) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
            << spvOpcodeString(opcode)
diff --git a/third_party/SPIRV-Tools/source/val/validate_type.cpp b/third_party/SPIRV-Tools/source/val/validate_type.cpp
index 430d819..cb26a52 100644
--- a/third_party/SPIRV-Tools/source/val/validate_type.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_type.cpp
@@ -24,21 +24,6 @@
 namespace val {
 namespace {
 
-// Returns, as an int64_t, the literal value from an OpConstant or the
-// default value of an OpSpecConstant, assuming it is an integral type.
-// For signed integers, relies the rule that literal value is sign extended
-// to fill out to word granularity.  Assumes that the constant value
-// has
-int64_t ConstantLiteralAsInt64(uint32_t width,
-                               const std::vector<uint32_t>& const_words) {
-  const uint32_t lo_word = const_words[3];
-  if (width <= 32) return int32_t(lo_word);
-  assert(width <= 64);
-  assert(const_words.size() > 4);
-  const uint32_t hi_word = const_words[4];  // Must exist, per spec.
-  return static_cast<int64_t>(uint64_t(lo_word) | uint64_t(hi_word) << 32);
-}
-
 // Validates that type declarations are unique, unless multiple declarations
 // of the same data type are allowed by the specification.
 // (see section 2.8 Types and Variables)
@@ -252,29 +237,17 @@
            << " is not a constant integer type.";
   }
 
-  switch (length->opcode()) {
-    case spv::Op::OpSpecConstant:
-    case spv::Op::OpConstant: {
-      auto& type_words = const_result_type->words();
-      const bool is_signed = type_words[3] > 0;
-      const uint32_t width = type_words[2];
-      const int64_t ivalue = ConstantLiteralAsInt64(width, length->words());
-      if (ivalue == 0 || (ivalue < 0 && is_signed)) {
-        return _.diag(SPV_ERROR_INVALID_ID, inst)
-               << "OpTypeArray Length <id> " << _.getIdName(length_id)
-               << " default value must be at least 1: found " << ivalue;
-      }
-    } break;
-    case spv::Op::OpConstantNull:
+  int64_t length_value;
+  if (_.EvalConstantValInt64(length_id, &length_value)) {
+    auto& type_words = const_result_type->words();
+    const bool is_signed = type_words[3] > 0;
+    if (length_value == 0 || (length_value < 0 && is_signed)) {
       return _.diag(SPV_ERROR_INVALID_ID, inst)
              << "OpTypeArray Length <id> " << _.getIdName(length_id)
-             << " default value must be at least 1.";
-    case spv::Op::OpSpecConstantOp:
-      // Assume it's OK, rather than try to evaluate the operation.
-      break;
-    default:
-      assert(0 && "bug in spvOpcodeIsConstant() or result type isn't int");
+             << " default value must be at least 1: found " << length_value;
+    }
   }
+
   return SPV_SUCCESS;
 }
 
@@ -552,8 +525,8 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t ValidateTypeCooperativeMatrixNV(ValidationState_t& _,
-                                             const Instruction* inst) {
+spv_result_t ValidateTypeCooperativeMatrix(ValidationState_t& _,
+                                           const Instruction* inst) {
   const auto component_type_index = 1;
   const auto component_type_id =
       inst->GetOperandAs<uint32_t>(component_type_index);
@@ -561,7 +534,7 @@
   if (!component_type || (spv::Op::OpTypeFloat != component_type->opcode() &&
                           spv::Op::OpTypeInt != component_type->opcode())) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
-           << "OpTypeCooperativeMatrixNV Component Type <id> "
+           << "OpTypeCooperativeMatrix Component Type <id> "
            << _.getIdName(component_type_id)
            << " is not a scalar numerical type.";
   }
@@ -572,7 +545,7 @@
   if (!scope || !_.IsIntScalarType(scope->type_id()) ||
       !spvOpcodeIsConstant(scope->opcode())) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
-           << "OpTypeCooperativeMatrixNV Scope <id> " << _.getIdName(scope_id)
+           << "OpTypeCooperativeMatrix Scope <id> " << _.getIdName(scope_id)
            << " is not a constant instruction with scalar integer type.";
   }
 
@@ -582,7 +555,7 @@
   if (!rows || !_.IsIntScalarType(rows->type_id()) ||
       !spvOpcodeIsConstant(rows->opcode())) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
-           << "OpTypeCooperativeMatrixNV Rows <id> " << _.getIdName(rows_id)
+           << "OpTypeCooperativeMatrix Rows <id> " << _.getIdName(rows_id)
            << " is not a constant instruction with scalar integer type.";
   }
 
@@ -592,10 +565,22 @@
   if (!cols || !_.IsIntScalarType(cols->type_id()) ||
       !spvOpcodeIsConstant(cols->opcode())) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
-           << "OpTypeCooperativeMatrixNV Cols <id> " << _.getIdName(cols_id)
+           << "OpTypeCooperativeMatrix Cols <id> " << _.getIdName(cols_id)
            << " is not a constant instruction with scalar integer type.";
   }
 
+  if (inst->opcode() == spv::Op::OpTypeCooperativeMatrixKHR) {
+    const auto use_index = 5;
+    const auto use_id = inst->GetOperandAs<uint32_t>(use_index);
+    const auto use = _.FindDef(use_id);
+    if (!use || !_.IsIntScalarType(use->type_id()) ||
+        !spvOpcodeIsConstant(use->opcode())) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "OpTypeCooperativeMatrixKHR Use <id> " << _.getIdName(use_id)
+             << " is not a constant instruction with scalar integer type.";
+    }
+  }
+
   return SPV_SUCCESS;
 }
 }  // namespace
@@ -640,7 +625,8 @@
       if (auto error = ValidateTypeForwardPointer(_, inst)) return error;
       break;
     case spv::Op::OpTypeCooperativeMatrixNV:
-      if (auto error = ValidateTypeCooperativeMatrixNV(_, inst)) return error;
+    case spv::Op::OpTypeCooperativeMatrixKHR:
+      if (auto error = ValidateTypeCooperativeMatrix(_, inst)) return error;
       break;
     default:
       break;
diff --git a/third_party/SPIRV-Tools/source/val/validation_state.cpp b/third_party/SPIRV-Tools/source/val/validation_state.cpp
index dbf0ba6..87322d2 100644
--- a/third_party/SPIRV-Tools/source/val/validation_state.cpp
+++ b/third_party/SPIRV-Tools/source/val/validation_state.cpp
@@ -21,6 +21,7 @@
 #include "source/opcode.h"
 #include "source/spirv_constant.h"
 #include "source/spirv_target_env.h"
+#include "source/util/make_unique.h"
 #include "source/val/basic_block.h"
 #include "source/val/construct.h"
 #include "source/val/function.h"
@@ -359,14 +360,16 @@
   // Avoid redundant work.  Otherwise the recursion could induce work
   // quadrdatic in the capability dependency depth. (Ok, not much, but
   // it's something.)
-  if (module_capabilities_.Contains(cap)) return;
+  if (module_capabilities_.contains(cap)) return;
 
-  module_capabilities_.Add(cap);
+  module_capabilities_.insert(cap);
   spv_operand_desc desc;
   if (SPV_SUCCESS == grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
                                             uint32_t(cap), &desc)) {
-    CapabilitySet(desc->numCapabilities, desc->capabilities)
-        .ForEach([this](spv::Capability c) { RegisterCapability(c); });
+    for (auto capability :
+         CapabilitySet(desc->numCapabilities, desc->capabilities)) {
+      RegisterCapability(capability);
+    }
   }
 
   switch (cap) {
@@ -418,9 +421,9 @@
 }
 
 void ValidationState_t::RegisterExtension(Extension ext) {
-  if (module_extensions_.Contains(ext)) return;
+  if (module_extensions_.contains(ext)) return;
 
-  module_extensions_.Add(ext);
+  module_extensions_.insert(ext);
 
   switch (ext) {
     case kSPV_AMD_gpu_shader_half_float:
@@ -608,6 +611,19 @@
   sampled_image_consumers_[sampled_image_id].push_back(consumer);
 }
 
+void ValidationState_t::RegisterQCOMImageProcessingTextureConsumer(
+    uint32_t texture_id, const Instruction* consumer0,
+    const Instruction* consumer1) {
+  if (HasDecoration(texture_id, spv::Decoration::WeightTextureQCOM) ||
+      HasDecoration(texture_id, spv::Decoration::BlockMatchTextureQCOM) ||
+      HasDecoration(texture_id, spv::Decoration::BlockMatchSamplerQCOM)) {
+    qcom_image_processing_consumers_.insert(consumer0->id());
+    if (consumer1) {
+      qcom_image_processing_consumers_.insert(consumer1->id());
+    }
+  }
+}
+
 void ValidationState_t::RegisterStorageClassConsumer(
     spv::StorageClass storage_class, Instruction* consumer) {
   if (spvIsVulkanEnv(context()->target_env)) {
@@ -665,39 +681,39 @@
   if (storage_class == spv::StorageClass::CallableDataKHR) {
     std::string errorVUID = VkErrorID(4704);
     function(consumer->function()->id())
-        ->RegisterExecutionModelLimitation([errorVUID](
-                                               spv::ExecutionModel model,
-                                               std::string* message) {
-          if (model != spv::ExecutionModel::RayGenerationKHR &&
-              model != spv::ExecutionModel::ClosestHitKHR &&
-              model != spv::ExecutionModel::CallableKHR &&
-              model != spv::ExecutionModel::MissKHR) {
-            if (message) {
-              *message = errorVUID +
-                         "CallableDataKHR Storage Class is limited to "
-                         "RayGenerationKHR, ClosestHitKHR, CallableKHR, and "
-                         "MissKHR execution model";
-            }
-            return false;
-          }
-          return true;
-        });
+        ->RegisterExecutionModelLimitation(
+            [errorVUID](spv::ExecutionModel model, std::string* message) {
+              if (model != spv::ExecutionModel::RayGenerationKHR &&
+                  model != spv::ExecutionModel::ClosestHitKHR &&
+                  model != spv::ExecutionModel::CallableKHR &&
+                  model != spv::ExecutionModel::MissKHR) {
+                if (message) {
+                  *message =
+                      errorVUID +
+                      "CallableDataKHR Storage Class is limited to "
+                      "RayGenerationKHR, ClosestHitKHR, CallableKHR, and "
+                      "MissKHR execution model";
+                }
+                return false;
+              }
+              return true;
+            });
   } else if (storage_class == spv::StorageClass::IncomingCallableDataKHR) {
     std::string errorVUID = VkErrorID(4705);
     function(consumer->function()->id())
-        ->RegisterExecutionModelLimitation([errorVUID](
-                                               spv::ExecutionModel model,
-                                               std::string* message) {
-          if (model != spv::ExecutionModel::CallableKHR) {
-            if (message) {
-              *message = errorVUID +
-                         "IncomingCallableDataKHR Storage Class is limited to "
-                         "CallableKHR execution model";
-            }
-            return false;
-          }
-          return true;
-        });
+        ->RegisterExecutionModelLimitation(
+            [errorVUID](spv::ExecutionModel model, std::string* message) {
+              if (model != spv::ExecutionModel::CallableKHR) {
+                if (message) {
+                  *message =
+                      errorVUID +
+                      "IncomingCallableDataKHR Storage Class is limited to "
+                      "CallableKHR execution model";
+                }
+                return false;
+              }
+              return true;
+            });
   } else if (storage_class == spv::StorageClass::RayPayloadKHR) {
     std::string errorVUID = VkErrorID(4698);
     function(consumer->function()->id())
@@ -859,6 +875,7 @@
       return GetComponentType(inst->word(2));
 
     case spv::Op::OpTypeCooperativeMatrixNV:
+    case spv::Op::OpTypeCooperativeMatrixKHR:
       return inst->word(2);
 
     default:
@@ -886,6 +903,7 @@
       return inst->word(3);
 
     case spv::Op::OpTypeCooperativeMatrixNV:
+    case spv::Op::OpTypeCooperativeMatrixKHR:
       // Actual dimension isn't known, return 0
       return 0;
 
@@ -937,6 +955,20 @@
   return false;
 }
 
+bool ValidationState_t::IsFloat16Vector2Or4Type(uint32_t id) const {
+  const Instruction* inst = FindDef(id);
+  assert(inst);
+
+  if (inst->opcode() == spv::Op::OpTypeVector) {
+    uint32_t vectorDim = GetDimension(id);
+    return IsFloatScalarType(GetComponentType(id)) &&
+           (vectorDim == 2 || vectorDim == 4) &&
+           (GetBitWidth(GetComponentType(id)) == 16);
+  }
+
+  return false;
+}
+
 bool ValidationState_t::IsFloatScalarOrVectorType(uint32_t id) const {
   const Instruction* inst = FindDef(id);
   if (!inst) {
@@ -1007,6 +1039,23 @@
   return false;
 }
 
+bool ValidationState_t::IsUnsignedIntScalarOrVectorType(uint32_t id) const {
+  const Instruction* inst = FindDef(id);
+  if (!inst) {
+    return false;
+  }
+
+  if (inst->opcode() == spv::Op::OpTypeInt) {
+    return inst->GetOperandAs<uint32_t>(2) == 0;
+  }
+
+  if (inst->opcode() == spv::Op::OpTypeVector) {
+    return IsUnsignedIntScalarType(GetComponentType(id));
+  }
+
+  return false;
+}
+
 bool ValidationState_t::IsSignedIntScalarType(uint32_t id) const {
   const Instruction* inst = FindDef(id);
   return inst && inst->opcode() == spv::Op::OpTypeInt && inst->word(3) == 1;
@@ -1143,21 +1192,67 @@
 
 bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const {
   const Instruction* inst = FindDef(id);
+  return inst && (inst->opcode() == spv::Op::OpTypeCooperativeMatrixNV ||
+                  inst->opcode() == spv::Op::OpTypeCooperativeMatrixKHR);
+}
+
+bool ValidationState_t::IsCooperativeMatrixNVType(uint32_t id) const {
+  const Instruction* inst = FindDef(id);
   return inst && inst->opcode() == spv::Op::OpTypeCooperativeMatrixNV;
 }
 
+bool ValidationState_t::IsCooperativeMatrixKHRType(uint32_t id) const {
+  const Instruction* inst = FindDef(id);
+  return inst && inst->opcode() == spv::Op::OpTypeCooperativeMatrixKHR;
+}
+
+bool ValidationState_t::IsCooperativeMatrixAType(uint32_t id) const {
+  if (!IsCooperativeMatrixKHRType(id)) return false;
+  const Instruction* inst = FindDef(id);
+  uint64_t matrixUse = 0;
+  if (EvalConstantValUint64(inst->word(6), &matrixUse)) {
+    return matrixUse ==
+           static_cast<uint64_t>(spv::CooperativeMatrixUse::MatrixAKHR);
+  }
+  return false;
+}
+
+bool ValidationState_t::IsCooperativeMatrixBType(uint32_t id) const {
+  if (!IsCooperativeMatrixKHRType(id)) return false;
+  const Instruction* inst = FindDef(id);
+  uint64_t matrixUse = 0;
+  if (EvalConstantValUint64(inst->word(6), &matrixUse)) {
+    return matrixUse ==
+           static_cast<uint64_t>(spv::CooperativeMatrixUse::MatrixBKHR);
+  }
+  return false;
+}
+bool ValidationState_t::IsCooperativeMatrixAccType(uint32_t id) const {
+  if (!IsCooperativeMatrixKHRType(id)) return false;
+  const Instruction* inst = FindDef(id);
+  uint64_t matrixUse = 0;
+  if (EvalConstantValUint64(inst->word(6), &matrixUse)) {
+    return matrixUse == static_cast<uint64_t>(
+                            spv::CooperativeMatrixUse::MatrixAccumulatorKHR);
+  }
+  return false;
+}
+
 bool ValidationState_t::IsFloatCooperativeMatrixType(uint32_t id) const {
-  if (!IsCooperativeMatrixType(id)) return false;
+  if (!IsCooperativeMatrixNVType(id) && !IsCooperativeMatrixKHRType(id))
+    return false;
   return IsFloatScalarType(FindDef(id)->word(2));
 }
 
 bool ValidationState_t::IsIntCooperativeMatrixType(uint32_t id) const {
-  if (!IsCooperativeMatrixType(id)) return false;
+  if (!IsCooperativeMatrixNVType(id) && !IsCooperativeMatrixKHRType(id))
+    return false;
   return IsIntScalarType(FindDef(id)->word(2));
 }
 
 bool ValidationState_t::IsUnsignedIntCooperativeMatrixType(uint32_t id) const {
-  if (!IsCooperativeMatrixType(id)) return false;
+  if (!IsCooperativeMatrixNVType(id) && !IsCooperativeMatrixKHRType(id))
+    return false;
   return IsUnsignedIntScalarType(FindDef(id)->word(2));
 }
 
@@ -1173,8 +1268,7 @@
   const auto m1_type = FindDef(m1);
   const auto m2_type = FindDef(m2);
 
-  if (m1_type->opcode() != spv::Op::OpTypeCooperativeMatrixNV ||
-      m2_type->opcode() != spv::Op::OpTypeCooperativeMatrixNV) {
+  if (m1_type->opcode() != m2_type->opcode()) {
     return diag(SPV_ERROR_INVALID_DATA, inst)
            << "Expected cooperative matrix types";
   }
@@ -1224,6 +1318,21 @@
            << "identical";
   }
 
+  if (m1_type->opcode() == spv::Op::OpTypeCooperativeMatrixKHR) {
+    uint32_t m1_use_id = m1_type->GetOperandAs<uint32_t>(5);
+    uint32_t m2_use_id = m2_type->GetOperandAs<uint32_t>(5);
+    std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
+        EvalInt32IfConst(m1_use_id);
+    std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
+        EvalInt32IfConst(m2_use_id);
+
+    if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
+      return diag(SPV_ERROR_INVALID_DATA, inst)
+             << "Expected Use of Matrix type and Result Type to be "
+             << "identical";
+    }
+  }
+
   return SPV_SUCCESS;
 }
 
@@ -1232,20 +1341,23 @@
   return GetTypeId(inst->GetOperandAs<uint32_t>(operand_index));
 }
 
-bool ValidationState_t::GetConstantValUint64(uint32_t id, uint64_t* val) const {
+bool ValidationState_t::EvalConstantValUint64(uint32_t id,
+                                              uint64_t* val) const {
   const Instruction* inst = FindDef(id);
   if (!inst) {
     assert(0 && "Instruction not found");
     return false;
   }
 
-  if (inst->opcode() != spv::Op::OpConstant &&
-      inst->opcode() != spv::Op::OpSpecConstant)
-    return false;
-
   if (!IsIntScalarType(inst->type_id())) return false;
 
-  if (inst->words().size() == 4) {
+  if (inst->opcode() == spv::Op::OpConstantNull) {
+    *val = 0;
+  } else if (inst->opcode() != spv::Op::OpConstant) {
+    // Spec constant values cannot be evaluated so don't consider constant for
+    // static validation
+    return false;
+  } else if (inst->words().size() == 4) {
     *val = inst->word(3);
   } else {
     assert(inst->words().size() == 5);
@@ -1255,6 +1367,32 @@
   return true;
 }
 
+bool ValidationState_t::EvalConstantValInt64(uint32_t id, int64_t* val) const {
+  const Instruction* inst = FindDef(id);
+  if (!inst) {
+    assert(0 && "Instruction not found");
+    return false;
+  }
+
+  if (!IsIntScalarType(inst->type_id())) return false;
+
+  if (inst->opcode() == spv::Op::OpConstantNull) {
+    *val = 0;
+  } else if (inst->opcode() != spv::Op::OpConstant) {
+    // Spec constant values cannot be evaluated so don't consider constant for
+    // static validation
+    return false;
+  } else if (inst->words().size() == 4) {
+    *val = int32_t(inst->word(3));
+  } else {
+    assert(inst->words().size() == 5);
+    const uint32_t lo_word = inst->word(3);
+    const uint32_t hi_word = inst->word(4);
+    *val = static_cast<int64_t>(uint64_t(lo_word) | uint64_t(hi_word) << 32);
+  }
+  return true;
+}
+
 std::tuple<bool, bool, uint32_t> ValidationState_t::EvalInt32IfConst(
     uint32_t id) const {
   const Instruction* const inst = FindDef(id);
@@ -1489,6 +1627,7 @@
     case spv::Op::OpTypeImage:
     case spv::Op::OpTypeSampledImage:
     case spv::Op::OpTypeCooperativeMatrixNV:
+    case spv::Op::OpTypeCooperativeMatrixKHR:
       return ContainsType(inst->GetOperandAs<uint32_t>(1u), f,
                           traverse_all_types);
     case spv::Op::OpTypePointer:
@@ -2030,6 +2169,8 @@
       return VUID_WRAP(VUID-StandaloneSpirv-None-04644);
     case 4645:
       return VUID_WRAP(VUID-StandaloneSpirv-None-04645);
+    case 4650:
+      return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04650);
     case 4651:
       return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651);
     case 4652:
@@ -2048,8 +2189,6 @@
       return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658);
     case 4659:
       return VUID_WRAP(VUID-StandaloneSpirv-OpImageQuerySizeLod-04659);
-    case 4662:
-      return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662);
     case 4663:
       return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663);
     case 4664:
@@ -2078,14 +2217,20 @@
       return VUID_WRAP(VUID-StandaloneSpirv-RayPayloadKHR-04698);
     case 4699:
       return VUID_WRAP(VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699);
+    case 4700:
+      return VUID_WRAP(VUID-StandaloneSpirv-IncomingRayPayloadKHR-04700);
     case 4701:
       return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04701);
+    case 4702:
+      return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04702);
     case 4703:
       return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04703);
     case 4704:
       return VUID_WRAP(VUID-StandaloneSpirv-CallableDataKHR-04704);
     case 4705:
       return VUID_WRAP(VUID-StandaloneSpirv-IncomingCallableDataKHR-04705);
+    case 4706:
+      return VUID_WRAP(VUID-StandaloneSpirv-IncomingCallableDataKHR-04706);
     case 7119:
       return VUID_WRAP(VUID-StandaloneSpirv-ShaderRecordBufferKHR-07119);
     case 4708:
@@ -2144,6 +2289,8 @@
       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeSampledImage-06671);
     case 6672:
       return VUID_WRAP(VUID-StandaloneSpirv-Location-06672);
+    case 6673:
+      return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-06673);
     case 6674:
       return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-06674);
     case 6675:
@@ -2164,6 +2311,24 @@
       return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06808);
     case 6925:
       return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925);
+    case 7041:
+      return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041);
+    case 7043:
+      return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043);
+    case 7044:
+      return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044);
+    case 7047:
+      return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07047);
+    case 7049:
+      return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049);
+    case 7050:
+      return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050);
+    case 7053:
+      return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07053);
+    case 7055:
+      return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07055);
+    case 7056:
+      return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07056);
     case 7102:
       return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102);
     case 7320:
@@ -2180,6 +2345,14 @@
       return VUID_WRAP(VUID-StandaloneSpirv-Component-07703);
     case 7951:
       return VUID_WRAP(VUID-StandaloneSpirv-SubgroupVoteKHR-07951);
+    case 8721:
+      return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08721);
+    case 8722:
+      return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08722);
+    case 8973:
+      return VUID_WRAP(VUID-StandaloneSpirv-Pointer-08973);
+    case 9638:
+      return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-09638);
     default:
       return "";  // unknown id
   }
diff --git a/third_party/SPIRV-Tools/source/val/validation_state.h b/third_party/SPIRV-Tools/source/val/validation_state.h
index 4d5ac00..27acdcc 100644
--- a/third_party/SPIRV-Tools/source/val/validation_state.h
+++ b/third_party/SPIRV-Tools/source/val/validation_state.h
@@ -317,7 +317,7 @@
 
   /// Returns true if the capability is enabled in the module.
   bool HasCapability(spv::Capability cap) const {
-    return module_capabilities_.Contains(cap);
+    return module_capabilities_.contains(cap);
   }
 
   /// Returns a reference to the set of capabilities in the module.
@@ -328,7 +328,7 @@
 
   /// Returns true if the extension is enabled in the module.
   bool HasExtension(Extension ext) const {
-    return module_extensions_.Contains(ext);
+    return module_extensions_.contains(ext);
   }
 
   /// Returns true if any of the capabilities is enabled, or if |capabilities|
@@ -485,6 +485,13 @@
   void RegisterSampledImageConsumer(uint32_t sampled_image_id,
                                     Instruction* consumer);
 
+  // Record a cons_id as a consumer of texture_id
+  // if texture 'texture_id' has a QCOM image processing decoration
+  // and consumer is a load or a sampled image instruction
+  void RegisterQCOMImageProcessingTextureConsumer(uint32_t texture_id,
+                                                  const Instruction* consumer0,
+                                                  const Instruction* consumer1);
+
   // Record a function's storage class consumer instruction
   void RegisterStorageClassConsumer(spv::StorageClass storage_class,
                                     Instruction* consumer);
@@ -595,6 +602,7 @@
   bool IsVoidType(uint32_t id) const;
   bool IsFloatScalarType(uint32_t id) const;
   bool IsFloatVectorType(uint32_t id) const;
+  bool IsFloat16Vector2Or4Type(uint32_t id) const;
   bool IsFloatScalarOrVectorType(uint32_t id) const;
   bool IsFloatMatrixType(uint32_t id) const;
   bool IsIntScalarType(uint32_t id) const;
@@ -602,6 +610,7 @@
   bool IsIntScalarOrVectorType(uint32_t id) const;
   bool IsUnsignedIntScalarType(uint32_t id) const;
   bool IsUnsignedIntVectorType(uint32_t id) const;
+  bool IsUnsignedIntScalarOrVectorType(uint32_t id) const;
   bool IsSignedIntScalarType(uint32_t id) const;
   bool IsSignedIntVectorType(uint32_t id) const;
   bool IsBoolScalarType(uint32_t id) const;
@@ -610,6 +619,11 @@
   bool IsPointerType(uint32_t id) const;
   bool IsAccelerationStructureType(uint32_t id) const;
   bool IsCooperativeMatrixType(uint32_t id) const;
+  bool IsCooperativeMatrixNVType(uint32_t id) const;
+  bool IsCooperativeMatrixKHRType(uint32_t id) const;
+  bool IsCooperativeMatrixAType(uint32_t id) const;
+  bool IsCooperativeMatrixBType(uint32_t id) const;
+  bool IsCooperativeMatrixAccType(uint32_t id) const;
   bool IsFloatCooperativeMatrixType(uint32_t id) const;
   bool IsIntCooperativeMatrixType(uint32_t id) const;
   bool IsUnsignedIntCooperativeMatrixType(uint32_t id) const;
@@ -634,10 +648,6 @@
                     const std::function<bool(const Instruction*)>& f,
                     bool traverse_all_types = true) const;
 
-  // Gets value from OpConstant and OpSpecConstant as uint64.
-  // Returns false on failure (no instruction, wrong instruction, not int).
-  bool GetConstantValUint64(uint32_t id, uint64_t* val) const;
-
   // Returns type_id if id has type or zero otherwise.
   uint32_t GetTypeId(uint32_t id) const;
 
@@ -712,6 +722,14 @@
     pointer_to_storage_image_.insert(type_id);
   }
 
+  // Tries to evaluate a any scalar integer OpConstant as uint64.
+  // OpConstantNull is defined as zero for scalar int (will return true)
+  // OpSpecConstant* return false since their values cannot be relied upon
+  // during validation.
+  bool EvalConstantValUint64(uint32_t id, uint64_t* val) const;
+  // Same as EvalConstantValUint64 but returns a signed int
+  bool EvalConstantValInt64(uint32_t id, int64_t* val) const;
+
   // Tries to evaluate a 32-bit signed or unsigned scalar integer constant.
   // Returns tuple <is_int32, is_const_int32, value>.
   // OpSpecConstant* return |is_const_int32| as false since their values cannot
@@ -786,6 +804,13 @@
     current_layout_section_ = section;
   }
 
+  // Check if instruction 'id' is a consumer of a texture decorated
+  // with a QCOM image processing decoration
+  bool IsQCOMImageProcessingTextureConsumer(uint32_t id) {
+    return qcom_image_processing_consumers_.find(id) !=
+           qcom_image_processing_consumers_.end();
+  }
+
  private:
   ValidationState_t(const ValidationState_t&);
 
@@ -820,6 +845,10 @@
   std::unordered_map<uint32_t, std::vector<Instruction*>>
       sampled_image_consumers_;
 
+  /// Stores load instructions that load textures used
+  //  in QCOM image processing functions
+  std::unordered_set<uint32_t> qcom_image_processing_consumers_;
+
   /// A map of operand IDs and their names defined by the OpName instruction
   std::unordered_map<uint32_t, std::string> operand_names_;
 
diff --git a/third_party/SPIRV-Tools/source/wasm/build.sh b/third_party/SPIRV-Tools/source/wasm/build.sh
index 4f7b701..69468c9 100755
--- a/third_party/SPIRV-Tools/source/wasm/build.sh
+++ b/third_party/SPIRV-Tools/source/wasm/build.sh
@@ -45,7 +45,7 @@
     emcc \
         --bind \
         -I../../include \
-        -std=c++11 \
+        -std=c++17 \
         ../../source/wasm/spirv-tools.cpp \
         source/libSPIRV-Tools.a \
         -o spirv-tools.js \
diff --git a/third_party/SPIRV-Tools/test/CMakeLists.txt b/third_party/SPIRV-Tools/test/CMakeLists.txt
index 37c5e1d..40c64f8 100644
--- a/third_party/SPIRV-Tools/test/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/test/CMakeLists.txt
@@ -12,22 +12,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+if (${SPIRV_SKIP_TESTS})
+  return()
+endif()
+
+if (TARGET gmock_main)
+  message(STATUS "Found Google Mock, building tests.")
+else()
+  message(STATUS "Did not find googletest, tests will not be built. "
+    "To enable tests place googletest in '<spirv-dir>/external/googletest'.")
+endif()
+
 # Add a SPIR-V Tools unit test. Signature:
 #   add_spvtools_unittest(
 #     TARGET target_name
 #     SRCS   src_file.h src_file.cpp
 #     LIBS   lib1 lib2
 #   )
-
-if (NOT "${SPIRV_SKIP_TESTS}")
-  if (TARGET gmock_main)
-    message(STATUS "Found Google Mock, building tests.")
-  else()
-    message(STATUS "Did not find googletest, tests will not be built. "
-      "To enable tests place googletest in '<spirv-dir>/external/googletest'.")
-  endif()
-endif()
-
 function(add_spvtools_unittest)
   if (NOT "${SPIRV_SKIP_TESTS}" AND TARGET gmock_main)
     set(one_value_args TARGET PCH_FILE)
@@ -111,7 +112,6 @@
   hex_float_test.cpp
   immediate_int_test.cpp
   libspirv_macros_test.cpp
-  log_test.cpp
   named_id_test.cpp
   name_mapper_test.cpp
   opcode_make_test.cpp
diff --git a/third_party/SPIRV-Tools/test/binary_parse_test.cpp b/third_party/SPIRV-Tools/test/binary_parse_test.cpp
index 50710cd..1a868db 100644
--- a/third_party/SPIRV-Tools/test/binary_parse_test.cpp
+++ b/third_party/SPIRV-Tools/test/binary_parse_test.cpp
@@ -1154,7 +1154,10 @@
         {"%2 = OpSpecConstantOp %1 !1000 %2",
          "Invalid OpSpecConstantOp opcode: 1000"},
         {"OpCapability !9999", "Invalid capability operand: 9999"},
-        {"OpSource !9999 100", "Invalid source language operand: 9999"},
+        {"OpSource !9999 100",
+         "Invalid source language operand: 9999, if you are creating a new "
+         "source language please use value 0 (Unknown) and when ready, add "
+         "your source language to SPRIV-Headers"},
         {"OpEntryPoint !9999", "Invalid execution model operand: 9999"},
         {"OpMemoryModel !9999", "Invalid addressing model operand: 9999"},
         {"OpMemoryModel Logical !9999", "Invalid memory model operand: 9999"},
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp
index 9944c2c..bd5a7d5 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp
@@ -95,8 +95,7 @@
   constexpr char kDiff[] = R"( ; SPIR-V
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
--; Bound: 15
-+; Bound: 16
+ ; Bound: 15
  ; Schema: 0
  OpCapability Shader
 -%1 = OpExtInstImport "GLSL.std.450"
@@ -199,8 +198,7 @@
   constexpr char kDiff[] = R"( ; SPIR-V
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
--; Bound: 15
-+; Bound: 16
+ ; Bound: 15
  ; Schema: 0
  OpCapability Shader
 -%1 = OpExtInstImport "GLSL.std.450"
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/basic_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/basic_autogen.cpp
index f3afc70..d4b6846 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/basic_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/basic_autogen.cpp
@@ -129,7 +129,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 27
-+; Bound: 36
++; Bound: 30
  ; Schema: 0
  OpCapability Shader
 +%27 = OpExtInstImport "GLSL.std.450"
@@ -272,7 +272,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 27
-+; Bound: 36
++; Bound: 30
  ; Schema: 0
  OpCapability Shader
 +%27 = OpExtInstImport "GLSL.std.450"
@@ -324,7 +324,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 27
-+; Bound: 36
++; Bound: 30
  ; Schema: 0
  OpCapability Shader
 +%27 = OpExtInstImport "GLSL.std.450"
@@ -384,8 +384,8 @@
    6 ->   14 [TypeInt]
   13 ->   19 [TypePointer]
   14 ->   27 [Variable]
-  15 ->   34 [Constant]
-  16 ->   35 [TypeArray]
+  15 ->   28 [Constant]
+  16 ->   29 [TypeArray]
   17 ->   11 [TypeStruct]
   18 ->   12 [TypePointer]
   19 ->   13 [Variable]
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_autogen.cpp
index 16975ff..2b6d7d8 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_autogen.cpp
@@ -125,7 +125,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 27
-+; Bound: 34
++; Bound: 28
  ; Schema: 0
  OpCapability Shader
  OpMemoryModel Logical GLSL450
@@ -259,7 +259,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 27
-+; Bound: 34
++; Bound: 28
  ; Schema: 0
  OpCapability Shader
  OpMemoryModel Logical GLSL450
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/diff_test_files_autogen.cmake b/third_party/SPIRV-Tools/test/diff/diff_files/diff_test_files_autogen.cmake
index 6440d0b..51cb62f 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/diff_test_files_autogen.cmake
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/diff_test_files_autogen.cmake
@@ -36,6 +36,7 @@
 "diff_files/large_functions_small_diffs_autogen.cpp"
 "diff_files/multiple_different_entry_points_autogen.cpp"
 "diff_files/multiple_same_entry_points_autogen.cpp"
+"diff_files/ray_query_types_autogen.cpp"
 "diff_files/reordered_if_blocks_autogen.cpp"
 "diff_files/reordered_switch_blocks_autogen.cpp"
 "diff_files/small_functions_small_diffs_autogen.cpp"
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_autogen.cpp
index 0d34654..ec9074c 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_autogen.cpp
@@ -977,7 +977,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 82
-+; Bound: 92
++; Bound: 89
  ; Schema: 0
  OpCapability Shader
  OpMemoryModel Logical GLSL450
@@ -1030,8 +1030,7 @@
 +OpDecorate %83 DescriptorSet 0
 +OpDecorate %83 Binding 0
  OpDecorate %32 RelaxedPrecision
--OpDecorate %33 RelaxedPrecision
-+OpDecorate %84 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
  OpDecorate %36 RelaxedPrecision
  OpDecorate %37 RelaxedPrecision
  OpDecorate %38 RelaxedPrecision
@@ -1040,10 +1039,8 @@
  OpDecorate %42 RelaxedPrecision
  OpDecorate %43 RelaxedPrecision
  OpDecorate %48 RelaxedPrecision
--OpDecorate %49 RelaxedPrecision
--OpDecorate %50 RelaxedPrecision
-+OpDecorate %85 RelaxedPrecision
-+OpDecorate %86 RelaxedPrecision
+ OpDecorate %49 RelaxedPrecision
+ OpDecorate %50 RelaxedPrecision
  OpDecorate %52 RelaxedPrecision
  OpDecorate %53 RelaxedPrecision
  OpDecorate %54 RelaxedPrecision
@@ -1082,13 +1079,13 @@
  %61 = OpTypeVoid
  %69 = OpConstant %16 0
  %78 = OpConstant %16 1
-+%88 = OpTypePointer Private %2
++%85 = OpTypePointer Private %2
  %3 = OpTypePointer Input %2
  %7 = OpTypePointer UniformConstant %6
  %10 = OpTypePointer UniformConstant %9
  %13 = OpTypePointer Uniform %12
  %19 = OpTypePointer Uniform %18
-+%89 = OpTypePointer Private %2
++%86 = OpTypePointer Private %2
  %21 = OpTypePointer Output %2
  %28 = OpTypePointer Uniform %27
  %30 = OpTypePointer Function %2
@@ -1106,19 +1103,16 @@
  %22 = OpVariable %21 Output
 -%29 = OpVariable %28 Uniform
 +%83 = OpVariable %28 Uniform
-+%90 = OpConstant %23 0
-+%91 = OpConstant %1 0.5
++%87 = OpConstant %23 0
++%88 = OpConstant %1 0.5
  %32 = OpFunction %2 None %31
--%33 = OpFunctionParameter %30
-+%84 = OpFunctionParameter %30
+ %33 = OpFunctionParameter %30
  %34 = OpLabel
  %36 = OpLoad %6 %8
--%37 = OpLoad %2 %33
-+%37 = OpLoad %2 %84
+ %37 = OpLoad %2 %33
  %38 = OpVectorShuffle %35 %37 %37 0 1
  %39 = OpImageSampleImplicitLod %2 %36 %38
--%41 = OpLoad %2 %33
-+%41 = OpLoad %2 %84
+ %41 = OpLoad %2 %33
  %42 = OpVectorShuffle %35 %41 %41 2 3
  %43 = OpConvertFToS %40 %42
  %44 = OpLoad %9 %11
@@ -1127,16 +1121,12 @@
  OpReturnValue %46
  OpFunctionEnd
  %48 = OpFunction %2 None %47
--%49 = OpFunctionParameter %30
--%50 = OpFunctionParameter %30
-+%85 = OpFunctionParameter %30
-+%86 = OpFunctionParameter %30
+ %49 = OpFunctionParameter %30
+ %50 = OpFunctionParameter %30
  %51 = OpLabel
--%52 = OpLoad %2 %49
-+%52 = OpLoad %2 %85
+ %52 = OpLoad %2 %49
  %53 = OpVectorShuffle %35 %52 %52 0 1
--%54 = OpLoad %2 %50
-+%54 = OpLoad %2 %86
+ %54 = OpLoad %2 %50
  %55 = OpVectorShuffle %35 %54 %54 2 3
  %56 = OpCompositeExtract %1 %53 0
  %57 = OpCompositeExtract %1 %53 1
@@ -1154,9 +1144,9 @@
  OpStore %65 %66
  %67 = OpFunctionCall %2 %32 %65
 -%71 = OpAccessChain %70 %14 %69
-+%87 = OpAccessChain %70 %82 %69
++%84 = OpAccessChain %70 %82 %69
 -%72 = OpLoad %2 %71
-+%72 = OpLoad %2 %87
++%72 = OpLoad %2 %84
  OpStore %68 %72
 -%74 = OpAccessChain %70 %20 %69 %69
 +%74 = OpAccessChain %70 %14 %69 %69
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_autogen.cpp
index f65ee5a..134ebb4 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_autogen.cpp
@@ -777,7 +777,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 58
-+; Bound: 79
++; Bound: 77
  ; Schema: 0
  OpCapability Shader
  OpMemoryModel Logical GLSL450
@@ -817,12 +817,10 @@
 -OpMemberDecorate %23 3 BuiltIn CullDistance
  OpDecorate %23 Block
  OpDecorate %28 RelaxedPrecision
--OpDecorate %29 RelaxedPrecision
-+OpDecorate %59 RelaxedPrecision
+ OpDecorate %29 RelaxedPrecision
  OpDecorate %31 RelaxedPrecision
  OpDecorate %32 RelaxedPrecision
--OpDecorate %33 RelaxedPrecision
-+OpDecorate %60 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
  OpDecorate %35 RelaxedPrecision
  OpDecorate %36 RelaxedPrecision
  OpDecorate %37 RelaxedPrecision
@@ -845,9 +843,9 @@
 +%23 = OpTypeStruct %2
  %38 = OpTypeVoid
  %45 = OpConstant %12 0
-+%65 = OpTypePointer Private %2
++%63 = OpTypePointer Private %2
  %3 = OpTypePointer Input %2
-+%66 = OpTypePointer Private %2
++%64 = OpTypePointer Private %2
  %7 = OpTypePointer Output %2
  %10 = OpTypePointer Uniform %9
  %18 = OpTypePointer Uniform %17
@@ -865,26 +863,21 @@
 -%19 = OpVariable %18 Uniform
 +%19 = OpVariable %10 Uniform
  %20 = OpVariable %7 Output
-+%58 = OpVariable %66 Private
++%58 = OpVariable %64 Private
  %25 = OpVariable %24 Output
-+%67 = OpConstant %13 0
-+%68 = OpConstant %1 0.5
++%65 = OpConstant %13 0
++%66 = OpConstant %1 0.5
  %28 = OpFunction %2 None %27
--%29 = OpFunctionParameter %26
-+%59 = OpFunctionParameter %26
+ %29 = OpFunctionParameter %26
  %30 = OpLabel
--%31 = OpLoad %2 %29
-+%31 = OpLoad %2 %59
+ %31 = OpLoad %2 %29
  OpReturnValue %31
  OpFunctionEnd
  %32 = OpFunction %2 None %27
--%33 = OpFunctionParameter %26
-+%60 = OpFunctionParameter %26
+ %33 = OpFunctionParameter %26
  %34 = OpLabel
--%35 = OpLoad %2 %33
-+%35 = OpLoad %2 %60
--%36 = OpLoad %2 %33
-+%36 = OpLoad %2 %60
+ %35 = OpLoad %2 %33
+ %36 = OpLoad %2 %33
  %37 = OpFAdd %2 %35 %36
  OpReturnValue %37
  OpFunctionEnd
@@ -894,41 +887,41 @@
  %50 = OpVariable %26 Function
  %53 = OpVariable %26 Function
 -%43 = OpLoad %2 %4
-+%61 = OpLoad %2 %5
++%59 = OpLoad %2 %5
 -OpStore %42 %43
-+OpStore %42 %61
++OpStore %42 %59
  %44 = OpFunctionCall %2 %28 %42
 -%47 = OpAccessChain %46 %11 %45
-+%62 = OpAccessChain %46 %19 %45
++%60 = OpAccessChain %46 %19 %45
 -%48 = OpLoad %2 %47
-+%48 = OpLoad %2 %62
++%48 = OpLoad %2 %60
  %49 = OpFAdd %2 %44 %48
 -OpStore %8 %49
 +OpStore %20 %49
 -%51 = OpLoad %2 %5
-+%63 = OpLoad %2 %6
++%61 = OpLoad %2 %6
 -OpStore %50 %51
-+OpStore %50 %63
++OpStore %50 %61
  %52 = OpFunctionCall %2 %32 %50
 -%54 = OpLoad %2 %6
-+%64 = OpLoad %2 %4
++%62 = OpLoad %2 %4
 -OpStore %53 %54
-+OpStore %53 %64
++OpStore %53 %62
  %55 = OpFunctionCall %2 %28 %53
  %56 = OpFAdd %2 %52 %55
  %57 = OpAccessChain %7 %25 %45
  OpStore %57 %56
-+%69 = OpAccessChain %7 %25 %67
-+%70 = OpLoad %2 %69
-+%71 = OpCompositeExtract %1 %70 0
-+%72 = OpCompositeExtract %1 %70 1
-+%73 = OpCompositeExtract %1 %70 2
-+%74 = OpCompositeExtract %1 %70 3
-+%76 = OpFNegate %1 %71
-+%77 = OpFAdd %1 %73 %74
-+%78 = OpFMul %1 %77 %68
-+%75 = OpCompositeConstruct %2 %72 %76 %78 %74
-+OpStore %69 %75
++%67 = OpAccessChain %7 %25 %65
++%68 = OpLoad %2 %67
++%69 = OpCompositeExtract %1 %68 0
++%70 = OpCompositeExtract %1 %68 1
++%71 = OpCompositeExtract %1 %68 2
++%72 = OpCompositeExtract %1 %68 3
++%74 = OpFNegate %1 %69
++%75 = OpFAdd %1 %71 %72
++%76 = OpFMul %1 %75 %66
++%73 = OpCompositeConstruct %2 %70 %74 %76 %72
++OpStore %67 %73
  OpReturn
  OpFunctionEnd
 )";
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/different_function_parameter_count_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/different_function_parameter_count_autogen.cpp
index 3a077fb..e31a4a8 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/different_function_parameter_count_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/different_function_parameter_count_autogen.cpp
@@ -128,7 +128,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 25
-+; Bound: 33
++; Bound: 31
  ; Schema: 0
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
@@ -143,7 +143,7 @@
 +OpName %26 "v2"
  OpName %20 "o"
  OpName %23 "param"
-+OpName %31 "param"
++OpName %29 "param"
  OpDecorate %20 RelaxedPrecision
  OpDecorate %20 Location 0
  %2 = OpTypeVoid
@@ -162,13 +162,13 @@
  %4 = OpFunction %2 None %3
  %5 = OpLabel
  %23 = OpVariable %8 Function
-+%31 = OpVariable %8 Function
++%29 = OpVariable %8 Function
  OpStore %23 %22
 -%24 = OpFunctionCall %7 %11 %23
-+OpStore %31 %15
-+%32 = OpFunctionCall %7 %11 %23 %31
++OpStore %29 %15
++%30 = OpFunctionCall %7 %11 %23 %29
 -OpStore %20 %24
-+OpStore %20 %32
++OpStore %20 %30
  OpReturn
  OpFunctionEnd
 -%11 = OpFunction %7 None %9
@@ -280,7 +280,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 25
-+; Bound: 34
++; Bound: 31
  ; Schema: 0
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
@@ -306,28 +306,26 @@
  %4 = OpFunction %2 None %3
  %5 = OpLabel
  %23 = OpVariable %8 Function
-+%32 = OpVariable %8 Function
++%29 = OpVariable %8 Function
  OpStore %23 %22
 -%24 = OpFunctionCall %7 %11 %23
-+OpStore %32 %15
-+%33 = OpFunctionCall %7 %11 %23 %32
++OpStore %29 %15
++%30 = OpFunctionCall %7 %11 %23 %29
 -OpStore %20 %24
-+OpStore %20 %33
++OpStore %20 %30
  OpReturn
  OpFunctionEnd
 -%11 = OpFunction %7 None %9
 +%11 = OpFunction %7 None %25
--%10 = OpFunctionParameter %8
+ %10 = OpFunctionParameter %8
 +%26 = OpFunctionParameter %8
-+%27 = OpFunctionParameter %8
  %12 = OpLabel
--%13 = OpLoad %7 %10
-+%13 = OpLoad %7 %26
+ %13 = OpLoad %7 %10
 -%16 = OpFAdd %7 %13 %15
-+%28 = OpLoad %7 %27
-+%29 = OpFAdd %7 %13 %28
++%27 = OpLoad %7 %26
++%28 = OpFAdd %7 %13 %27
 -OpReturnValue %16
-+OpReturnValue %29
++OpReturnValue %28
  OpFunctionEnd
 )";
   Options options;
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_autogen.cpp
index 4f91319..fee34ae 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_autogen.cpp
@@ -303,7 +303,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 69
-+; Bound: 81
++; Bound: 77
  ; Schema: 0
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
@@ -352,10 +352,10 @@
  OpDecorate %54 RelaxedPrecision
  OpDecorate %55 RelaxedPrecision
  OpDecorate %56 RelaxedPrecision
-+OpDecorate %72 RelaxedPrecision
++OpDecorate %70 RelaxedPrecision
  OpDecorate %57 RelaxedPrecision
-+OpDecorate %77 RelaxedPrecision
-+OpDecorate %78 RelaxedPrecision
++OpDecorate %75 RelaxedPrecision
++OpDecorate %76 RelaxedPrecision
  OpDecorate %58 RelaxedPrecision
  OpDecorate %63 RelaxedPrecision
  OpDecorate %63 Location 0
@@ -383,7 +383,7 @@
  %32 = OpConstant %19 1
  %49 = OpConstant %6 10
  %52 = OpConstant %6 0.5
-+%76 = OpConstant %6 0.100000001
++%74 = OpConstant %6 0.100000001
  %53 = OpConstant %6 0.699999988
  %61 = OpTypeVector %6 4
  %62 = OpTypePointer Output %61
@@ -439,20 +439,20 @@
  %55 = OpLoad %6 %45
  %56 = OpFMul %6 %55 %54
  OpStore %45 %56
-+%71 = OpAccessChain %21 %18 %32
-+%72 = OpLoad %15 %71
-+%73 = OpINotEqual %25 %72 %24
-+OpSelectionMerge %75 None
-+OpBranchConditional %73 %74 %75
-+%74 = OpLabel
++%69 = OpAccessChain %21 %18 %32
++%70 = OpLoad %15 %69
++%71 = OpINotEqual %25 %70 %24
++OpSelectionMerge %73 None
++OpBranchConditional %71 %72 %73
++%72 = OpLabel
  %57 = OpLoad %6 %45
-+%77 = OpFSub %6 %57 %76
-+OpStore %45 %77
-+OpBranch %75
-+%75 = OpLabel
-+%78 = OpLoad %6 %45
++%75 = OpFSub %6 %57 %74
++OpStore %45 %75
++OpBranch %73
++%73 = OpLabel
++%76 = OpLoad %6 %45
 -%58 = OpExtInst %6 %1 Exp %57
-+%58 = OpExtInst %6 %1 Exp %78
++%58 = OpExtInst %6 %1 Exp %76
  OpReturnValue %58
  OpFunctionEnd
 )";
@@ -716,7 +716,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 69
-+; Bound: 81
++; Bound: 77
  ; Schema: 0
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
@@ -754,10 +754,10 @@
  OpDecorate %54 RelaxedPrecision
  OpDecorate %55 RelaxedPrecision
  OpDecorate %56 RelaxedPrecision
-+OpDecorate %72 RelaxedPrecision
++OpDecorate %70 RelaxedPrecision
  OpDecorate %57 RelaxedPrecision
-+OpDecorate %77 RelaxedPrecision
-+OpDecorate %78 RelaxedPrecision
++OpDecorate %75 RelaxedPrecision
++OpDecorate %76 RelaxedPrecision
  OpDecorate %58 RelaxedPrecision
  OpDecorate %63 RelaxedPrecision
  OpDecorate %63 Location 0
@@ -785,7 +785,7 @@
  %32 = OpConstant %19 1
  %49 = OpConstant %6 10
  %52 = OpConstant %6 0.5
-+%76 = OpConstant %6 0.100000001
++%74 = OpConstant %6 0.100000001
  %53 = OpConstant %6 0.699999988
  %61 = OpTypeVector %6 4
  %62 = OpTypePointer Output %61
@@ -841,20 +841,20 @@
  %55 = OpLoad %6 %45
  %56 = OpFMul %6 %55 %54
  OpStore %45 %56
-+%71 = OpAccessChain %21 %18 %32
-+%72 = OpLoad %15 %71
-+%73 = OpINotEqual %25 %72 %24
-+OpSelectionMerge %75 None
-+OpBranchConditional %73 %74 %75
-+%74 = OpLabel
++%69 = OpAccessChain %21 %18 %32
++%70 = OpLoad %15 %69
++%71 = OpINotEqual %25 %70 %24
++OpSelectionMerge %73 None
++OpBranchConditional %71 %72 %73
++%72 = OpLabel
  %57 = OpLoad %6 %45
-+%77 = OpFSub %6 %57 %76
-+OpStore %45 %77
-+OpBranch %75
-+%75 = OpLabel
-+%78 = OpLoad %6 %45
++%75 = OpFSub %6 %57 %74
++OpStore %45 %75
++OpBranch %73
++%73 = OpLabel
++%76 = OpLoad %6 %45
 -%58 = OpExtInst %6 %1 Exp %57
-+%58 = OpExtInst %6 %1 Exp %78
++%58 = OpExtInst %6 %1 Exp %76
  OpReturnValue %58
  OpFunctionEnd
 )";
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_autogen.cpp
index 187722e..11bb811 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_autogen.cpp
@@ -371,10 +371,10 @@
    3 ->   16 [TypePointer]
    4 ->   17 [Variable]
    5 ->    8 [TypeInt]
-   8 ->   23 [TypeVector]
+   8 ->   21 [TypeVector]
   13 ->   19 [TypePointer]
-  15 ->   29 [Constant]
-  16 ->   30 [TypeArray]
+  15 ->   22 [Constant]
+  16 ->   23 [TypeArray]
   17 ->   11 [TypeStruct]
   18 ->   12 [TypePointer]
   19 ->   13 [Variable]
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_autogen.cpp
index 9d01166..00bee6b 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_autogen.cpp
@@ -125,9 +125,8 @@
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
  OpMemoryModel Logical GLSL450
-+OpEntryPoint Vertex %12 "main2" %13 %14 %15
  OpEntryPoint Vertex %4 "main1" %8 %10
--OpEntryPoint Vertex %12 "main2" %13 %14 %15
+ OpEntryPoint Vertex %12 "main2" %13 %14 %15
  OpSource ESSL 310
  OpName %4 "main1"
  OpName %12 "main2"
@@ -257,9 +256,8 @@
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
  OpMemoryModel Logical GLSL450
-+OpEntryPoint Vertex %12 "main2" %13 %14 %15
  OpEntryPoint Vertex %4 "main1" %8 %10
--OpEntryPoint Vertex %12 "main2" %13 %14 %15
+ OpEntryPoint Vertex %12 "main2" %13 %14 %15
  OpSource ESSL 310
  OpDecorate %8 Location 0
  OpDecorate %10 Location 0
@@ -304,9 +302,8 @@
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
  OpMemoryModel Logical GLSL450
-+OpEntryPoint Vertex %12 "main2" %13 %14 %15
  OpEntryPoint Vertex %4 "main1" %8 %10
--OpEntryPoint Vertex %12 "main2" %13 %14 %15
+ OpEntryPoint Vertex %12 "main2" %13 %14 %15
  OpSource ESSL 310
  OpName %4 "main1"
  OpName %12 "main2"
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/ray_query_types_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/ray_query_types_autogen.cpp
new file mode 100644
index 0000000..5507def
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/ray_query_types_autogen.cpp
@@ -0,0 +1,148 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// Copyright (c) 2022 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test that OpTypeAccelerationStructureNV and OpTypeRayQueryKHR are
+// matched.
+constexpr char kSrc[] = R"(OpCapability RayQueryKHR
+OpCapability Shader
+OpExtension "SPV_KHR_ray_query"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %43 "main"
+OpExecutionMode %43 LocalSize 1 1 1
+%2 = OpTypeVoid
+%3 = OpTypeAccelerationStructureNV
+%13 = OpTypeRayQueryKHR
+%44 = OpTypeFunction %2
+%43 = OpFunction  %2  None %44
+%42 = OpLabel
+OpReturn
+OpFunctionEnd)";
+constexpr char kDst[] = R"(; SPIR-V
+; Version: 1.4
+; Generator: rspirv
+; Bound: 95
+OpCapability RayQueryKHR
+OpCapability Shader
+OpExtension "SPV_KHR_ray_query"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %43 "main"
+OpExecutionMode %43 LocalSize 1 1 1
+%2 = OpTypeVoid
+%3 = OpTypeAccelerationStructureNV
+%13 = OpTypeRayQueryKHR
+%44 = OpTypeFunction %2
+%43 = OpFunction  %2  None %44
+%42 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+TEST(DiffTest, RayQueryTypes) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 45
+ ; Schema: 0
+ OpCapability RayQueryKHR
+ OpCapability Shader
+ OpExtension "SPV_KHR_ray_query"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %43 "main"
+ OpExecutionMode %43 LocalSize 1 1 1
+ %2 = OpTypeVoid
+ %3 = OpTypeAccelerationStructureKHR
+ %13 = OpTypeRayQueryKHR
+ %44 = OpTypeFunction %2
+ %43 = OpFunction %2 None %44
+ %42 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, RayQueryTypesNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(OpCapability RayQueryKHR
+OpCapability Shader
+OpExtension "SPV_KHR_ray_query"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %43 "main"
+OpExecutionMode %43 LocalSize 1 1 1
+%2 = OpTypeVoid
+%3 = OpTypeAccelerationStructureNV
+%13 = OpTypeRayQueryKHR
+%44 = OpTypeFunction %2
+%43 = OpFunction  %2  None %44
+%42 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(; SPIR-V
+; Version: 1.4
+; Generator: rspirv
+; Bound: 95
+OpCapability RayQueryKHR
+OpCapability Shader
+OpExtension "SPV_KHR_ray_query"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %43 "main"
+OpExecutionMode %43 LocalSize 1 1 1
+%2 = OpTypeVoid
+%3 = OpTypeAccelerationStructureNV
+%13 = OpTypeRayQueryKHR
+%44 = OpTypeFunction %2
+%43 = OpFunction  %2  None %44
+%42 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 45
+ ; Schema: 0
+ OpCapability RayQueryKHR
+ OpCapability Shader
+ OpExtension "SPV_KHR_ray_query"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %43 "main"
+ OpExecutionMode %43 LocalSize 1 1 1
+ %2 = OpTypeVoid
+ %3 = OpTypeAccelerationStructureKHR
+ %13 = OpTypeRayQueryKHR
+ %44 = OpTypeFunction %2
+ %43 = OpFunction %2 None %44
+ %42 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/ray_query_types_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/ray_query_types_dst.spvasm
new file mode 100644
index 0000000..5f8be53
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/ray_query_types_dst.spvasm
@@ -0,0 +1,18 @@
+; SPIR-V
+; Version: 1.4
+; Generator: rspirv
+; Bound: 95
+OpCapability RayQueryKHR
+OpCapability Shader
+OpExtension "SPV_KHR_ray_query"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %43 "main"
+OpExecutionMode %43 LocalSize 1 1 1
+%2 = OpTypeVoid
+%3 = OpTypeAccelerationStructureNV
+%13 = OpTypeRayQueryKHR
+%44 = OpTypeFunction %2
+%43 = OpFunction  %2  None %44
+%42 = OpLabel
+OpReturn
+OpFunctionEnd
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/ray_query_types_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/ray_query_types_src.spvasm
new file mode 100644
index 0000000..0b64015
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/ray_query_types_src.spvasm
@@ -0,0 +1,16 @@
+;; Test that OpTypeAccelerationStructureNV and OpTypeRayQueryKHR are
+;; matched.
+OpCapability RayQueryKHR
+OpCapability Shader
+OpExtension "SPV_KHR_ray_query"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %43 "main"
+OpExecutionMode %43 LocalSize 1 1 1
+%2 = OpTypeVoid
+%3 = OpTypeAccelerationStructureNV
+%13 = OpTypeRayQueryKHR
+%44 = OpTypeFunction %2
+%43 = OpFunction  %2  None %44
+%42 = OpLabel
+OpReturn
+OpFunctionEnd
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_autogen.cpp
index 0788199..3abaf40 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_autogen.cpp
@@ -203,8 +203,7 @@
   constexpr char kDiff[] = R"( ; SPIR-V
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
--; Bound: 46
-+; Bound: 47
+ ; Bound: 46
  ; Schema: 0
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
@@ -471,8 +470,7 @@
   constexpr char kDiff[] = R"( ; SPIR-V
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
--; Bound: 46
-+; Bound: 47
+ ; Bound: 46
  ; Schema: 0
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_autogen.cpp
index c0ba48d..ade5350 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_autogen.cpp
@@ -212,8 +212,7 @@
   constexpr char kDiff[] = R"( ; SPIR-V
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
--; Bound: 58
-+; Bound: 62
+ ; Bound: 58
  ; Schema: 0
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
@@ -485,8 +484,7 @@
   constexpr char kDiff[] = R"( ; SPIR-V
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
--; Bound: 58
-+; Bound: 62
+ ; Bound: 58
  ; Schema: 0
  OpCapability Shader
  %1 = OpExtInstImport "GLSL.std.450"
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_autogen.cpp
index 1962d27..98ad072 100644
--- a/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_autogen.cpp
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_autogen.cpp
@@ -125,7 +125,7 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 27
-+; Bound: 36
++; Bound: 29
  ; Schema: 0
  OpCapability Shader
  OpMemoryModel Logical GLSL450
@@ -140,7 +140,7 @@
  OpName %19 ""
  OpName %22 "main"
  OpDecorate %4 Location 0
-+OpDecorate %34 SpecId 4
++OpDecorate %27 SpecId 4
  OpMemberDecorate %17 1 RelaxedPrecision
  OpMemberDecorate %17 0 BuiltIn Position
  OpMemberDecorate %17 1 BuiltIn PointSize
@@ -153,10 +153,10 @@
  %8 = OpTypeVector %5 4
 -%15 = OpConstant %5 8
 -%16 = OpTypeArray %1 %15
-+%34 = OpSpecConstant %5 8
-+%35 = OpTypeArray %1 %34
++%27 = OpSpecConstant %5 8
++%28 = OpTypeArray %1 %27
 -%17 = OpTypeStruct %2 %1 %16 %16
-+%17 = OpTypeStruct %2 %1 %35 %35
++%17 = OpTypeStruct %2 %1 %28 %28
  %20 = OpTypeVoid
  %25 = OpConstant %5 0
  %3 = OpTypePointer Input %2
@@ -261,14 +261,14 @@
  ; Version: 1.6
  ; Generator: Khronos SPIR-V Tools Assembler; 0
 -; Bound: 27
-+; Bound: 36
++; Bound: 29
  ; Schema: 0
  OpCapability Shader
  OpMemoryModel Logical GLSL450
  OpEntryPoint Vertex %22 "main" %4 %19
  OpSource GLSL 450
  OpDecorate %4 Location 0
-+OpDecorate %34 SpecId 4
++OpDecorate %27 SpecId 4
  OpMemberDecorate %17 1 RelaxedPrecision
  OpMemberDecorate %17 0 BuiltIn Position
  OpMemberDecorate %17 1 BuiltIn PointSize
@@ -281,10 +281,10 @@
  %8 = OpTypeVector %5 4
 -%15 = OpConstant %5 8
 -%16 = OpTypeArray %1 %15
-+%34 = OpSpecConstant %5 8
-+%35 = OpTypeArray %1 %34
++%27 = OpSpecConstant %5 8
++%28 = OpTypeArray %1 %27
 -%17 = OpTypeStruct %2 %1 %16 %16
-+%17 = OpTypeStruct %2 %1 %35 %35
++%17 = OpTypeStruct %2 %1 %28 %28
  %20 = OpTypeVoid
  %25 = OpConstant %5 0
  %3 = OpTypePointer Input %2
diff --git a/third_party/SPIRV-Tools/test/enum_set_test.cpp b/third_party/SPIRV-Tools/test/enum_set_test.cpp
index 1f72715..11105f9 100644
--- a/third_party/SPIRV-Tools/test/enum_set_test.cpp
+++ b/third_party/SPIRV-Tools/test/enum_set_test.cpp
@@ -12,12 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "source/enum_set.h"
+
 #include <algorithm>
+#include <array>
+#include <random>
 #include <utility>
 #include <vector>
 
 #include "gmock/gmock.h"
-#include "source/enum_set.h"
 #include "test/unit_spirv.h"
 
 namespace spvtools {
@@ -25,208 +28,800 @@
 
 using spvtest::ElementsIn;
 using ::testing::Eq;
+using ::testing::Values;
 using ::testing::ValuesIn;
 
+enum class TestEnum : uint32_t {
+  ZERO = 0,
+  ONE = 1,
+  TWO = 2,
+  THREE = 3,
+  FOUR = 4,
+  FIVE = 5,
+  EIGHT = 8,
+  TWENTY = 20,
+  TWENTY_FOUR = 24,
+  THIRTY = 30,
+  ONE_HUNDRED = 100,
+  ONE_HUNDRED_FIFTY = 150,
+  TWO_HUNDRED = 200,
+  THREE_HUNDRED = 300,
+  FOUR_HUNDRED = 400,
+  FIVE_HUNDRED = 500,
+  SIX_HUNDRED = 600,
+};
+
+constexpr std::array kCapabilities{
+    spv::Capability::Matrix,
+    spv::Capability::Shader,
+    spv::Capability::Geometry,
+    spv::Capability::Tessellation,
+    spv::Capability::Addresses,
+    spv::Capability::Linkage,
+    spv::Capability::Kernel,
+    spv::Capability::Vector16,
+    spv::Capability::Float16Buffer,
+    spv::Capability::Float16,
+    spv::Capability::Float64,
+    spv::Capability::Int64,
+    spv::Capability::Int64Atomics,
+    spv::Capability::ImageBasic,
+    spv::Capability::ImageReadWrite,
+    spv::Capability::ImageMipmap,
+    spv::Capability::Pipes,
+    spv::Capability::Groups,
+    spv::Capability::DeviceEnqueue,
+    spv::Capability::LiteralSampler,
+    spv::Capability::AtomicStorage,
+    spv::Capability::Int16,
+    spv::Capability::TessellationPointSize,
+    spv::Capability::GeometryPointSize,
+    spv::Capability::ImageGatherExtended,
+    spv::Capability::StorageImageMultisample,
+    spv::Capability::UniformBufferArrayDynamicIndexing,
+    spv::Capability::SampledImageArrayDynamicIndexing,
+    spv::Capability::StorageBufferArrayDynamicIndexing,
+    spv::Capability::StorageImageArrayDynamicIndexing,
+    spv::Capability::ClipDistance,
+    spv::Capability::CullDistance,
+    spv::Capability::ImageCubeArray,
+    spv::Capability::SampleRateShading,
+    spv::Capability::ImageRect,
+    spv::Capability::SampledRect,
+    spv::Capability::GenericPointer,
+    spv::Capability::Int8,
+    spv::Capability::InputAttachment,
+    spv::Capability::SparseResidency,
+    spv::Capability::MinLod,
+    spv::Capability::Sampled1D,
+    spv::Capability::Image1D,
+    spv::Capability::SampledCubeArray,
+    spv::Capability::SampledBuffer,
+    spv::Capability::ImageBuffer,
+    spv::Capability::ImageMSArray,
+    spv::Capability::StorageImageExtendedFormats,
+    spv::Capability::ImageQuery,
+    spv::Capability::DerivativeControl,
+    spv::Capability::InterpolationFunction,
+    spv::Capability::TransformFeedback,
+    spv::Capability::GeometryStreams,
+    spv::Capability::StorageImageReadWithoutFormat,
+    spv::Capability::StorageImageWriteWithoutFormat,
+    spv::Capability::MultiViewport,
+    spv::Capability::SubgroupDispatch,
+    spv::Capability::NamedBarrier,
+    spv::Capability::PipeStorage,
+    spv::Capability::GroupNonUniform,
+    spv::Capability::GroupNonUniformVote,
+    spv::Capability::GroupNonUniformArithmetic,
+    spv::Capability::GroupNonUniformBallot,
+    spv::Capability::GroupNonUniformShuffle,
+    spv::Capability::GroupNonUniformShuffleRelative,
+    spv::Capability::GroupNonUniformClustered,
+    spv::Capability::GroupNonUniformQuad,
+    spv::Capability::ShaderLayer,
+    spv::Capability::ShaderViewportIndex,
+    spv::Capability::UniformDecoration,
+    spv::Capability::CoreBuiltinsARM,
+    spv::Capability::FragmentShadingRateKHR,
+    spv::Capability::SubgroupBallotKHR,
+    spv::Capability::DrawParameters,
+    spv::Capability::WorkgroupMemoryExplicitLayoutKHR,
+    spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR,
+    spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR,
+    spv::Capability::SubgroupVoteKHR,
+    spv::Capability::StorageBuffer16BitAccess,
+    spv::Capability::StorageUniformBufferBlock16,
+    spv::Capability::StorageUniform16,
+    spv::Capability::UniformAndStorageBuffer16BitAccess,
+    spv::Capability::StoragePushConstant16,
+    spv::Capability::StorageInputOutput16,
+    spv::Capability::DeviceGroup,
+    spv::Capability::MultiView,
+    spv::Capability::VariablePointersStorageBuffer,
+    spv::Capability::VariablePointers,
+    spv::Capability::AtomicStorageOps,
+    spv::Capability::SampleMaskPostDepthCoverage,
+    spv::Capability::StorageBuffer8BitAccess,
+    spv::Capability::UniformAndStorageBuffer8BitAccess,
+    spv::Capability::StoragePushConstant8,
+    spv::Capability::DenormPreserve,
+    spv::Capability::DenormFlushToZero,
+    spv::Capability::SignedZeroInfNanPreserve,
+    spv::Capability::RoundingModeRTE,
+    spv::Capability::RoundingModeRTZ,
+    spv::Capability::RayQueryProvisionalKHR,
+    spv::Capability::RayQueryKHR,
+    spv::Capability::RayTraversalPrimitiveCullingKHR,
+    spv::Capability::RayTracingKHR,
+    spv::Capability::Float16ImageAMD,
+    spv::Capability::ImageGatherBiasLodAMD,
+    spv::Capability::FragmentMaskAMD,
+    spv::Capability::StencilExportEXT,
+    spv::Capability::ImageReadWriteLodAMD,
+    spv::Capability::Int64ImageEXT,
+    spv::Capability::ShaderClockKHR,
+    spv::Capability::SampleMaskOverrideCoverageNV,
+    spv::Capability::GeometryShaderPassthroughNV,
+    spv::Capability::ShaderViewportIndexLayerEXT,
+    spv::Capability::ShaderViewportIndexLayerNV,
+    spv::Capability::ShaderViewportMaskNV,
+    spv::Capability::ShaderStereoViewNV,
+    spv::Capability::PerViewAttributesNV,
+    spv::Capability::FragmentFullyCoveredEXT,
+    spv::Capability::MeshShadingNV,
+    spv::Capability::ImageFootprintNV,
+    spv::Capability::MeshShadingEXT,
+    spv::Capability::FragmentBarycentricKHR,
+    spv::Capability::FragmentBarycentricNV,
+    spv::Capability::ComputeDerivativeGroupQuadsNV,
+    spv::Capability::FragmentDensityEXT,
+    spv::Capability::ShadingRateNV,
+    spv::Capability::GroupNonUniformPartitionedNV,
+    spv::Capability::ShaderNonUniform,
+    spv::Capability::ShaderNonUniformEXT,
+    spv::Capability::RuntimeDescriptorArray,
+    spv::Capability::RuntimeDescriptorArrayEXT,
+    spv::Capability::InputAttachmentArrayDynamicIndexing,
+    spv::Capability::InputAttachmentArrayDynamicIndexingEXT,
+    spv::Capability::UniformTexelBufferArrayDynamicIndexing,
+    spv::Capability::UniformTexelBufferArrayDynamicIndexingEXT,
+    spv::Capability::StorageTexelBufferArrayDynamicIndexing,
+    spv::Capability::StorageTexelBufferArrayDynamicIndexingEXT,
+    spv::Capability::UniformBufferArrayNonUniformIndexing,
+    spv::Capability::UniformBufferArrayNonUniformIndexingEXT,
+    spv::Capability::SampledImageArrayNonUniformIndexing,
+    spv::Capability::SampledImageArrayNonUniformIndexingEXT,
+    spv::Capability::StorageBufferArrayNonUniformIndexing,
+    spv::Capability::StorageBufferArrayNonUniformIndexingEXT,
+    spv::Capability::StorageImageArrayNonUniformIndexing,
+    spv::Capability::StorageImageArrayNonUniformIndexingEXT,
+    spv::Capability::InputAttachmentArrayNonUniformIndexing,
+    spv::Capability::InputAttachmentArrayNonUniformIndexingEXT,
+    spv::Capability::UniformTexelBufferArrayNonUniformIndexing,
+    spv::Capability::UniformTexelBufferArrayNonUniformIndexingEXT,
+    spv::Capability::StorageTexelBufferArrayNonUniformIndexing,
+    spv::Capability::StorageTexelBufferArrayNonUniformIndexingEXT,
+    spv::Capability::RayTracingNV,
+    spv::Capability::RayTracingMotionBlurNV,
+    spv::Capability::VulkanMemoryModel,
+    spv::Capability::VulkanMemoryModelKHR,
+    spv::Capability::VulkanMemoryModelDeviceScope,
+    spv::Capability::VulkanMemoryModelDeviceScopeKHR,
+    spv::Capability::PhysicalStorageBufferAddresses,
+    spv::Capability::PhysicalStorageBufferAddressesEXT,
+    spv::Capability::ComputeDerivativeGroupLinearNV,
+    spv::Capability::RayTracingProvisionalKHR,
+    spv::Capability::CooperativeMatrixNV,
+    spv::Capability::FragmentShaderSampleInterlockEXT,
+    spv::Capability::FragmentShaderShadingRateInterlockEXT,
+    spv::Capability::ShaderSMBuiltinsNV,
+    spv::Capability::FragmentShaderPixelInterlockEXT,
+    spv::Capability::DemoteToHelperInvocation,
+    spv::Capability::DemoteToHelperInvocationEXT,
+    spv::Capability::RayTracingOpacityMicromapEXT,
+    spv::Capability::ShaderInvocationReorderNV,
+    spv::Capability::BindlessTextureNV,
+    spv::Capability::SubgroupShuffleINTEL,
+    spv::Capability::SubgroupBufferBlockIOINTEL,
+    spv::Capability::SubgroupImageBlockIOINTEL,
+    spv::Capability::SubgroupImageMediaBlockIOINTEL,
+    spv::Capability::RoundToInfinityINTEL,
+    spv::Capability::FloatingPointModeINTEL,
+    spv::Capability::IntegerFunctions2INTEL,
+    spv::Capability::FunctionPointersINTEL,
+    spv::Capability::IndirectReferencesINTEL,
+    spv::Capability::AsmINTEL,
+    spv::Capability::AtomicFloat32MinMaxEXT,
+    spv::Capability::AtomicFloat64MinMaxEXT,
+    spv::Capability::AtomicFloat16MinMaxEXT,
+    spv::Capability::VectorComputeINTEL,
+    spv::Capability::VectorAnyINTEL,
+    spv::Capability::ExpectAssumeKHR,
+    spv::Capability::SubgroupAvcMotionEstimationINTEL,
+    spv::Capability::SubgroupAvcMotionEstimationIntraINTEL,
+    spv::Capability::SubgroupAvcMotionEstimationChromaINTEL,
+    spv::Capability::VariableLengthArrayINTEL,
+    spv::Capability::FunctionFloatControlINTEL,
+    spv::Capability::FPGAMemoryAttributesINTEL,
+    spv::Capability::FPFastMathModeINTEL,
+    spv::Capability::ArbitraryPrecisionIntegersINTEL,
+    spv::Capability::ArbitraryPrecisionFloatingPointINTEL,
+    spv::Capability::UnstructuredLoopControlsINTEL,
+    spv::Capability::FPGALoopControlsINTEL,
+    spv::Capability::KernelAttributesINTEL,
+    spv::Capability::FPGAKernelAttributesINTEL,
+    spv::Capability::FPGAMemoryAccessesINTEL,
+    spv::Capability::FPGAClusterAttributesINTEL,
+    spv::Capability::LoopFuseINTEL,
+    spv::Capability::FPGADSPControlINTEL,
+    spv::Capability::MemoryAccessAliasingINTEL,
+    spv::Capability::FPGAInvocationPipeliningAttributesINTEL,
+    spv::Capability::FPGABufferLocationINTEL,
+    spv::Capability::ArbitraryPrecisionFixedPointINTEL,
+    spv::Capability::USMStorageClassesINTEL,
+    spv::Capability::RuntimeAlignedAttributeINTEL,
+    spv::Capability::IOPipesINTEL,
+    spv::Capability::BlockingPipesINTEL,
+    spv::Capability::FPGARegINTEL,
+    spv::Capability::DotProductInputAll,
+    spv::Capability::DotProductInputAllKHR,
+    spv::Capability::DotProductInput4x8Bit,
+    spv::Capability::DotProductInput4x8BitKHR,
+    spv::Capability::DotProductInput4x8BitPacked,
+    spv::Capability::DotProductInput4x8BitPackedKHR,
+    spv::Capability::DotProduct,
+    spv::Capability::DotProductKHR,
+    spv::Capability::RayCullMaskKHR,
+    spv::Capability::BitInstructions,
+    spv::Capability::GroupNonUniformRotateKHR,
+    spv::Capability::AtomicFloat32AddEXT,
+    spv::Capability::AtomicFloat64AddEXT,
+    spv::Capability::LongCompositesINTEL,
+    spv::Capability::OptNoneINTEL,
+    spv::Capability::AtomicFloat16AddEXT,
+    spv::Capability::DebugInfoModuleINTEL,
+    spv::Capability::SplitBarrierINTEL,
+    spv::Capability::GroupUniformArithmeticKHR,
+    spv::Capability::Max,
+};
+
+namespace {
+std::vector<TestEnum> enumerateValuesFromToWithStep(size_t start, size_t end,
+                                                    size_t step) {
+  assert(end > start && "end > start");
+  std::vector<TestEnum> orderedValues;
+  for (size_t i = start; i < end; i += step) {
+    orderedValues.push_back(static_cast<TestEnum>(i));
+  }
+  return orderedValues;
+}
+
+EnumSet<TestEnum> createSetUnorderedInsertion(
+    const std::vector<TestEnum>& values) {
+  std::vector shuffledValues(values.cbegin(), values.cend());
+  std::mt19937 rng(0);
+  std::shuffle(shuffledValues.begin(), shuffledValues.end(), rng);
+  EnumSet<TestEnum> set;
+  for (auto value : shuffledValues) {
+    set.insert(value);
+  }
+  return set;
+}
+}  // namespace
+
 TEST(EnumSet, IsEmpty1) {
-  EnumSet<uint32_t> set;
-  EXPECT_TRUE(set.IsEmpty());
-  set.Add(0);
-  EXPECT_FALSE(set.IsEmpty());
+  EnumSet<TestEnum> set;
+  EXPECT_TRUE(set.empty());
+  set.insert(TestEnum::ZERO);
+  EXPECT_FALSE(set.empty());
 }
 
 TEST(EnumSet, IsEmpty2) {
-  EnumSet<uint32_t> set;
-  EXPECT_TRUE(set.IsEmpty());
-  set.Add(150);
-  EXPECT_FALSE(set.IsEmpty());
+  EnumSet<TestEnum> set;
+  EXPECT_TRUE(set.empty());
+  set.insert(TestEnum::ONE_HUNDRED_FIFTY);
+  EXPECT_FALSE(set.empty());
 }
 
 TEST(EnumSet, IsEmpty3) {
-  EnumSet<uint32_t> set(4);
-  EXPECT_FALSE(set.IsEmpty());
+  EnumSet<TestEnum> set(TestEnum::FOUR);
+  EXPECT_FALSE(set.empty());
 }
 
 TEST(EnumSet, IsEmpty4) {
-  EnumSet<uint32_t> set(300);
-  EXPECT_FALSE(set.IsEmpty());
+  EnumSet<TestEnum> set(TestEnum::THREE_HUNDRED);
+  EXPECT_FALSE(set.empty());
 }
 
 TEST(EnumSetHasAnyOf, EmptySetEmptyQuery) {
-  const EnumSet<uint32_t> set;
-  const EnumSet<uint32_t> empty;
+  const EnumSet<TestEnum> set;
+  const EnumSet<TestEnum> empty;
   EXPECT_TRUE(set.HasAnyOf(empty));
-  EXPECT_TRUE(EnumSet<uint32_t>().HasAnyOf(EnumSet<uint32_t>()));
+  EXPECT_TRUE(EnumSet<TestEnum>().HasAnyOf(EnumSet<TestEnum>()));
 }
 
 TEST(EnumSetHasAnyOf, MaskSetEmptyQuery) {
-  EnumSet<uint32_t> set;
-  const EnumSet<uint32_t> empty;
-  set.Add(5);
-  set.Add(8);
+  EnumSet<TestEnum> set;
+  const EnumSet<TestEnum> empty;
+  set.insert(TestEnum::FIVE);
+  set.insert(TestEnum::EIGHT);
   EXPECT_TRUE(set.HasAnyOf(empty));
 }
 
 TEST(EnumSetHasAnyOf, OverflowSetEmptyQuery) {
-  EnumSet<uint32_t> set;
-  const EnumSet<uint32_t> empty;
-  set.Add(200);
-  set.Add(300);
+  EnumSet<TestEnum> set;
+  const EnumSet<TestEnum> empty;
+  set.insert(TestEnum::TWO_HUNDRED);
+  set.insert(TestEnum::THREE_HUNDRED);
   EXPECT_TRUE(set.HasAnyOf(empty));
 }
 
 TEST(EnumSetHasAnyOf, EmptyQuery) {
-  EnumSet<uint32_t> set;
-  const EnumSet<uint32_t> empty;
-  set.Add(5);
-  set.Add(8);
-  set.Add(200);
-  set.Add(300);
+  EnumSet<TestEnum> set;
+  const EnumSet<TestEnum> empty;
+  set.insert(TestEnum::FIVE);
+  set.insert(TestEnum::EIGHT);
+  set.insert(TestEnum::TWO_HUNDRED);
+  set.insert(TestEnum::THREE_HUNDRED);
   EXPECT_TRUE(set.HasAnyOf(empty));
 }
 
 TEST(EnumSetHasAnyOf, EmptyQueryAlwaysTrue) {
-  EnumSet<uint32_t> set;
-  const EnumSet<uint32_t> empty;
+  EnumSet<TestEnum> set;
+  const EnumSet<TestEnum> empty;
   EXPECT_TRUE(set.HasAnyOf(empty));
-  set.Add(5);
+  set.insert(TestEnum::FIVE);
   EXPECT_TRUE(set.HasAnyOf(empty));
 
-  EXPECT_TRUE(EnumSet<uint32_t>(100).HasAnyOf(EnumSet<uint32_t>()));
+  EXPECT_TRUE(
+      EnumSet<TestEnum>(TestEnum::ONE_HUNDRED).HasAnyOf(EnumSet<TestEnum>()));
 }
 
 TEST(EnumSetHasAnyOf, ReflexiveMask) {
-  EnumSet<uint32_t> set(3);
-  set.Add(24);
-  set.Add(30);
+  EnumSet<TestEnum> set(TestEnum::THREE);
+  set.insert(TestEnum::TWENTY_FOUR);
+  set.insert(TestEnum::THIRTY);
   EXPECT_TRUE(set.HasAnyOf(set));
 }
 
 TEST(EnumSetHasAnyOf, ReflexiveOverflow) {
-  EnumSet<uint32_t> set(200);
-  set.Add(300);
-  set.Add(400);
+  EnumSet<TestEnum> set(TestEnum::TWO_HUNDRED);
+  set.insert(TestEnum::TWO_HUNDRED);
+  set.insert(TestEnum::FOUR_HUNDRED);
   EXPECT_TRUE(set.HasAnyOf(set));
 }
 
 TEST(EnumSetHasAnyOf, Reflexive) {
-  EnumSet<uint32_t> set(3);
-  set.Add(24);
-  set.Add(300);
-  set.Add(400);
+  EnumSet<TestEnum> set(TestEnum::THREE);
+  set.insert(TestEnum::TWENTY_FOUR);
+  set.insert(TestEnum::THREE_HUNDRED);
+  set.insert(TestEnum::FOUR_HUNDRED);
   EXPECT_TRUE(set.HasAnyOf(set));
 }
 
 TEST(EnumSetHasAnyOf, EmptySetHasNone) {
-  EnumSet<uint32_t> set;
-  EnumSet<uint32_t> items;
+  EnumSet<TestEnum> set;
+  EnumSet<TestEnum> items;
   for (uint32_t i = 0; i < 200; ++i) {
-    items.Add(i);
+    TestEnum enumValue = static_cast<TestEnum>(i);
+    items.insert(enumValue);
     EXPECT_FALSE(set.HasAnyOf(items));
-    EXPECT_FALSE(set.HasAnyOf(EnumSet<uint32_t>(i)));
+    EXPECT_FALSE(set.HasAnyOf(EnumSet<TestEnum>(enumValue)));
   }
 }
 
 TEST(EnumSetHasAnyOf, MaskSetMaskQuery) {
-  EnumSet<uint32_t> set(0);
-  EnumSet<uint32_t> items(1);
+  EnumSet<TestEnum> set(TestEnum::ZERO);
+  EnumSet<TestEnum> items(TestEnum::ONE);
   EXPECT_FALSE(set.HasAnyOf(items));
-  set.Add(2);
-  items.Add(3);
+  set.insert(TestEnum::TWO);
+  items.insert(TestEnum::THREE);
   EXPECT_FALSE(set.HasAnyOf(items));
-  set.Add(3);
+  set.insert(TestEnum::THREE);
   EXPECT_TRUE(set.HasAnyOf(items));
-  set.Add(4);
+  set.insert(TestEnum::FOUR);
   EXPECT_TRUE(set.HasAnyOf(items));
 }
 
 TEST(EnumSetHasAnyOf, OverflowSetOverflowQuery) {
-  EnumSet<uint32_t> set(100);
-  EnumSet<uint32_t> items(200);
+  EnumSet<TestEnum> set(TestEnum::ONE_HUNDRED);
+  EnumSet<TestEnum> items(TestEnum::TWO_HUNDRED);
   EXPECT_FALSE(set.HasAnyOf(items));
-  set.Add(300);
-  items.Add(400);
+  set.insert(TestEnum::THREE_HUNDRED);
+  items.insert(TestEnum::FOUR_HUNDRED);
   EXPECT_FALSE(set.HasAnyOf(items));
-  set.Add(200);
+  set.insert(TestEnum::TWO_HUNDRED);
   EXPECT_TRUE(set.HasAnyOf(items));
-  set.Add(500);
+  set.insert(TestEnum::FIVE_HUNDRED);
   EXPECT_TRUE(set.HasAnyOf(items));
 }
 
 TEST(EnumSetHasAnyOf, GeneralCase) {
-  EnumSet<uint32_t> set(0);
-  EnumSet<uint32_t> items(100);
+  EnumSet<TestEnum> set(TestEnum::ZERO);
+  EnumSet<TestEnum> items(TestEnum::ONE_HUNDRED);
   EXPECT_FALSE(set.HasAnyOf(items));
-  set.Add(300);
-  items.Add(4);
+  set.insert(TestEnum::THREE_HUNDRED);
+  items.insert(TestEnum::FOUR);
   EXPECT_FALSE(set.HasAnyOf(items));
-  set.Add(5);
-  items.Add(500);
+  set.insert(TestEnum::FIVE);
+  items.insert(TestEnum::FIVE_HUNDRED);
   EXPECT_FALSE(set.HasAnyOf(items));
-  set.Add(500);
+  set.insert(TestEnum::FIVE_HUNDRED);
   EXPECT_TRUE(set.HasAnyOf(items));
-  EXPECT_FALSE(set.HasAnyOf(EnumSet<uint32_t>(20)));
-  EXPECT_FALSE(set.HasAnyOf(EnumSet<uint32_t>(600)));
-  EXPECT_TRUE(set.HasAnyOf(EnumSet<uint32_t>(5)));
-  EXPECT_TRUE(set.HasAnyOf(EnumSet<uint32_t>(300)));
-  EXPECT_TRUE(set.HasAnyOf(EnumSet<uint32_t>(0)));
+  EXPECT_FALSE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::TWENTY)));
+  EXPECT_FALSE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::SIX_HUNDRED)));
+  EXPECT_TRUE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::FIVE)));
+  EXPECT_TRUE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::THREE_HUNDRED)));
+  EXPECT_TRUE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::ZERO)));
 }
 
 TEST(EnumSet, DefaultIsEmpty) {
-  EnumSet<uint32_t> set;
+  EnumSet<TestEnum> set;
   for (uint32_t i = 0; i < 1000; ++i) {
-    EXPECT_FALSE(set.Contains(i));
+    EXPECT_FALSE(set.contains(static_cast<TestEnum>(i)));
+  }
+}
+
+TEST(EnumSet, EqualityCompareEmpty) {
+  EnumSet<TestEnum> set1;
+  EnumSet<TestEnum> set2;
+
+  EXPECT_TRUE(set1 == set2);
+  EXPECT_FALSE(set1 != set2);
+}
+
+TEST(EnumSet, EqualityCompareSame) {
+  EnumSet<TestEnum> set1;
+  EnumSet<TestEnum> set2;
+
+  set1.insert(TestEnum::ONE);
+  set1.insert(TestEnum::TWENTY);
+  set2.insert(TestEnum::TWENTY);
+  set2.insert(TestEnum::ONE);
+
+  EXPECT_TRUE(set1 == set2);
+  EXPECT_FALSE(set1 != set2);
+}
+
+TEST(EnumSet, EqualityCompareDifferent) {
+  EnumSet<TestEnum> set1;
+  EnumSet<TestEnum> set2;
+
+  set1.insert(TestEnum::ONE);
+  set1.insert(TestEnum::TWENTY);
+  set2.insert(TestEnum::FIVE);
+  set2.insert(TestEnum::ONE);
+
+  EXPECT_FALSE(set1 == set2);
+  EXPECT_TRUE(set1 != set2);
+}
+
+TEST(EnumSet, ConstructFromIterators) {
+  auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1);
+  EnumSet<TestEnum> set1 = createSetUnorderedInsertion(orderedValues);
+
+  EnumSet<TestEnum> set2(orderedValues.cbegin(), orderedValues.cend());
+
+  EXPECT_EQ(set1, set2);
+}
+
+TEST(EnumSet, InsertUsingIteratorRange) {
+  auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1);
+  EnumSet<TestEnum> set1 = createSetUnorderedInsertion(orderedValues);
+
+  EnumSet<TestEnum> set2;
+  set2.insert(orderedValues.cbegin(), orderedValues.cend());
+
+  EXPECT_EQ(set1, set2);
+}
+
+TEST(CapabilitySet, RangeBasedLoopOrderIsEnumOrder) {
+  auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1);
+  auto set = createSetUnorderedInsertion(orderedValues);
+
+  size_t index = 0;
+  for (auto value : set) {
+    ASSERT_THAT(value, Eq(orderedValues[index]));
+    index++;
   }
 }
 
 TEST(CapabilitySet, ConstructSingleMemberMatrix) {
   CapabilitySet s(spv::Capability::Matrix);
-  EXPECT_TRUE(s.Contains(spv::Capability::Matrix));
-  EXPECT_FALSE(s.Contains(spv::Capability::Shader));
-  EXPECT_FALSE(s.Contains(static_cast<spv::Capability>(1000)));
+  EXPECT_TRUE(s.contains(spv::Capability::Matrix));
+  EXPECT_FALSE(s.contains(spv::Capability::Shader));
+  EXPECT_FALSE(s.contains(static_cast<spv::Capability>(1000)));
 }
 
 TEST(CapabilitySet, ConstructSingleMemberMaxInMask) {
   CapabilitySet s(static_cast<spv::Capability>(63));
-  EXPECT_FALSE(s.Contains(spv::Capability::Matrix));
-  EXPECT_FALSE(s.Contains(spv::Capability::Shader));
-  EXPECT_TRUE(s.Contains(static_cast<spv::Capability>(63)));
-  EXPECT_FALSE(s.Contains(static_cast<spv::Capability>(64)));
-  EXPECT_FALSE(s.Contains(static_cast<spv::Capability>(1000)));
+  EXPECT_FALSE(s.contains(spv::Capability::Matrix));
+  EXPECT_FALSE(s.contains(spv::Capability::Shader));
+  EXPECT_TRUE(s.contains(static_cast<spv::Capability>(63)));
+  EXPECT_FALSE(s.contains(static_cast<spv::Capability>(64)));
+  EXPECT_FALSE(s.contains(static_cast<spv::Capability>(1000)));
 }
 
 TEST(CapabilitySet, ConstructSingleMemberMinOverflow) {
   // Check the first one that forces overflow beyond the mask.
   CapabilitySet s(static_cast<spv::Capability>(64));
-  EXPECT_FALSE(s.Contains(spv::Capability::Matrix));
-  EXPECT_FALSE(s.Contains(spv::Capability::Shader));
-  EXPECT_FALSE(s.Contains(static_cast<spv::Capability>(63)));
-  EXPECT_TRUE(s.Contains(static_cast<spv::Capability>(64)));
-  EXPECT_FALSE(s.Contains(static_cast<spv::Capability>(1000)));
+  EXPECT_FALSE(s.contains(spv::Capability::Matrix));
+  EXPECT_FALSE(s.contains(spv::Capability::Shader));
+  EXPECT_FALSE(s.contains(static_cast<spv::Capability>(63)));
+  EXPECT_TRUE(s.contains(static_cast<spv::Capability>(64)));
+  EXPECT_FALSE(s.contains(static_cast<spv::Capability>(1000)));
 }
 
 TEST(CapabilitySet, ConstructSingleMemberMaxOverflow) {
   // Check the max 32-bit signed int.
   CapabilitySet s(static_cast<spv::Capability>(0x7fffffffu));
-  EXPECT_FALSE(s.Contains(spv::Capability::Matrix));
-  EXPECT_FALSE(s.Contains(spv::Capability::Shader));
-  EXPECT_FALSE(s.Contains(static_cast<spv::Capability>(1000)));
-  EXPECT_TRUE(s.Contains(static_cast<spv::Capability>(0x7fffffffu)));
+  EXPECT_FALSE(s.contains(spv::Capability::Matrix));
+  EXPECT_FALSE(s.contains(spv::Capability::Shader));
+  EXPECT_FALSE(s.contains(static_cast<spv::Capability>(1000)));
+  EXPECT_TRUE(s.contains(static_cast<spv::Capability>(0x7fffffffu)));
 }
 
 TEST(CapabilitySet, AddEnum) {
   CapabilitySet s(spv::Capability::Shader);
-  s.Add(spv::Capability::Kernel);
-  s.Add(static_cast<spv::Capability>(42));
-  EXPECT_FALSE(s.Contains(spv::Capability::Matrix));
-  EXPECT_TRUE(s.Contains(spv::Capability::Shader));
-  EXPECT_TRUE(s.Contains(spv::Capability::Kernel));
-  EXPECT_TRUE(s.Contains(static_cast<spv::Capability>(42)));
+  s.insert(spv::Capability::Kernel);
+  s.insert(static_cast<spv::Capability>(42));
+  EXPECT_FALSE(s.contains(spv::Capability::Matrix));
+  EXPECT_TRUE(s.contains(spv::Capability::Shader));
+  EXPECT_TRUE(s.contains(spv::Capability::Kernel));
+  EXPECT_TRUE(s.contains(static_cast<spv::Capability>(42)));
+}
+
+TEST(CapabilitySet, InsertReturnsIteratorToInserted) {
+  CapabilitySet set;
+
+  auto[it, inserted] = set.insert(spv::Capability::Kernel);
+
+  EXPECT_TRUE(inserted);
+  EXPECT_EQ(*it, spv::Capability::Kernel);
+}
+
+TEST(CapabilitySet, InsertReturnsIteratorToElementOnDoubleInsertion) {
+  CapabilitySet set;
+  EXPECT_FALSE(set.contains(spv::Capability::Shader));
+  {
+    auto[it, inserted] = set.insert(spv::Capability::Shader);
+    EXPECT_TRUE(inserted);
+    EXPECT_EQ(*it, spv::Capability::Shader);
+  }
+  EXPECT_TRUE(set.contains(spv::Capability::Shader));
+
+  auto[it, inserted] = set.insert(spv::Capability::Shader);
+
+  EXPECT_FALSE(inserted);
+  EXPECT_EQ(*it, spv::Capability::Shader);
+  EXPECT_TRUE(set.contains(spv::Capability::Shader));
+}
+
+TEST(CapabilitySet, InsertWithHintWorks) {
+  CapabilitySet set;
+  EXPECT_FALSE(set.contains(spv::Capability::Shader));
+
+  auto it = set.insert(set.begin(), spv::Capability::Shader);
+
+  EXPECT_EQ(*it, spv::Capability::Shader);
+  EXPECT_TRUE(set.contains(spv::Capability::Shader));
+}
+
+TEST(CapabilitySet, InsertWithEndHintWorks) {
+  CapabilitySet set;
+  EXPECT_FALSE(set.contains(spv::Capability::Shader));
+
+  auto it = set.insert(set.end(), spv::Capability::Shader);
+
+  EXPECT_EQ(*it, spv::Capability::Shader);
+  EXPECT_TRUE(set.contains(spv::Capability::Shader));
+}
+
+TEST(CapabilitySet, IteratorCanBeCopied) {
+  CapabilitySet set;
+  set.insert(spv::Capability::Matrix);
+  set.insert(spv::Capability::Shader);
+  set.insert(spv::Capability::Geometry);
+  set.insert(spv::Capability::Float64);
+  set.insert(spv::Capability::Float16);
+
+  auto a = set.begin();
+  ++a;
+  auto b = a;
+
+  EXPECT_EQ(*b, *a);
+  ++b;
+  EXPECT_NE(*b, *a);
+
+  ++a;
+  EXPECT_EQ(*b, *a);
+
+  ++a;
+  EXPECT_NE(*b, *a);
+}
+
+TEST(CapabilitySet, IteratorBeginToEndPostfix) {
+  auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 1);
+  auto set = createSetUnorderedInsertion(orderedValues);
+
+  size_t index = 0;
+  for (auto it = set.cbegin(); it != set.cend(); it++, index++) {
+    EXPECT_EQ(*it, orderedValues[index]);
+  }
+}
+
+TEST(CapabilitySet, IteratorBeginToEndPrefix) {
+  auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 1);
+  auto set = createSetUnorderedInsertion(orderedValues);
+
+  size_t index = 0;
+  for (auto it = set.cbegin(); it != set.cend(); ++it, index++) {
+    EXPECT_EQ(*it, orderedValues[index]);
+  }
+}
+
+TEST(CapabilitySet, IteratorBeginToEndPrefixStep) {
+  auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 8);
+  auto set = createSetUnorderedInsertion(orderedValues);
+
+  size_t index = 0;
+  for (auto it = set.cbegin(); it != set.cend(); ++it, index++) {
+    ASSERT_EQ(*it, orderedValues[index]);
+  }
+}
+
+TEST(CapabilitySet, IteratorBeginOnEmpty) {
+  CapabilitySet set;
+
+  auto begin = set.begin();
+  auto end = set.end();
+  ASSERT_EQ(begin, end);
+}
+
+TEST(CapabilitySet, IteratorBeginOnSingleNonZeroValue) {
+  CapabilitySet set;
+  set.insert(spv::Capability::Shader);
+
+  auto begin = set.begin();
+  auto end = set.end();
+
+  ASSERT_NE(begin, end);
+  ASSERT_EQ(*begin, spv::Capability::Shader);
+}
+
+TEST(CapabilitySet, IteratorForLoopNonZeroValue) {
+  CapabilitySet set;
+  set.insert(spv::Capability::Shader);
+  set.insert(spv::Capability::Tessellation);
+
+  auto begin = set.begin();
+  auto end = set.end();
+
+  ASSERT_NE(begin, end);
+  ASSERT_EQ(*begin, spv::Capability::Shader);
+
+  begin++;
+  ASSERT_NE(begin, end);
+  ASSERT_EQ(*begin, spv::Capability::Tessellation);
+
+  begin++;
+  ASSERT_EQ(begin, end);
+}
+
+TEST(CapabilitySet, IteratorPastEnd) {
+  CapabilitySet set;
+  set.insert(spv::Capability::Shader);
+
+  auto begin = set.begin();
+  auto end = set.end();
+
+  ASSERT_NE(begin, end);
+  ASSERT_EQ(*begin, spv::Capability::Shader);
+
+  begin++;
+  ASSERT_EQ(begin, end);
+
+  begin++;
+  ASSERT_EQ(begin, end);
+}
+
+TEST(CapabilitySet, CompatibleWithSTLFind) {
+  CapabilitySet set;
+  set.insert(spv::Capability::Matrix);
+  set.insert(spv::Capability::Shader);
+  set.insert(spv::Capability::Geometry);
+  set.insert(spv::Capability::Tessellation);
+  set.insert(spv::Capability::Addresses);
+  set.insert(spv::Capability::Linkage);
+  set.insert(spv::Capability::Kernel);
+  set.insert(spv::Capability::Vector16);
+  set.insert(spv::Capability::Float16Buffer);
+  set.insert(spv::Capability::Float64);
+
+  {
+    auto it = std::find(set.cbegin(), set.cend(), spv::Capability::Vector16);
+    ASSERT_NE(it, set.end());
+    ASSERT_EQ(*it, spv::Capability::Vector16);
+  }
+
+  {
+    auto it = std::find(set.cbegin(), set.cend(), spv::Capability::Float16);
+    ASSERT_EQ(it, set.end());
+  }
+}
+
+TEST(CapabilitySet, CompatibleWithSTLForEach) {
+  auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 15);
+  auto set = createSetUnorderedInsertion(orderedValues);
+
+  size_t index = 0;
+  std::for_each(set.cbegin(), set.cend(), [&](auto item) {
+    ASSERT_EQ(item, orderedValues[index]);
+    index++;
+  });
 }
 
 TEST(CapabilitySet, InitializerListEmpty) {
   CapabilitySet s{};
   for (uint32_t i = 0; i < 1000; i++) {
-    EXPECT_FALSE(s.Contains(static_cast<spv::Capability>(i)));
+    EXPECT_FALSE(s.contains(static_cast<spv::Capability>(i)));
+  }
+}
+
+TEST(CapabilitySet, LargeSetHasInsertedElements) {
+  CapabilitySet set;
+  for (auto c : kCapabilities) {
+    EXPECT_FALSE(set.contains(c));
+  }
+
+  for (auto c : kCapabilities) {
+    set.insert(c);
+    EXPECT_TRUE(set.contains(c));
+  }
+
+  for (auto c : kCapabilities) {
+    EXPECT_TRUE(set.contains(c));
+  }
+}
+
+TEST(CapabilitySet, LargeSetHasUnsortedInsertedElements) {
+  std::vector shuffledCapabilities(kCapabilities.cbegin(),
+                                   kCapabilities.cend());
+  std::mt19937 rng(0);
+  std::shuffle(shuffledCapabilities.begin(), shuffledCapabilities.end(), rng);
+  CapabilitySet set;
+  for (auto c : shuffledCapabilities) {
+    EXPECT_FALSE(set.contains(c));
+  }
+
+  for (auto c : shuffledCapabilities) {
+    set.insert(c);
+    EXPECT_TRUE(set.contains(c));
+  }
+
+  for (auto c : shuffledCapabilities) {
+    EXPECT_TRUE(set.contains(c));
+  }
+}
+
+TEST(CapabilitySet, LargeSetHasUnsortedRemovedElement) {
+  std::vector shuffledCapabilities(kCapabilities.cbegin(),
+                                   kCapabilities.cend());
+  std::mt19937 rng(0);
+  std::shuffle(shuffledCapabilities.begin(), shuffledCapabilities.end(), rng);
+  CapabilitySet set;
+  for (auto c : shuffledCapabilities) {
+    set.insert(c);
+    EXPECT_TRUE(set.contains(c));
+  }
+
+  for (auto c : kCapabilities) {
+    set.erase(c);
+  }
+
+  for (auto c : shuffledCapabilities) {
+    EXPECT_FALSE(set.contains(c));
   }
 }
 
@@ -287,5 +882,20 @@
           static_cast<spv::Capability>(0x7fffffff)}},
     }));
 
+using BoundaryTestWithParam = ::testing::TestWithParam<spv::Capability>;
+
+TEST_P(BoundaryTestWithParam, InsertedContains) {
+  CapabilitySet set;
+  set.insert(GetParam());
+  EXPECT_TRUE(set.contains(GetParam()));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    Samples, BoundaryTestWithParam,
+    Values(static_cast<spv::Capability>(0), static_cast<spv::Capability>(63),
+           static_cast<spv::Capability>(64), static_cast<spv::Capability>(65),
+           static_cast<spv::Capability>(127), static_cast<spv::Capability>(128),
+           static_cast<spv::Capability>(129)));
+
 }  // namespace
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/fuzz/transformation_add_no_contraction_decoration_test.cpp b/third_party/SPIRV-Tools/test/fuzz/transformation_add_no_contraction_decoration_test.cpp
index 4fc9d2d..1280b81 100644
--- a/third_party/SPIRV-Tools/test/fuzz/transformation_add_no_contraction_decoration_test.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/transformation_add_no_contraction_decoration_test.cpp
@@ -36,7 +36,6 @@
                OpName %8 "x"
                OpName %10 "y"
                OpName %14 "i"
-               OpDecorate %32 NoContraction
           %2 = OpTypeVoid
           %3 = OpTypeFunction %2
           %6 = OpTypeFloat 32
@@ -110,9 +109,8 @@
   ASSERT_FALSE(TransformationAddNoContractionDecoration(24).IsApplicable(
       context.get(), transformation_context));
 
-  // It is valid to add NoContraction to each of these ids (and it's fine to
-  // have duplicates of the decoration, in the case of 32).
-  for (uint32_t result_id : {32u, 32u, 27u, 29u, 39u}) {
+  // It is valid to add NoContraction to each of these ids.
+  for (uint32_t result_id : {32u, 27u, 29u, 39u}) {
     TransformationAddNoContractionDecoration transformation(result_id);
     ASSERT_TRUE(
         transformation.IsApplicable(context.get(), transformation_context));
@@ -134,8 +132,6 @@
                OpName %10 "y"
                OpName %14 "i"
                OpDecorate %32 NoContraction
-               OpDecorate %32 NoContraction
-               OpDecorate %32 NoContraction
                OpDecorate %27 NoContraction
                OpDecorate %29 NoContraction
                OpDecorate %39 NoContraction
diff --git a/third_party/SPIRV-Tools/test/fuzz/transformation_add_opphi_synonym_test.cpp b/third_party/SPIRV-Tools/test/fuzz/transformation_add_opphi_synonym_test.cpp
index 4aca30c..03fd39a 100644
--- a/third_party/SPIRV-Tools/test/fuzz/transformation_add_opphi_synonym_test.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/transformation_add_opphi_synonym_test.cpp
@@ -365,8 +365,7 @@
       MakeSynonymFact(12, 16));
 
   // Remove the VariablePointers capability.
-  context.get()->get_feature_mgr()->RemoveCapability(
-      spv::Capability::VariablePointers);
+  context.get()->RemoveCapability(spv::Capability::VariablePointers);
 
   // The VariablePointers capability is required to add an OpPhi instruction of
   // pointer type.
@@ -374,8 +373,7 @@
                    .IsApplicable(context.get(), transformation_context));
 
   // Add the VariablePointers capability back.
-  context.get()->get_feature_mgr()->AddCapability(
-      spv::Capability::VariablePointers);
+  context.get()->AddCapability(spv::Capability::VariablePointers);
 
   // If the ids have pointer type, the storage class must be Workgroup or
   // StorageBuffer, but it is Function in this case.
diff --git a/third_party/SPIRV-Tools/test/fuzz/transformation_add_relaxed_decoration_test.cpp b/third_party/SPIRV-Tools/test/fuzz/transformation_add_relaxed_decoration_test.cpp
index c440882..979eeb7 100644
--- a/third_party/SPIRV-Tools/test/fuzz/transformation_add_relaxed_decoration_test.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/transformation_add_relaxed_decoration_test.cpp
@@ -86,9 +86,8 @@
   // Invalid: 28 is in a dead block, but returns bool (not numeric).
   ASSERT_FALSE(TransformationAddRelaxedDecoration(28).IsApplicable(
       context.get(), transformation_context));
-  // It is valid to add RelaxedPrecision to 25 (and it's fine to
-  // have a duplicate).
-  for (uint32_t result_id : {25u, 25u}) {
+  // It is valid to add RelaxedPrecision to 25
+  for (uint32_t result_id : {25u}) {
     TransformationAddRelaxedDecoration transformation(result_id);
     ASSERT_TRUE(
         transformation.IsApplicable(context.get(), transformation_context));
@@ -110,7 +109,6 @@
                OpName %10 "b"
                OpName %14 "c"
                OpDecorate %25 RelaxedPrecision
-               OpDecorate %25 RelaxedPrecision
           %2 = OpTypeVoid
           %3 = OpTypeFunction %2
           %6 = OpTypeInt 32 1
diff --git a/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_float_test.cpp b/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_float_test.cpp
index 75f3788..135190a 100644
--- a/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_float_test.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_float_test.cpp
@@ -74,7 +74,7 @@
 
   // By default, SPIR-V does not support 64-bit float types.
   // Below we add such capability, so the test should now pass.
-  context.get()->get_feature_mgr()->AddCapability(spv::Capability::Float64);
+  context.get()->AddCapability(spv::Capability::Float64);
   ASSERT_TRUE(TransformationAddTypeFloat(7, 64).IsApplicable(
       context.get(), transformation_context));
 
diff --git a/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_int_test.cpp b/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_int_test.cpp
index b41d420..e31730c 100644
--- a/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_int_test.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_int_test.cpp
@@ -88,13 +88,13 @@
 
   // By default SPIR-V does not support 16-bit integers.
   // Below we add such capability, so the test should now be successful.
-  context.get()->get_feature_mgr()->AddCapability(spv::Capability::Int16);
+  context.get()->AddCapability(spv::Capability::Int16);
   ASSERT_TRUE(TransformationAddTypeInt(7, 16, true)
                   .IsApplicable(context.get(), transformation_context));
 
   // By default SPIR-V does not support 64-bit integers.
   // Below we add such capability, so the test should now pass.
-  context.get()->get_feature_mgr()->AddCapability(spv::Capability::Int64);
+  context.get()->AddCapability(spv::Capability::Int64);
   ASSERT_TRUE(TransformationAddTypeInt(7, 64, true)
                   .IsApplicable(context.get(), transformation_context));
 
diff --git a/third_party/SPIRV-Tools/test/link/binary_version_test.cpp b/third_party/SPIRV-Tools/test/link/binary_version_test.cpp
index 78da1ae..384255a 100644
--- a/third_party/SPIRV-Tools/test/link/binary_version_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/binary_version_test.cpp
@@ -73,5 +73,21 @@
                         "through 1) vs 1.5 (input module 2)."));
 }
 
+TEST_F(BinaryVersion, UseHighest) {
+  // clang-format off
+  spvtest::Binaries binaries = {
+      CreateBinary(SPV_SPIRV_VERSION_WORD(1, 3)),
+      CreateBinary(SPV_SPIRV_VERSION_WORD(1, 5)),
+  };
+  // clang-format on
+  LinkerOptions options;
+  options.SetUseHighestVersion(true);
+  spvtest::Binary linked_binary;
+  ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary, options))
+      << GetErrorMessage();
+  EXPECT_THAT(GetErrorMessage(), std::string());
+  EXPECT_EQ(SPV_SPIRV_VERSION_WORD(1, 5), linked_binary[1]);
+}
+
 }  // namespace
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/log_test.cpp b/third_party/SPIRV-Tools/test/log_test.cpp
deleted file mode 100644
index ec66aa1..0000000
--- a/third_party/SPIRV-Tools/test/log_test.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2016 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "source/opt/log.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace spvtools {
-namespace {
-
-using ::testing::MatchesRegex;
-
-TEST(Log, Unimplemented) {
-  int invocation = 0;
-  auto consumer = [&invocation](spv_message_level_t level, const char* source,
-                                const spv_position_t&, const char* message) {
-    ++invocation;
-    EXPECT_EQ(SPV_MSG_INTERNAL_ERROR, level);
-    EXPECT_THAT(source, MatchesRegex(".*log_test.cpp$"));
-    EXPECT_STREQ("unimplemented: the-ultimite-feature", message);
-  };
-
-  SPIRV_UNIMPLEMENTED(consumer, "the-ultimite-feature");
-  EXPECT_EQ(1, invocation);
-}
-
-TEST(Log, Unreachable) {
-  int invocation = 0;
-  auto consumer = [&invocation](spv_message_level_t level, const char* source,
-                                const spv_position_t&, const char* message) {
-    ++invocation;
-    EXPECT_EQ(SPV_MSG_INTERNAL_ERROR, level);
-    EXPECT_THAT(source, MatchesRegex(".*log_test.cpp$"));
-    EXPECT_STREQ("unreachable", message);
-  };
-
-  SPIRV_UNREACHABLE(consumer);
-  EXPECT_EQ(1, invocation);
-}
-
-}  // namespace
-}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/operand_capabilities_test.cpp b/third_party/SPIRV-Tools/test/operand_capabilities_test.cpp
index 01b98a6..53dbe07 100644
--- a/third_party/SPIRV-Tools/test/operand_capabilities_test.cpp
+++ b/third_party/SPIRV-Tools/test/operand_capabilities_test.cpp
@@ -18,7 +18,12 @@
 #include <vector>
 
 #include "gmock/gmock.h"
+#include "source/assembly_grammar.h"
 #include "source/enum_set.h"
+#include "source/operand.h"
+#include "source/spirv_target_env.h"
+#include "source/table.h"
+#include "spirv-tools/libspirv.h"
 #include "test/unit_spirv.h"
 
 namespace spvtools {
@@ -31,6 +36,25 @@
 using ::testing::Values;
 using ::testing::ValuesIn;
 
+// Emits a CapabilitySet to the given ostream, returning the ostream.
+inline std::ostream& operator<<(std::ostream& out, const CapabilitySet& cs) {
+  out << "CapabilitySet{";
+  auto ctx = spvContextCreate(SPV_ENV_UNIVERSAL_1_0);
+  spvtools::AssemblyGrammar grammar(ctx);
+  bool first = true;
+  for (auto c : cs) {
+    if (!first) {
+      out << " ";
+      first = false;
+    }
+    out << grammar.lookupOperandName(SPV_OPERAND_TYPE_CAPABILITY, uint32_t(c))
+        << "(" << uint32_t(c) << ")";
+  }
+  spvContextDestroy(ctx);
+  out << "}";
+  return out;
+}
+
 // A test case for mapping an enum to a capability mask.
 struct EnumCapabilityCase {
   spv_operand_type_t type;
@@ -38,6 +62,16 @@
   CapabilitySet expected_capabilities;
 };
 
+// Emits an EnumCapabilityCase to the given output stream. This is used
+// to emit failure cases when they occur, which helps debug tests.
+inline std::ostream& operator<<(std::ostream& out, EnumCapabilityCase e) {
+  out << "{" << spvOperandTypeStr(e.type) << " " << e.value << " "
+      << e.expected_capabilities << " }";
+  return out;
+}
+
+using EnvEnumCapabilityCase = std::tuple<spv_target_env, EnumCapabilityCase>;
+
 // Test fixture for testing EnumCapabilityCases.
 using EnumCapabilityTest =
     TestWithParam<std::tuple<spv_target_env, EnumCapabilityCase>>;
@@ -56,7 +90,7 @@
 
   EXPECT_THAT(ElementsIn(cap_set),
               Eq(ElementsIn(std::get<1>(GetParam()).expected_capabilities)))
-      << " capability value " << std::get<1>(GetParam()).value;
+      << " enum value " << std::get<1>(GetParam()).value;
   spvContextDestroy(context);
 }
 
@@ -237,25 +271,21 @@
     SamplerAddressingMode, EnumCapabilityTest,
     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
             ValuesIn(std::vector<EnumCapabilityCase>{
-                CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::None,
-                      Kernel),
-                CASE1(SAMPLER_ADDRESSING_MODE,
-                      SamplerAddressingMode::ClampToEdge, Kernel),
-                CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::Clamp,
-                      Kernel),
-                CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::Repeat,
-                      Kernel),
-                CASE1(SAMPLER_ADDRESSING_MODE,
-                      SamplerAddressingMode::RepeatMirrored, Kernel),
-            })));
+                CASE0(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::None),
+                CASE0(SAMPLER_ADDRESSING_MODE,
+                      SamplerAddressingMode::ClampToEdge),
+                CASE0(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::Clamp),
+                CASE0(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::Repeat),
+                CASE0(SAMPLER_ADDRESSING_MODE,
+                      SamplerAddressingMode::RepeatMirrored)})));
 
 // See SPIR-V Section 3.10 Sampler Filter Mode
 INSTANTIATE_TEST_SUITE_P(
     SamplerFilterMode, EnumCapabilityTest,
     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
             ValuesIn(std::vector<EnumCapabilityCase>{
-                CASE1(SAMPLER_FILTER_MODE, SamplerFilterMode::Nearest, Kernel),
-                CASE1(SAMPLER_FILTER_MODE, SamplerFilterMode::Linear, Kernel),
+                CASE0(SAMPLER_FILTER_MODE, SamplerFilterMode::Nearest),
+                CASE0(SAMPLER_FILTER_MODE, SamplerFilterMode::Linear),
             })));
 
 // See SPIR-V Section 3.11 Image Format
@@ -310,56 +340,56 @@
 // See SPIR-V Section 3.12 Image Channel Order
 INSTANTIATE_TEST_SUITE_P(
     ImageChannelOrder, EnumCapabilityTest,
-    Combine(
-        Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
-        ValuesIn(std::vector<EnumCapabilityCase>{
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::R, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::A, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RG, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RA, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGB, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGBA, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::BGRA, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::ARGB, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Intensity, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Luminance, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Rx, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGx, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGBx, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Depth, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::DepthStencil, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGB, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGBx, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGBA, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sBGRA, Kernel),
-            CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::ABGR, Kernel),
-        })));
+    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
+            ValuesIn(std::vector<EnumCapabilityCase>{
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::R),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::A),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RG),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RA),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGB),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGBA),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::BGRA),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::ARGB),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Intensity),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Luminance),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Rx),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGx),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGBx),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Depth),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::DepthStencil),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGB),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGBx),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGBA),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sBGRA),
+                CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::ABGR),
+            })));
 
 // See SPIR-V Section 3.13 Image Channel Data Type
 INSTANTIATE_TEST_SUITE_P(
     ImageChannelDataType, EnumCapabilityTest,
-    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
-            ValuesIn(std::vector<EnumCapabilityCase>{
-                // clang-format off
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SnormInt8, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SnormInt16, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt8, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt16, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormShort565, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormShort555, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt101010, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt8, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt16, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt32, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt8, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt16, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt32, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::HalfFloat, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::Float, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt24, Kernel),
-                CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt101010_2, Kernel),
-                // clang-format on
-            })));
+    Combine(
+        Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
+        ValuesIn(std::vector<EnumCapabilityCase>{
+            // clang-format off
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SnormInt8),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SnormInt16),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt8),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt16),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormShort565),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormShort555),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt101010),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt8),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt16),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt32),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt8),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt16),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt32),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::HalfFloat),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::Float),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt24),
+                CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt101010_2),
+            // clang-format on
+        })));
 
 // See SPIR-V Section 3.14 Image Operands
 INSTANTIATE_TEST_SUITE_P(
@@ -417,7 +447,7 @@
 
 // See SPIR-V Section 3.20 Decoration
 INSTANTIATE_TEST_SUITE_P(
-    Decoration, EnumCapabilityTest,
+    Decoration_1_1, EnumCapabilityTest,
     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
             ValuesIn(std::vector<EnumCapabilityCase>{
                 CASE1(DECORATION, Decoration::RelaxedPrecision, Shader),
@@ -461,7 +491,8 @@
                 CASE1(DECORATION, Decoration::XfbBuffer, TransformFeedback),
                 CASE1(DECORATION, Decoration::XfbStride, TransformFeedback),
                 CASE1(DECORATION, Decoration::FuncParamAttr, Kernel),
-                CASE1(DECORATION, Decoration::FPFastMathMode, Kernel),
+                CASE2(DECORATION, Decoration::FPFastMathMode, Kernel,
+                      FloatControls2),
                 CASE1(DECORATION, Decoration::LinkageAttributes, Linkage),
                 CASE1(DECORATION, Decoration::NoContraction, Shader),
                 CASE1(DECORATION, Decoration::InputAttachmentIndex,
@@ -469,6 +500,13 @@
                 CASE1(DECORATION, Decoration::Alignment, Kernel),
             })));
 
+// See SPIR-V Section 3.20 Decoration
+INSTANTIATE_TEST_SUITE_P(Decoration_1_6, EnumCapabilityTest,
+                         Combine(Values(SPV_ENV_UNIVERSAL_1_6),
+                                 ValuesIn(std::vector<EnumCapabilityCase>{
+                                     CASE2(DECORATION, Decoration::Uniform,
+                                           Shader, UniformDecoration)})));
+
 #if 0
 // SpecId has different requirements in v1.0 and v1.1:
 INSTANTIATE_TEST_SUITE_P(DecorationSpecIdV10, EnumCapabilityTest,
diff --git a/third_party/SPIRV-Tools/test/opt/CMakeLists.txt b/third_party/SPIRV-Tools/test/opt/CMakeLists.txt
index 3b2d384..92d266b 100644
--- a/third_party/SPIRV-Tools/test/opt/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/test/opt/CMakeLists.txt
@@ -66,6 +66,7 @@
        instruction_list_test.cpp
        instruction_test.cpp
        interface_var_sroa_test.cpp
+       invocation_interlock_placement_test.cpp
        interp_fixup_test.cpp
        ir_builder.cpp
        ir_context_test.cpp
@@ -77,6 +78,7 @@
        local_single_block_elim.cpp
        local_single_store_elim_test.cpp
        local_ssa_elim_test.cpp
+       modify_maximal_reconvergence_test.cpp
        module_test.cpp
        module_utils.h
        optimizer_test.cpp
@@ -103,6 +105,8 @@
        strip_debug_info_test.cpp
        strip_nonsemantic_info_test.cpp
        struct_cfg_analysis_test.cpp
+       switch_descriptorset_test.cpp
+       trim_capabilities_pass_test.cpp
        type_manager_test.cpp
        types_test.cpp
        unify_const_test.cpp
@@ -115,3 +119,12 @@
   LIBS SPIRV-Tools-opt
   PCH_FILE pch_test_opt
 )
+if (NOT "${SPIRV_SKIP_TESTS}" AND TARGET gmock_main)
+  if (MSVC)
+    if (${MSVC_VERSION} LESS 1920)
+      # The VS 2017 debug build requires /bigobj on test_opt
+      # https://github.com/KhronosGroup/SPIRV-Tools/issues/5335
+      target_compile_options(test_opt PRIVATE /bigobj)
+    endif()
+  endif()
+endif()
diff --git a/third_party/SPIRV-Tools/test/opt/aggressive_dead_code_elim_test.cpp b/third_party/SPIRV-Tools/test/opt/aggressive_dead_code_elim_test.cpp
index 83aab3c..845c6a5 100644
--- a/third_party/SPIRV-Tools/test/opt/aggressive_dead_code_elim_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/aggressive_dead_code_elim_test.cpp
@@ -6764,7 +6764,7 @@
          %60 = OpExtInst %void %1 DebugTypeVector %59 %uint_4
          %58 = OpExtInst %void %1 DebugTypeMember %10 %60 %55 %uint_12 %uint_5 %uint_0 %uint_128 %uint_3
          %57 = OpExtInst %void %1 DebugTypeComposite %8 %uint_1 %55 %uint_10 %uint_1 %56 %8 %uint_128 %uint_3 %58
-         %63 = OpExtInst %void %1 DebugTypeVector %59 %uint_2 
+         %63 = OpExtInst %void %1 DebugTypeVector %59 %uint_2
          %62 = OpExtInst %void %1 DebugTypeMember %12 %63 %55 %uint_7 %uint_5 %uint_0 %uint_64 %uint_3
          %61 = OpExtInst %void %1 DebugTypeComposite %11 %uint_1 %55 %uint_5 %uint_1 %56 %11 %uint_64 %uint_3 %62
          %64 = OpExtInst %void %1 DebugTypeComposite %13 %uint_0 %55 %uint_0 %uint_0 %56 %14 %51 %uint_3
@@ -7884,6 +7884,114 @@
   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
 }
 
+TEST_F(AggressiveDCETest, FunctionReturnPointer) {
+  // Run DCE when a function returning a pointer to a reference is present
+
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability PhysicalStorageBufferAddresses
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel PhysicalStorageBuffer64 GLSL450
+               OpEntryPoint Vertex %2 "main" %3 %4
+               OpSource GLSL 450
+               OpSourceExtension "GL_EXT_buffer_reference"
+               OpSourceExtension "GL_EXT_scalar_block_layout"
+               OpName %4 "color"
+               OpMemberDecorate %5 0 Offset 0
+               OpDecorate %5 Block
+               OpMemberDecorate %7 0 Offset 0
+               OpDecorate %7 Block
+               OpDecorate %8 AliasedPointer
+               OpDecorate %4 Location 0
+          %9 = OpTypeVoid
+         %10 = OpTypeFunction %9
+               OpTypeForwardPointer %11 PhysicalStorageBuffer
+         %12 = OpTypeInt 32 0
+          %5 = OpTypeStruct %12
+         %11 = OpTypePointer PhysicalStorageBuffer %5
+;CHECK:         [[pt:%\w+]] = OpTypePointer PhysicalStorageBuffer {{%\w+}}
+         %13 = OpTypeFunction %11
+;CHECK:  [[pt_fn:%\w+]] = OpTypeFunction [[pt]]
+          %7 = OpTypeStruct %11
+         %14 = OpTypePointer PushConstant %7
+          %3 = OpVariable %14 PushConstant
+         %15 = OpTypeInt 32 1
+         %16 = OpConstant %15 0
+         %17 = OpTypePointer PushConstant %11
+         %18 = OpTypePointer Function %11
+         %19 = OpTypeFloat 32
+         %20 = OpTypeVector %19 4
+         %21 = OpTypePointer Output %20
+          %4 = OpVariable %21 Output
+         %22 = OpConstant %19 1
+         %23 = OpConstant %19 0
+         %24 = OpConstantComposite %20 %22 %23 %22 %22
+          %6 = OpFunction %11 None %13
+;CHECK:   [[fn:%\w+]] = OpFunction [[pt]] None [[pt_fn]]
+         %27 = OpLabel
+         %28 = OpAccessChain %17 %3 %16
+         %29 = OpLoad %11 %28
+               OpReturnValue %29
+               OpFunctionEnd
+          %2 = OpFunction %9 None %10
+         %25 = OpLabel
+          %8 = OpVariable %18 Function
+         %26 = OpFunctionCall %11 %6
+;CHECK:  {{%\w+}} = OpFunctionCall [[pt]] [[fn]]
+               OpStore %8 %26
+               OpStore %4 %24
+               OpReturn
+               OpFunctionEnd
+)";
+
+  // For physical storage buffer support
+  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
+}
+
+TEST_F(AggressiveDCETest, KeepBeginEndInvocationInterlock) {
+  // OpBeginInvocationInterlockEXT and OpEndInvocationInterlockEXT delimit a
+  // critical section. As such, they should be treated as if they have side
+  // effects and should not be removed.
+  const std::string test =
+      R"(OpCapability Shader
+OpCapability FragmentShaderSampleInterlockEXT
+OpExtension "SPV_EXT_fragment_shader_interlock"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %1 "main" %gl_FragCoord
+OpExecutionMode %1 OriginUpperLeft
+OpExecutionMode %1 SampleInterlockOrderedEXT
+OpDecorate %gl_FragCoord BuiltIn FragCoord
+%float = OpTypeFloat 32
+%float_0 = OpConstant %float 0
+%v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%void = OpTypeVoid
+%8 = OpTypeFunction %void
+%bool = OpTypeBool
+%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+%1 = OpFunction %void None %8
+%10 = OpLabel
+%11 = OpLoad %v4float %gl_FragCoord
+%12 = OpCompositeExtract %float %11 0
+%13 = OpFOrdGreaterThan %bool %12 %float_0
+OpSelectionMerge %14 None
+OpBranchConditional %13 %15 %16
+%15 = OpLabel
+OpBeginInvocationInterlockEXT
+OpBranch %14
+%16 = OpLabel
+OpBeginInvocationInterlockEXT
+OpBranch %14
+%14 = OpLabel
+OpEndInvocationInterlockEXT
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndCheck<AggressiveDCEPass>(test, test, true, true);
+}
+
 }  // namespace
 }  // namespace opt
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/amd_ext_to_khr.cpp b/third_party/SPIRV-Tools/test/opt/amd_ext_to_khr.cpp
index 3340e89..a520d60 100644
--- a/third_party/SPIRV-Tools/test/opt/amd_ext_to_khr.cpp
+++ b/third_party/SPIRV-Tools/test/opt/amd_ext_to_khr.cpp
@@ -26,15 +26,17 @@
 
 using ::testing::HasSubstr;
 
-std::string GetTest(std::string op_code, std::string new_op_code) {
+std::string GetTest(std::string op_code, std::string new_op_code,
+                    bool is_float = false) {
   const std::string text = R"(
 ; CHECK: OpCapability Shader
 ; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot"
 ; CHECK: OpFunction
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: [[undef:%\w+]] = OpUndef %uint
+; CHECK-NEXT: [[undef:%\w+]] = OpUndef %
 ; CHECK-NEXT: )" + new_op_code +
-                           R"( %uint %uint_3 Reduce [[undef]]
+                           " %" + (is_float ? "float" : "uint") +
+                           R"( %uint_3 Reduce [[undef]]
                OpCapability Shader
                OpCapability Groups
                OpExtension "SPV_AMD_shader_ballot"
@@ -44,12 +46,15 @@
        %void = OpTypeVoid
           %3 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+      %float = OpTypeFloat 32
      %uint_3 = OpConstant %uint 3
           %1 = OpFunction %void None %3
           %6 = OpLabel
-          %7 = OpUndef %uint
+          %7 = OpUndef %)" +
+                           (is_float ? "float" : "uint") + R"(
           %8 = )" + op_code +
-                           R"( %uint %uint_3 Reduce %7
+                           " %" + (is_float ? "float" : "uint") +
+                           R"( %uint_3 Reduce %7
                OpReturn
                OpFunctionEnd
 
@@ -64,7 +69,7 @@
 }
 TEST_F(AmdExtToKhrTest, ReplaceGroupFAddNonUniformAMD) {
   std::string text =
-      GetTest("OpGroupFAddNonUniformAMD", "OpGroupNonUniformFAdd");
+      GetTest("OpGroupFAddNonUniformAMD", "OpGroupNonUniformFAdd", true);
   SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
 }
 TEST_F(AmdExtToKhrTest, ReplaceGroupUMinNonUniformAMD) {
@@ -79,7 +84,7 @@
 }
 TEST_F(AmdExtToKhrTest, ReplaceGroupFMinNonUniformAMD) {
   std::string text =
-      GetTest("OpGroupFMinNonUniformAMD", "OpGroupNonUniformFMin");
+      GetTest("OpGroupFMinNonUniformAMD", "OpGroupNonUniformFMin", true);
   SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
 }
 TEST_F(AmdExtToKhrTest, ReplaceGroupUMaxNonUniformAMD) {
@@ -94,7 +99,7 @@
 }
 TEST_F(AmdExtToKhrTest, ReplaceGroupFMaxNonUniformAMD) {
   std::string text =
-      GetTest("OpGroupFMaxNonUniformAMD", "OpGroupNonUniformFMax");
+      GetTest("OpGroupFMaxNonUniformAMD", "OpGroupNonUniformFMax", true);
   SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
 }
 
diff --git a/third_party/SPIRV-Tools/test/opt/block_merge_test.cpp b/third_party/SPIRV-Tools/test/opt/block_merge_test.cpp
index 57c5061..331ce3a 100644
--- a/third_party/SPIRV-Tools/test/opt/block_merge_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/block_merge_test.cpp
@@ -1320,6 +1320,148 @@
   SinglePassRunAndMatch<BlockMergePass>(text, true);
 }
 
+TEST_F(BlockMergeTest, MaximalReconvergenceNoMeldToMerge) {
+  const std::string text = R"(
+                              OpCapability Shader
+                              OpCapability GroupNonUniformBallot
+                              OpCapability GroupNonUniformArithmetic
+                              OpExtension "SPV_KHR_maximal_reconvergence"
+                              OpMemoryModel Logical GLSL450
+                              OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID %output
+                              OpExecutionMode %main LocalSize 1 1 1
+                              OpExecutionMode %main MaximallyReconvergesKHR
+                              OpSource HLSL 660
+                              OpName %type_RWStructuredBuffer_uint "type.RWStructuredBuffer.uint"
+                              OpName %output "output"
+                              OpName %main "main"
+                              OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
+                              OpDecorate %output DescriptorSet 0
+                              OpDecorate %output Binding 0
+                              OpDecorate %_runtimearr_uint ArrayStride 4
+                              OpMemberDecorate %type_RWStructuredBuffer_uint 0 Offset 0
+                              OpDecorate %type_RWStructuredBuffer_uint Block
+                      %uint = OpTypeInt 32 0
+                      %bool = OpTypeBool
+                       %int = OpTypeInt 32 1
+                     %int_0 = OpConstant %int 0
+                     %int_1 = OpConstant %int 1
+               %_runtimearr_uint = OpTypeRuntimeArray %uint
+               %type_RWStructuredBuffer_uint = OpTypeStruct %_runtimearr_uint
+               %_ptr_StorageBuffer_type_RWStructuredBuffer_uint = OpTypePointer StorageBuffer %type_RWStructuredBuffer_uint
+                    %v3uint = OpTypeVector %uint 3
+               %_ptr_Input_v3uint = OpTypePointer Input %v3uint
+                      %void = OpTypeVoid
+                        %15 = OpTypeFunction %void
+                    %uint_3 = OpConstant %uint 3
+               %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+                    %output = OpVariable %_ptr_StorageBuffer_type_RWStructuredBuffer_uint StorageBuffer
+               %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
+                      %main = OpFunction %void None %15
+                        %18 = OpLabel
+                        %19 = OpLoad %v3uint %gl_GlobalInvocationID
+                              OpBranch %20
+                        %20 = OpLabel
+                              OpLoopMerge %21 %22 None
+; CHECK:                      OpLoopMerge [[merge:%\w+]] [[continue:%\w+]]
+                              OpBranch %23
+                        %23 = OpLabel
+                        %24 = OpCompositeExtract %uint %19 0
+                        %25 = OpGroupNonUniformBroadcastFirst %uint %uint_3 %24
+                        %26 = OpIEqual %bool %24 %25
+                              OpSelectionMerge %27 None
+                              OpBranchConditional %26 %28 %27
+                        %28 = OpLabel
+                        %29 = OpGroupNonUniformIAdd %int %uint_3 Reduce %int_1
+                        %30 = OpBitcast %uint %29
+                              OpBranch %21
+; CHECK:        [[t1:%\w+]] = OpGroupNonUniformIAdd %int %uint_3 Reduce %int_1
+; CHECK-NEXT:   [[t2:%\w+]] = OpBitcast %uint [[t1]]
+; CHECK-NEXT:                 OpBranch [[merge]]
+                        %27 = OpLabel
+                              OpBranch %22
+                        %22 = OpLabel
+                              OpBranch %20
+                        %21 = OpLabel
+                        %31 = OpAccessChain %_ptr_StorageBuffer_uint %output %int_0 %24
+                              OpStore %31 %30
+                              OpReturn
+                              OpFunctionEnd
+)";
+
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  SinglePassRunAndMatch<BlockMergePass>(text, true);
+}
+
+TEST_F(BlockMergeTest, NoMaximalReconvergenceMeldToMerge) {
+  const std::string text = R"(
+                              OpCapability Shader
+                              OpCapability GroupNonUniformBallot
+                              OpCapability GroupNonUniformArithmetic
+                              OpMemoryModel Logical GLSL450
+                              OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID %output
+                              OpExecutionMode %main LocalSize 1 1 1
+                              OpSource HLSL 660
+                              OpName %type_RWStructuredBuffer_uint "type.RWStructuredBuffer.uint"
+                              OpName %output "output"
+                              OpName %main "main"
+                              OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
+                              OpDecorate %output DescriptorSet 0
+                              OpDecorate %output Binding 0
+                              OpDecorate %_runtimearr_uint ArrayStride 4
+                              OpMemberDecorate %type_RWStructuredBuffer_uint 0 Offset 0
+                              OpDecorate %type_RWStructuredBuffer_uint Block
+                      %uint = OpTypeInt 32 0
+                      %bool = OpTypeBool
+                       %int = OpTypeInt 32 1
+                     %int_0 = OpConstant %int 0
+                     %int_1 = OpConstant %int 1
+               %_runtimearr_uint = OpTypeRuntimeArray %uint
+               %type_RWStructuredBuffer_uint = OpTypeStruct %_runtimearr_uint
+               %_ptr_StorageBuffer_type_RWStructuredBuffer_uint = OpTypePointer StorageBuffer %type_RWStructuredBuffer_uint
+                    %v3uint = OpTypeVector %uint 3
+               %_ptr_Input_v3uint = OpTypePointer Input %v3uint
+                      %void = OpTypeVoid
+                        %15 = OpTypeFunction %void
+                    %uint_3 = OpConstant %uint 3
+               %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+                    %output = OpVariable %_ptr_StorageBuffer_type_RWStructuredBuffer_uint StorageBuffer
+               %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
+                      %main = OpFunction %void None %15
+                        %18 = OpLabel
+                        %19 = OpLoad %v3uint %gl_GlobalInvocationID
+                              OpBranch %20
+                        %20 = OpLabel
+                              OpLoopMerge %21 %22 None
+; CHECK:                      OpLoopMerge [[merge:%\w+]] [[continue:%\w+]]
+                              OpBranch %23
+                        %23 = OpLabel
+                        %24 = OpCompositeExtract %uint %19 0
+                        %25 = OpGroupNonUniformBroadcastFirst %uint %uint_3 %24
+                        %26 = OpIEqual %bool %24 %25
+                              OpSelectionMerge %27 None
+                              OpBranchConditional %26 %28 %27
+                        %28 = OpLabel
+                        %29 = OpGroupNonUniformIAdd %int %uint_3 Reduce %int_1
+                        %30 = OpBitcast %uint %29
+                              OpBranch %21
+; CHECK:          [[merge]] = OpLabel
+; CHECK-NEXT:   [[t1:%\w+]] = OpGroupNonUniformIAdd %int %uint_3 Reduce %int_1
+; CHECK-NEXT:   [[t2:%\w+]] = OpBitcast %uint [[t1]]
+                        %27 = OpLabel
+                              OpBranch %22
+                        %22 = OpLabel
+                              OpBranch %20
+                        %21 = OpLabel
+                        %31 = OpAccessChain %_ptr_StorageBuffer_uint %output %int_0 %24
+                              OpStore %31 %30
+                              OpReturn
+                              OpFunctionEnd
+)";
+
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  SinglePassRunAndMatch<BlockMergePass>(text, true);
+}
+
 // TODO(greg-lunarg): Add tests to verify handling of these cases:
 //
 //    More complex control flow
diff --git a/third_party/SPIRV-Tools/test/opt/convert_relaxed_to_half_test.cpp b/third_party/SPIRV-Tools/test/opt/convert_relaxed_to_half_test.cpp
index 27330e1..c577404 100644
--- a/third_party/SPIRV-Tools/test/opt/convert_relaxed_to_half_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/convert_relaxed_to_half_test.cpp
@@ -1613,6 +1613,175 @@
   SinglePassRunAndCheck<ConvertToHalfPass>(test, test, true);
 }
 
+TEST_F(ConvertToHalfTest, PreserveImageOperandPrecision) {
+  // Ensure that a non-relaxed texture coordinate does not get relaxed nor
+  // converted to half precision if the image instruction is marked relaxed.
+
+  // Also ensure that a relaxed local variable does get converted to half
+  // precision before being passed to an image opeartor.
+
+  // #version 310 es
+  //
+  // precision mediump float;
+  //
+  // layout(location = 10) in highp vec4 vertex_uv01;
+  // layout(binding = 0, set = 3) uniform sampler2D materialParams_baseColorMap;
+  //
+  // layout(location = 0) out vec4 fragColor;
+  //
+  // void main() {
+  //   vec4 uv = vec4(2.0);
+  //   fragColor = texture(materialParams_baseColorMap, uv.xy);
+  //   fragColor = texture(materialParams_baseColorMap, vertex_uv01.xy);
+  // }
+  const std::string test = R"(
+               OpCapability Shader
+               OpCapability Float16
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %13 %25
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %9 RelaxedPrecision
+;CHECK: OpDecorate [[uv:%\w+]] RelaxedPrecision
+               OpDecorate %13 Location 0
+               OpDecorate %17 DescriptorSet 3
+               OpDecorate %17 Binding 0
+               OpDecorate %18 RelaxedPrecision
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %25 Location 10
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+;CHECK: [[float32_t:%\w+]] = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+;CHECK: [[vec4_t:%\w+]] = OpTypeVector [[float32_t]] 4
+          %8 = OpTypePointer Function %7
+         %10 = OpConstant %6 2
+         %11 = OpConstantComposite %7 %10 %10 %10 %10
+         %12 = OpTypePointer Output %7
+;CHECK: [[output_ptr_t:%\w+]] = OpTypePointer Output [[vec4_t]]
+         %13 = OpVariable %12 Output
+;CHECK: [[output:%\w+]] = OpVariable [[output_ptr_t]] Output
+         %14 = OpTypeImage %6 2D 0 0 0 1 Unknown
+         %15 = OpTypeSampledImage %14
+         %16 = OpTypePointer UniformConstant %15
+         %17 = OpVariable %16 UniformConstant
+         %19 = OpTypeVector %6 2
+;CHECK: [[vec2_t:%\w+]] = OpTypeVector [[float32_t]] 2
+         %24 = OpTypePointer Input %7
+;CHECK: [[input_ptr_t:%\w+]] = OpTypePointer Input [[vec4_t]]
+         %25 = OpVariable %24 Input
+         %29 = OpTypeFloat 16
+;CHECK: [[float16_t:%\w+]] = OpTypeFloat 16
+         %30 = OpTypeVector %29 4
+         %33 = OpTypeVector %29 2
+;CHECK: [[vec2_16b_t:%\w+]] = OpTypeVector [[float16_t]] 2
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+
+; The only Function storage variable is marked as relaxed
+          %9 = OpVariable %8 Function
+;CHECK: [[uv]] = OpVariable {{%\w+}} Function
+               OpStore %9 %11
+         %18 = OpLoad %15 %17
+         %20 = OpLoad %7 %9
+         %31 = OpFConvert %30 %20
+         %32 = OpFConvert %30 %20
+
+; The first sample op should get a 16b coordinate
+         %21 = OpVectorShuffle %33 %31 %32 0 1
+;CHECK: [[uv_16b:%\w+]] = OpVectorShuffle [[vec2_16b_t]]
+         %22 = OpImageSampleImplicitLod %7 %18 %21
+;CHECK: OpImageSampleImplicitLod [[vec4_t]] {{%\w+}} [[uv_16b]]
+
+               OpStore %13 %22
+         %23 = OpLoad %15 %17
+         %26 = OpLoad %7 %25
+
+; The second sample op should get a 32b coordinate
+         %27 = OpVectorShuffle %19 %26 %26 0 1
+;CHECK: [[uv_32b:%\w+]] = OpVectorShuffle [[vec2_t]]
+         %28 = OpImageSampleImplicitLod %7 %23 %27
+;CHECK: OpImageSampleImplicitLod [[vec4_t]] {{%\w+}} [[uv_32b]]
+
+               OpStore %13 %28
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  SinglePassRunAndMatch<ConvertToHalfPass>(test, true);
+}
+
+TEST_F(ConvertToHalfTest, DontRelaxDecoratedOpCompositeExtract) {
+  // This test checks that a OpCompositeExtract with a Struct operand won't be
+  // relaxed, even if it is explicitly decorated with RelaxedPrecision.
+  const std::string test =
+      R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %1 "main"
+OpExecutionMode %1 OriginUpperLeft
+OpDecorate %9 RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_struct_6 = OpTypeStruct %v4float
+%7 = OpUndef %_struct_6
+%1 = OpFunction %void None %3
+%8 = OpLabel
+%9 = OpCompositeExtract %float %7 0 3
+OpReturn
+OpFunctionEnd
+)";
+
+  const std::string expected =
+      R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %1 "main"
+OpExecutionMode %1 OriginUpperLeft
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_struct_6 = OpTypeStruct %v4float
+%7 = OpUndef %_struct_6
+%1 = OpFunction %void None %3
+%8 = OpLabel
+%9 = OpCompositeExtract %float %7 0 3
+OpReturn
+OpFunctionEnd
+)";
+
+  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndCheck<ConvertToHalfPass>(test, expected, true);
+}
+
+TEST_F(ConvertToHalfTest, DontRelaxOpCompositeExtract) {
+  // This test checks that a OpCompositeExtract with a Struct operand won't be
+  // relaxed, even if its result has no uses.
+  const std::string test =
+      R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %1 "main"
+OpExecutionMode %1 OriginUpperLeft
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_struct_6 = OpTypeStruct %v4float
+%7 = OpUndef %_struct_6
+%1 = OpFunction %void None %3
+%8 = OpLabel
+%9 = OpCompositeExtract %float %7 0 3
+OpReturn
+OpFunctionEnd
+)";
+
+  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndCheck<ConvertToHalfPass>(test, test, true);
+}
+
 }  // namespace
 }  // namespace opt
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/copy_prop_array_test.cpp b/third_party/SPIRV-Tools/test/opt/copy_prop_array_test.cpp
index 2d4b7a3..16719b8 100644
--- a/third_party/SPIRV-Tools/test/opt/copy_prop_array_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/copy_prop_array_test.cpp
@@ -1942,6 +1942,41 @@
 
   SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false);
 }
+
+// If the size of an array used in an OpCompositeInsert is not known at compile
+// time, then we should not propagate the array, because we do not have a single
+// array that represents the final value.
+TEST_F(CopyPropArrayPassTest, SpecConstSizedArray) {
+  const std::string text = R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %2 "main"
+OpExecutionMode %2 OriginUpperLeft
+%void = OpTypeVoid
+%4 = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%uint = OpTypeInt 32 0
+%7 = OpSpecConstant %uint 32
+%_arr_int_7 = OpTypeArray %int %7
+%int_63 = OpConstant %int 63
+%uint_0 = OpConstant %uint 0
+%bool = OpTypeBool
+%int_0 = OpConstant %int 0
+%int_587202566 = OpConstant %int 587202566
+%false = OpConstantFalse %bool
+%_ptr_Function__arr_int_7 = OpTypePointer Function %_arr_int_7
+%16 = OpUndef %_arr_int_7
+%2 = OpFunction %void None %4
+%17 = OpLabel
+%18 = OpVariable %_ptr_Function__arr_int_7 Function
+%19 = OpCompositeInsert %_arr_int_7 %int_0 %16 0
+OpStore %18 %19
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false);
+}
 }  // namespace
 }  // namespace opt
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/dead_insert_elim_test.cpp b/third_party/SPIRV-Tools/test/opt/dead_insert_elim_test.cpp
index 268e659..fcc3dde 100644
--- a/third_party/SPIRV-Tools/test/opt/dead_insert_elim_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/dead_insert_elim_test.cpp
@@ -736,6 +736,113 @@
   SinglePassRunAndMatch<DeadInsertElimPass>(text, true);
 }
 
+TEST_F(DeadInsertElimTest, PhiOverEmptyStruct) {
+  // Reproducer for nullptr access error in MarkInsertChain
+  // that occurs when processing a phi operation with an
+  // empty struct result type.
+  //
+  // Note: Disassembly created from HLSL source with
+  // dxc -T cs_6_6 -spirv -Oconfig=
+  //  --eliminate-dead-branches,--merge-return,--ssa-rewrite
+  //
+  // RWBuffer<float> buf;
+  //
+  // struct S { };
+  //
+  // S fn() {
+  //     S s = (S)0;
+  //     if (buf[0] > 0) {
+  //         return s;
+  //     }
+  //     return s;
+  // }
+  //
+  // [numthreads(1,1,1)]
+  // void main() {
+  //     fn();
+  // }
+
+  const std::string disassembly =
+      R"(OpCapability Shader
+               OpCapability SampledBuffer
+               OpCapability ImageBuffer
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource HLSL 660
+               OpName %S "S"
+               OpName %type_buffer_image "type.buffer.image"
+               OpName %buf "buf"
+               OpName %main "main"
+               OpName %src_main "src.main"
+               OpName %bb_entry "bb.entry"
+               OpName %fn "fn"
+               OpName %bb_entry_0 "bb.entry"
+               OpName %s "s"
+               OpName %if_true "if.true"
+               OpName %if_merge "if.merge"
+               OpDecorate %buf DescriptorSet 0
+               OpDecorate %buf Binding 0
+          %S = OpTypeStruct
+          %4 = OpConstantNull %S
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+      %float = OpTypeFloat 32
+    %float_0 = OpConstant %float 0
+%type_buffer_image = OpTypeImage %float Buffer 2 0 0 2 R32f
+%_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+         %19 = OpTypeFunction %S
+%_ptr_Function_S = OpTypePointer Function %S
+    %v4float = OpTypeVector %float 4
+       %bool = OpTypeBool
+        %buf = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant
+      %false = OpConstantFalse %bool
+%_ptr_Function_bool = OpTypePointer Function %bool
+       %true = OpConstantTrue %bool
+       %main = OpFunction %void None %12
+         %13 = OpLabel
+         %14 = OpFunctionCall %void %src_main
+               OpReturn
+               OpFunctionEnd
+   %src_main = OpFunction %void None %12
+   %bb_entry = OpLabel
+         %17 = OpFunctionCall %S %fn
+               OpReturn
+               OpFunctionEnd
+         %fn = OpFunction %S None %19
+ %bb_entry_0 = OpLabel
+         %39 = OpVariable %_ptr_Function_bool Function %false
+         %34 = OpVariable %_ptr_Function_S Function
+          %s = OpVariable %_ptr_Function_S Function
+               OpSelectionMerge %33 None
+               OpSwitch %uint_0 %36
+         %36 = OpLabel
+               OpStore %s %4
+         %23 = OpLoad %type_buffer_image %buf
+         %25 = OpImageRead %v4float %23 %uint_0 None
+         %26 = OpCompositeExtract %float %25 0
+         %28 = OpFOrdGreaterThan %bool %26 %float_0
+               OpSelectionMerge %if_merge None
+               OpBranchConditional %28 %if_true %if_merge
+    %if_true = OpLabel
+               OpStore %39 %true
+               OpStore %34 %4
+               OpBranch %33
+   %if_merge = OpLabel
+               OpStore %39 %true
+               OpStore %34 %4
+               OpBranch %33
+         %33 = OpLabel
+         %41 = OpPhi %S %4 %if_true %4 %if_merge
+               OpReturnValue %41
+               OpFunctionEnd
+)";
+  // Used to crash with a nullptr access violation when processing %41
+  SinglePassRunToBinary<DeadInsertElimPass>(disassembly, true);
+}
+
 // TODO(greg-lunarg): Add tests to verify handling of these cases:
 //
 
diff --git a/third_party/SPIRV-Tools/test/opt/desc_sroa_test.cpp b/third_party/SPIRV-Tools/test/opt/desc_sroa_test.cpp
index 7a118f9..5c166d8 100644
--- a/third_party/SPIRV-Tools/test/opt/desc_sroa_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/desc_sroa_test.cpp
@@ -918,6 +918,74 @@
   SinglePassRunAndMatch<DescriptorScalarReplacement>(shader, true);
 }
 
+TEST_F(DescriptorScalarReplacementTest, ExpandArrayInOpEntryPoint) {
+  const std::string text = R"(; SPIR-V
+; Version: 1.6
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+
+; CHECK:       OpEntryPoint GLCompute %main "main" %output_0_ %output_1_
+
+               OpEntryPoint GLCompute %main "main" %output
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource HLSL 670
+               OpName %type_RWByteAddressBuffer "type.RWByteAddressBuffer"
+               OpName %output "output"
+               OpName %main "main"
+               OpName %src_main "src.main"
+               OpName %bb_entry "bb.entry"
+
+; CHECK:       OpDecorate %output_1_ DescriptorSet 0
+; CHECK:       OpDecorate %output_1_ Binding 1
+; CHECK:       OpDecorate %output_0_ DescriptorSet 0
+; CHECK:       OpDecorate %output_0_ Binding 0
+
+               OpDecorate %output DescriptorSet 0
+               OpDecorate %output Binding 0
+
+               OpDecorate %_runtimearr_uint ArrayStride 4
+               OpMemberDecorate %type_RWByteAddressBuffer 0 Offset 0
+               OpDecorate %type_RWByteAddressBuffer Block
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+    %uint_32 = OpConstant %uint 32
+%_runtimearr_uint = OpTypeRuntimeArray %uint
+%type_RWByteAddressBuffer = OpTypeStruct %_runtimearr_uint
+%_arr_type_RWByteAddressBuffer_uint_2 = OpTypeArray %type_RWByteAddressBuffer %uint_2
+%_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 = OpTypePointer StorageBuffer %_arr_type_RWByteAddressBuffer_uint_2
+       %void = OpTypeVoid
+         %23 = OpTypeFunction %void
+%_ptr_StorageBuffer_type_RWByteAddressBuffer = OpTypePointer StorageBuffer %type_RWByteAddressBuffer
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+
+; CHECK: %output_1_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer
+; CHECK: %output_0_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer
+
+     %output = OpVariable %_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 StorageBuffer
+
+       %main = OpFunction %void None %23
+         %26 = OpLabel
+         %27 = OpFunctionCall %void %src_main
+               OpReturn
+               OpFunctionEnd
+   %src_main = OpFunction %void None %23
+   %bb_entry = OpLabel
+         %28 = OpAccessChain %_ptr_StorageBuffer_type_RWByteAddressBuffer %output %int_1
+         %29 = OpShiftRightLogical %uint %uint_0 %uint_2
+         %30 = OpAccessChain %_ptr_StorageBuffer_uint %28 %uint_0 %29
+               OpStore %30 %uint_32
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  SinglePassRunAndMatch<DescriptorScalarReplacement>(text, false);
+}
+
 }  // namespace
 }  // namespace opt
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/feature_manager_test.cpp b/third_party/SPIRV-Tools/test/opt/feature_manager_test.cpp
index a5105a9..7e8f92c 100644
--- a/third_party/SPIRV-Tools/test/opt/feature_manager_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/feature_manager_test.cpp
@@ -87,6 +87,25 @@
       Extension::kSPV_KHR_storage_buffer_storage_class));
 }
 
+TEST_F(FeatureManagerTest, GetExtensionsReturnsExtensions) {
+  const std::string text = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpExtension "SPV_KHR_variable_pointers"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+  )";
+
+  std::unique_ptr<IRContext> context =
+      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
+  ASSERT_NE(context, nullptr);
+
+  const auto& extensions = context->get_feature_mgr()->GetExtensions();
+  EXPECT_EQ(extensions.size(), 2);
+  EXPECT_TRUE(extensions.contains(Extension::kSPV_KHR_variable_pointers));
+  EXPECT_TRUE(
+      extensions.contains(Extension::kSPV_KHR_storage_buffer_storage_class));
+}
+
 // Test capability checks.
 TEST_F(FeatureManagerTest, ExplicitlyPresent1) {
   const std::string text = R"(
@@ -142,6 +161,24 @@
       context->get_feature_mgr()->HasCapability(spv::Capability::Kernel));
 }
 
+TEST_F(FeatureManagerTest, GetCapabilitiesReturnsImplicitCapabilities) {
+  const std::string text = R"(
+OpCapability Tessellation
+OpMemoryModel Logical GLSL450
+  )";
+
+  std::unique_ptr<IRContext> context =
+      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
+  ASSERT_NE(context, nullptr);
+
+  const auto& capabilities = context->get_feature_mgr()->GetCapabilities();
+  // Tesselation implies Shader, which implies Matrix.
+  EXPECT_EQ(capabilities.size(), 3);
+  EXPECT_TRUE(capabilities.contains(spv::Capability::Tessellation));
+  EXPECT_TRUE(capabilities.contains(spv::Capability::Shader));
+  EXPECT_TRUE(capabilities.contains(spv::Capability::Matrix));
+}
+
 }  // namespace
 }  // namespace opt
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/fix_storage_class_test.cpp b/third_party/SPIRV-Tools/test/opt/fix_storage_class_test.cpp
index 93ce873..684e006 100644
--- a/third_party/SPIRV-Tools/test/opt/fix_storage_class_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/fix_storage_class_test.cpp
@@ -874,6 +874,47 @@
 
   SinglePassRunAndMatch<FixStorageClass>(text, false);
 }
+TEST_F(FixStorageClassTest, SupportsU64Index) {
+  const std::string text = R"(
+; CHECK: OpAccessChain %_ptr_Uniform_float
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "testMain" %gl_LocalInvocationID
+               OpExecutionMode %1 LocalSize 8 8 1
+               OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
+               OpDecorate %8 DescriptorSet 0
+               OpDecorate %8 Binding 0
+               OpDecorate %_runtimearr_float ArrayStride 4
+               OpMemberDecorate %_struct_7 0 Offset 0
+               OpDecorate %_struct_7 BufferBlock
+      %ulong = OpTypeInt 64 0
+    %ulong_0 = OpConstant %ulong 0
+      %float = OpTypeFloat 32
+  %float_123 = OpConstant %float 123
+       %uint = OpTypeInt 32 0
+    %uint_10 = OpConstant %uint 10
+%_runtimearr_float = OpTypeRuntimeArray %float
+  %_struct_7 = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7
+     %v3uint = OpTypeVector %uint 3
+%_ptr_Input_v3uint = OpTypePointer Input %v3uint
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %8 = OpVariable %_ptr_Uniform__struct_7 Uniform
+%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
+          %1 = OpFunction %void None %30
+         %38 = OpLabel
+         %44 = OpLoad %v3uint %gl_LocalInvocationID
+         %59 = OpCompositeExtract %uint %44 0
+         %60 = OpAccessChain %_ptr_Uniform_float %8 %ulong_0 %59
+               OpStore %60 %float_123
+               OpReturn
+               OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<FixStorageClass>(text, false);
+}
 
 }  // namespace
 }  // namespace opt
diff --git a/third_party/SPIRV-Tools/test/opt/fold_spec_const_op_composite_test.cpp b/third_party/SPIRV-Tools/test/opt/fold_spec_const_op_composite_test.cpp
index f83e86e..335e0f5 100644
--- a/third_party/SPIRV-Tools/test/opt/fold_spec_const_op_composite_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/fold_spec_const_op_composite_test.cpp
@@ -674,6 +674,31 @@
   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
 }
 
+// Silently ignore spec constants that cannot be folded
+TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, UnfoldableOp) {
+  const std::string test = R"(
+               OpCapability Shader
+               OpCapability SignedZeroInfNanPreserve
+               OpExtension "SPV_KHR_float_controls"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main"
+               OpSource GLSL 450
+               OpDecorate %v SpecId 1
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %float = OpTypeFloat 32
+          %v = OpConstant %float 0x1p-1
+%c = OpSpecConstantOp %float QuantizeToF16 %v
+;CHECK: {{%\w+}} = OpSpecConstantOp {{%\w+}} QuantizeToF16 {{%\w+}}
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
+}
+
 // All types and some common constants that are potentially required in
 // FoldSpecConstantOpAndCompositeTest.
 std::vector<std::string> CommonTypesAndConstants() {
@@ -1033,14 +1058,8 @@
               },
               // expected
               {
-                "%true = OpConstantTrue %bool",
-                "%true_0 = OpConstantTrue %bool",
                 "%spec_bool_t_vec = OpConstantComposite %v2bool %bool_true %bool_true",
-                "%false = OpConstantFalse %bool",
-                "%false_0 = OpConstantFalse %bool",
                 "%spec_bool_f_vec = OpConstantComposite %v2bool %bool_false %bool_false",
-                "%false_1 = OpConstantFalse %bool",
-                "%false_2 = OpConstantFalse %bool",
                 "%spec_bool_from_null = OpConstantComposite %v2bool %bool_false %bool_false",
               },
             },
@@ -1055,14 +1074,8 @@
               },
               // expected
               {
-                "%true = OpConstantTrue %bool",
-                "%true_0 = OpConstantTrue %bool",
                 "%spec_bool_t_vec = OpConstantComposite %v2bool %bool_true %bool_true",
-                "%false = OpConstantFalse %bool",
-                "%false_0 = OpConstantFalse %bool",
                 "%spec_bool_f_vec = OpConstantComposite %v2bool %bool_false %bool_false",
-                "%false_1 = OpConstantFalse %bool",
-                "%false_2 = OpConstantFalse %bool",
                 "%spec_bool_from_null = OpConstantComposite %v2bool %bool_false %bool_false",
               },
             },
@@ -1077,14 +1090,8 @@
               },
               // expected
               {
-                "%int_1 = OpConstant %int 1",
-                "%int_1_0 = OpConstant %int 1",
                 "%spec_int_one_vec = OpConstantComposite %v2int %signed_one %signed_one",
-                "%int_0 = OpConstant %int 0",
-                "%int_0_0 = OpConstant %int 0",
                 "%spec_int_zero_vec = OpConstantComposite %v2int %signed_zero %signed_zero",
-                "%int_0_1 = OpConstant %int 0",
-                "%int_0_2 = OpConstant %int 0",
                 "%spec_int_from_null = OpConstantComposite %v2int %signed_zero %signed_zero",
               },
             },
@@ -1099,14 +1106,8 @@
               },
               // expected
               {
-                "%int_1 = OpConstant %int 1",
-                "%int_1_0 = OpConstant %int 1",
                 "%spec_int_one_vec = OpConstantComposite %v2int %signed_one %signed_one",
-                "%int_0 = OpConstant %int 0",
-                "%int_0_0 = OpConstant %int 0",
                 "%spec_int_zero_vec = OpConstantComposite %v2int %signed_zero %signed_zero",
-                "%int_0_1 = OpConstant %int 0",
-                "%int_0_2 = OpConstant %int 0",
                 "%spec_int_from_null = OpConstantComposite %v2int %signed_zero %signed_zero",
               },
             },
@@ -1121,14 +1122,8 @@
               },
               // expected
               {
-                "%uint_1 = OpConstant %uint 1",
-                "%uint_1_0 = OpConstant %uint 1",
                 "%spec_uint_one_vec = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
-                "%uint_0 = OpConstant %uint 0",
-                "%uint_0_0 = OpConstant %uint 0",
                 "%spec_uint_zero_vec = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
-                "%uint_0_1 = OpConstant %uint 0",
-                "%uint_0_2 = OpConstant %uint 0",
                 "%spec_uint_from_null = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
               },
             },
@@ -1143,14 +1138,8 @@
               },
               // expected
               {
-                "%uint_1 = OpConstant %uint 1",
-                "%uint_1_0 = OpConstant %uint 1",
                 "%spec_uint_one_vec = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
-                "%uint_0 = OpConstant %uint 0",
-                "%uint_0_0 = OpConstant %uint 0",
                 "%spec_uint_zero_vec = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
-                "%uint_0_1 = OpConstant %uint 0",
-                "%uint_0_2 = OpConstant %uint 0",
                 "%spec_uint_from_null = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
               },
             },
@@ -1159,8 +1148,6 @@
             {
               // original
               {
-                "%spec_uint_zero = OpSpecConstantOp %uint UConvert %bool_false",
-                "%spec_uint_one = OpSpecConstantOp %uint UConvert %bool_true",
                 "%spec_ulong_zero = OpSpecConstantOp %ulong UConvert %unsigned_zero",
                 "%spec_ulong_one = OpSpecConstantOp %ulong UConvert %unsigned_one",
                 "%spec_short_zero = OpSpecConstantOp %ushort UConvert %unsigned_zero",
@@ -1172,8 +1159,6 @@
               },
               // expected
               {
-                "%spec_uint_zero = OpConstant %uint 0",
-                "%spec_uint_one = OpConstant %uint 1",
                 "%spec_ulong_zero = OpConstant %ulong 0",
                 "%spec_ulong_one = OpConstant %ulong 1",
                 "%spec_short_zero = OpConstant %ushort 0",
@@ -1211,24 +1196,13 @@
             {
               // original
               {
-                "%spec_v2uint_zero = OpSpecConstantOp %v2uint UConvert %bool_false_vec",
-                "%spec_v2uint_one = OpSpecConstantOp %v2uint UConvert %bool_true_vec",
                 "%spec_v2ulong_zero = OpSpecConstantOp %v2ulong UConvert %unsigned_zero_vec",
                 "%spec_v2ulong_one = OpSpecConstantOp %v2ulong UConvert %unsigned_one_vec",
               },
               // expected
               {
-                "%uint_0 = OpConstant %uint 0",
-                "%uint_0_0 = OpConstant %uint 0",
-                "%spec_v2uint_zero = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
-                "%uint_1 = OpConstant %uint 1",
-                "%uint_1_0 = OpConstant %uint 1",
-                "%spec_v2uint_one = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
-                "%ulong_0 = OpConstant %ulong 0",
-                "%ulong_0_0 = OpConstant %ulong 0",
                 "%spec_v2ulong_zero = OpConstantComposite %v2ulong %ulong_zero %ulong_zero",
                 "%ulong_1 = OpConstant %ulong 1",
-                "%ulong_1_0 = OpConstant %ulong 1",
                 "%spec_v2ulong_one = OpConstantComposite %v2ulong %ulong_1 %ulong_1",
               },
             },
@@ -1243,14 +1217,10 @@
               },
               // expected
               {
-                "%long_0 = OpConstant %long 0",
-                "%long_0_0 = OpConstant %long 0",
                 "%spec_v2long_zero = OpConstantComposite %v2long %long_zero %long_zero",
                 "%long_1 = OpConstant %long 1",
-                "%long_1_0 = OpConstant %long 1",
                 "%spec_v2long_one = OpConstantComposite %v2long %long_1 %long_1",
                 "%long_n1 = OpConstant %long -1",
-                "%long_n1_0 = OpConstant %long -1",
                 "%spec_v2long_minus_one = OpConstantComposite %v2long %long_n1 %long_n1",
               },
             },
@@ -1347,7 +1317,7 @@
               {
                 "%int_minus_1 = OpConstant %int -1",
                 "%int_minus_2 = OpConstant %int -2",
-                "%int_neg_null = OpConstant %int 0",
+                "%int_neg_null = OpConstantNull %int",
                 "%int_max = OpConstant %int 2147483647",
                 "%int_neg_max = OpConstant %int -2147483647",
               },
@@ -1528,15 +1498,10 @@
               },
               // expected
               {
-                "%int_n1 = OpConstant %int -1",
-                "%int_n1_0 = OpConstant %int -1",
                 "%v2int_minus_1 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
                 "%int_n2 = OpConstant %int -2",
-                "%int_n2_0 = OpConstant %int -2",
                 "%v2int_minus_2 = OpConstantComposite %v2int %int_n2 %int_n2",
-                "%int_0 = OpConstant %int 0",
-                "%int_0_0 = OpConstant %int 0",
-                "%v2int_neg_null = OpConstantComposite %v2int %signed_zero %signed_zero",
+                "%v2int_neg_null = OpConstantComposite %v2int %signed_null %signed_null",
               },
             },
             // vector integer (including null vetors) add, sub, div, mul
@@ -1558,35 +1523,23 @@
               // expected
               {
                 "%int_5 = OpConstant %int 5",
-                "%int_5_0 = OpConstant %int 5",
                 "%spec_v2int_iadd = OpConstantComposite %v2int %int_5 %int_5",
                 "%int_n4 = OpConstant %int -4",
-                "%int_n4_0 = OpConstant %int -4",
                 "%spec_v2int_isub = OpConstantComposite %v2int %int_n4 %int_n4",
                 "%int_n2 = OpConstant %int -2",
-                "%int_n2_0 = OpConstant %int -2",
                 "%spec_v2int_sdiv = OpConstantComposite %v2int %int_n2 %int_n2",
                 "%int_n6 = OpConstant %int -6",
-                "%int_n6_0 = OpConstant %int -6",
                 "%spec_v2int_imul = OpConstantComposite %v2int %int_n6 %int_n6",
-                "%int_n6_1 = OpConstant %int -6",
-                "%int_n6_2 = OpConstant %int -6",
                 "%spec_v2int_iadd_null = OpConstantComposite %v2int %int_n6 %int_n6",
 
                 "%uint_5 = OpConstant %uint 5",
-                "%uint_5_0 = OpConstant %uint 5",
                 "%spec_v2uint_iadd = OpConstantComposite %v2uint %uint_5 %uint_5",
                 "%uint_4294967292 = OpConstant %uint 4294967292",
-                "%uint_4294967292_0 = OpConstant %uint 4294967292",
                 "%spec_v2uint_isub = OpConstantComposite %v2uint %uint_4294967292 %uint_4294967292",
                 "%uint_1431655764 = OpConstant %uint 1431655764",
-                "%uint_1431655764_0 = OpConstant %uint 1431655764",
                 "%spec_v2uint_udiv = OpConstantComposite %v2uint %uint_1431655764 %uint_1431655764",
                 "%uint_2863311528 = OpConstant %uint 2863311528",
-                "%uint_2863311528_0 = OpConstant %uint 2863311528",
                 "%spec_v2uint_imul = OpConstantComposite %v2uint %uint_2863311528 %uint_2863311528",
-                "%uint_2863311528_1 = OpConstant %uint 2863311528",
-                "%uint_2863311528_2 = OpConstant %uint 2863311528",
                 "%spec_v2uint_isub_null = OpConstantComposite %v2uint %uint_2863311528 %uint_2863311528",
               },
             },
@@ -1630,34 +1583,17 @@
                 "%v2int_minus_3 = OpConstantComposite %v2int %int_minus_3 %int_minus_3",
 
                 // srem
-                "%int_1 = OpConstant %int 1",
-                "%int_1_0 = OpConstant %int 1",
                 "%7_srem_3 = OpConstantComposite %v2int %signed_one %signed_one",
-                "%int_n1 = OpConstant %int -1",
-                "%int_n1_0 = OpConstant %int -1",
                 "%minus_7_srem_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
-                "%int_1_1 = OpConstant %int 1",
-                "%int_1_2 = OpConstant %int 1",
                 "%7_srem_minus_3 = OpConstantComposite %v2int %signed_one %signed_one",
-                "%int_n1_1 = OpConstant %int -1",
-                "%int_n1_2 = OpConstant %int -1",
                 "%minus_7_srem_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
                 // smod
-                "%int_1_3 = OpConstant %int 1",
-                "%int_1_4 = OpConstant %int 1",
                 "%7_smod_3 = OpConstantComposite %v2int %signed_one %signed_one",
-                "%int_2 = OpConstant %int 2",
-                "%int_2_0 = OpConstant %int 2",
                 "%minus_7_smod_3 = OpConstantComposite %v2int %signed_two %signed_two",
                 "%int_n2 = OpConstant %int -2",
-                "%int_n2_0 = OpConstant %int -2",
                 "%7_smod_minus_3 = OpConstantComposite %v2int %int_n2 %int_n2",
-                "%int_n1_3 = OpConstant %int -1",
-                "%int_n1_4 = OpConstant %int -1",
                 "%minus_7_smod_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
                 // umod
-                "%uint_1 = OpConstant %uint 1",
-                "%uint_1_0 = OpConstant %uint 1",
                 "%7_umod_3 = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
               },
             },
@@ -1677,26 +1613,15 @@
               },
               // expected
               {
-                "%int_2 = OpConstant %int 2",
-                "%int_2_0 = OpConstant %int 2",
                 "%xor_1_3 = OpConstantComposite %v2int %signed_two %signed_two",
-                "%int_0 = OpConstant %int 0",
-                "%int_0_0 = OpConstant %int 0",
                 "%and_1_2 = OpConstantComposite %v2int %signed_zero %signed_zero",
-                "%int_3 = OpConstant %int 3",
-                "%int_3_0 = OpConstant %int 3",
                 "%or_1_2 = OpConstantComposite %v2int %signed_three %signed_three",
 
                 "%unsigned_31 = OpConstant %uint 31",
                 "%v2unsigned_31 = OpConstantComposite %v2uint %unsigned_31 %unsigned_31",
                 "%uint_2147483648 = OpConstant %uint 2147483648",
-                "%uint_2147483648_0 = OpConstant %uint 2147483648",
                 "%unsigned_left_shift_max = OpConstantComposite %v2uint %uint_2147483648 %uint_2147483648",
-                "%uint_1 = OpConstant %uint 1",
-                "%uint_1_0 = OpConstant %uint 1",
                 "%unsigned_right_shift_logical = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
-                "%int_n1 = OpConstant %int -1",
-                "%int_n1_0 = OpConstant %int -1",
                 "%signed_right_shift_arithmetic = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
               },
             },
@@ -2066,7 +1991,6 @@
               "%spec_int_20 = OpConstant %int 101",
               "%used_vec_a = OpConstantComposite %v2int %spec_int_18 %spec_int_19",
               "%int_10201 = OpConstant %int 10201",
-              "%int_1 = OpConstant %int 1",
               "%used_vec_b = OpConstantComposite %v2int %int_10201 %signed_one",
               "%spec_int_21 = OpConstant %int 10201",
               "%array = OpConstantComposite %type_arr_int_4 %spec_int_20 %spec_int_20 %spec_int_21 %spec_int_21",
diff --git a/third_party/SPIRV-Tools/test/opt/fold_test.cpp b/third_party/SPIRV-Tools/test/opt/fold_test.cpp
index eff8edf..a4e0447 100644
--- a/third_party/SPIRV-Tools/test/opt/fold_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/fold_test.cpp
@@ -16,7 +16,6 @@
 #include <limits>
 #include <memory>
 #include <string>
-#include <unordered_set>
 #include <vector>
 
 #include "effcee/effcee.h"
@@ -67,42 +66,136 @@
   ResultType expected_result;
 };
 
+std::tuple<std::unique_ptr<IRContext>, Instruction*> GetInstructionToFold(
+    const std::string test_body, const uint32_t id_to_fold,
+    spv_target_env spv_env) {
+  // Build module.
+  std::unique_ptr<IRContext> context =
+      BuildModule(spv_env, nullptr, test_body,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  EXPECT_NE(nullptr, context);
+  if (context == nullptr) {
+    return {nullptr, nullptr};
+  }
+
+  // Fold the instruction to test.
+  if (id_to_fold != 0) {
+    analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
+    Instruction* inst = def_use_mgr->GetDef(id_to_fold);
+    return {std::move(context), inst};
+  }
+
+  // If there is not ID, we get the instruction just before a terminator
+  // instruction. That could be a return or abort. This is used for cases where
+  // the instruction we want to fold does not have a result id.
+  Function* func = &*context->module()->begin();
+  for (auto& bb : *func) {
+    Instruction* terminator = bb.terminator();
+    if (terminator->IsReturnOrAbort()) {
+      return {std::move(context), terminator->PreviousNode()};
+    }
+  }
+  return {nullptr, nullptr};
+}
+
+std::tuple<std::unique_ptr<IRContext>, Instruction*> FoldInstruction(
+    const std::string test_body, const uint32_t id_to_fold,
+    spv_target_env spv_env) {
+  // Build module.
+  std::unique_ptr<IRContext> context;
+  Instruction* inst = nullptr;
+  std::tie(context, inst) =
+      GetInstructionToFold(test_body, id_to_fold, spv_env);
+
+  if (context == nullptr) {
+    return {nullptr, nullptr};
+  }
+
+  std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
+  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
+  EXPECT_EQ(inst->result_id(), original_inst->result_id());
+  EXPECT_EQ(inst->type_id(), original_inst->type_id());
+
+  if (!succeeded && inst != nullptr) {
+    EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
+    for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
+      EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
+    }
+  }
+
+  return {std::move(context), succeeded ? inst : nullptr};
+}
+
+template <class ElementType, class Function>
+void CheckForExpectedScalarConstant(Instruction* inst,
+                                    ElementType expected_result,
+                                    Function GetValue) {
+  ASSERT_TRUE(inst);
+
+  IRContext* context = inst->context();
+  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
+  while (inst->opcode() == spv::Op::OpCopyObject) {
+    inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
+  }
+
+  // Make sure we have a constant.
+  analysis::ConstantManager* const_mrg = context->get_constant_mgr();
+  const analysis::Constant* constant = const_mrg->GetConstantFromInst(inst);
+  ASSERT_TRUE(constant);
+
+  // Make sure the constant is a scalar.
+  const analysis::ScalarConstant* result = constant->AsScalarConstant();
+  ASSERT_TRUE(result);
+
+  // Check if the result matches the expected value.
+  // If ExpectedType is not a float type, it should cast the value to a double
+  // and never get a nan.
+  if (!std::isnan(static_cast<double>(expected_result))) {
+    EXPECT_EQ(expected_result, GetValue(result));
+  } else {
+    EXPECT_TRUE(std::isnan(static_cast<double>(GetValue(result))));
+  }
+}
+
+template <class ElementType, class Function>
+void CheckForExpectedVectorConstant(Instruction* inst,
+                                    std::vector<ElementType> expected_result,
+                                    Function GetValue) {
+  ASSERT_TRUE(inst);
+
+  IRContext* context = inst->context();
+  EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
+  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
+  inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
+  std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
+  EXPECT_THAT(opcodes, Contains(inst->opcode()));
+  analysis::ConstantManager* const_mrg = context->get_constant_mgr();
+  const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
+  EXPECT_NE(result, nullptr);
+  if (result != nullptr) {
+    const std::vector<const analysis::Constant*>& componenets =
+        result->AsVectorConstant()->GetComponents();
+    EXPECT_EQ(componenets.size(), expected_result.size());
+    for (size_t i = 0; i < componenets.size(); i++) {
+      EXPECT_EQ(expected_result[i], GetValue(componenets[i]));
+    }
+  }
+}
+
 using IntegerInstructionFoldingTest =
     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
 
 TEST_P(IntegerInstructionFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
-
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-
-  // Make sure the instruction folded as expected.
-  EXPECT_TRUE(succeeded);
-  if (inst != nullptr) {
-    EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
-    inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
-    EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
-    analysis::ConstantManager* const_mrg = context->get_constant_mgr();
-    const analysis::Constant* constant = const_mrg->GetConstantFromInst(inst);
-    // We expect to see either integer types or 16-bit float types here.
-    EXPECT_TRUE((constant->AsIntConstant() != nullptr) ||
-                ((constant->AsFloatConstant() != nullptr) &&
-                 (constant->type()->AsFloat()->width() == 16)));
-    const analysis::ScalarConstant* result =
-        const_mrg->GetConstantFromInst(inst)->AsScalarConstant();
-    EXPECT_NE(result, nullptr);
-    if (result != nullptr) {
-      EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
-    }
-  }
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
+  CheckForExpectedScalarConstant(
+      inst, tc.expected_result, [](const analysis::Constant* c) {
+        return c->AsScalarConstant()->GetU32BitValue();
+      });
 }
 
 // Returns a common SPIR-V header for all of the test that follow.
@@ -148,14 +241,20 @@
 %ulong = OpTypeInt 64 0
 %v2int = OpTypeVector %int 2
 %v4int = OpTypeVector %int 4
+%v2short = OpTypeVector %short 2
+%v2long = OpTypeVector %long 2
+%v4long = OpTypeVector %long 4
 %v4float = OpTypeVector %float 4
 %v4double = OpTypeVector %double 4
 %v2uint = OpTypeVector %uint 2
+%v2ulong = OpTypeVector %ulong 2
 %v2float = OpTypeVector %float 2
 %v2double = OpTypeVector %double 2
 %v2half = OpTypeVector %half 2
 %v2bool = OpTypeVector %bool 2
 %m2x2int = OpTypeMatrix %v2int 2
+%mat4v2float = OpTypeMatrix %v2float 4
+%mat2v4float = OpTypeMatrix %v4float 2
 %mat4v4float = OpTypeMatrix %v4float 4
 %mat4v4double = OpTypeMatrix %v4double 4
 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
@@ -174,16 +273,18 @@
 %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int
 %_ptr_v2float = OpTypePointer Function %v2float
 %_ptr_v2double = OpTypePointer Function %v2double
+%int_2 = OpConstant %int 2
+%int_arr_2 = OpTypeArray %int %int_2
 %short_0 = OpConstant %short 0
 %short_2 = OpConstant %short 2
 %short_3 = OpConstant %short 3
+%short_n5 = OpConstant %short -5
 %ubyte_1 = OpConstant %ubyte 1
 %byte_n1 = OpConstant %byte -1
 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
 %int_0 = OpConstant %int 0
 %int_1 = OpConstant %int 1
-%int_2 = OpConstant %int 2
 %int_3 = OpConstant %int 3
 %int_4 = OpConstant %int 4
 %int_10 = OpConstant %int 10
@@ -197,12 +298,20 @@
 %long_1 = OpConstant %long 1
 %long_2 = OpConstant %long 2
 %long_3 = OpConstant %long 3
+%long_n3 = OpConstant %long -3
+%long_7 = OpConstant %long 7
+%long_n7 = OpConstant %long -7
 %long_10 = OpConstant %long 10
+%long_32768 = OpConstant %long 32768
+%long_n57344 = OpConstant %long -57344
+%long_n4611686018427387904 = OpConstant %long -4611686018427387904
 %long_4611686018427387904 = OpConstant %long 4611686018427387904
 %long_n1 = OpConstant %long -1
 %long_n3689348814741910323 = OpConstant %long -3689348814741910323
 %long_min = OpConstant %long -9223372036854775808
 %long_max = OpConstant %long 9223372036854775807
+%ulong_7 = OpConstant %ulong 7
+%ulong_4611686018427387904 = OpConstant %ulong 4611686018427387904
 %uint_0 = OpConstant %uint 0
 %uint_1 = OpConstant %uint 1
 %uint_2 = OpConstant %uint 2
@@ -223,8 +332,12 @@
 %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2
 %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3
 %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2
+%v2int_n1_n24 = OpConstantComposite %v2int %int_n1 %int_n24
 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4
 %v2int_min_max = OpConstantComposite %v2int %int_min %int_max
+%v2short_2_n5 = OpConstantComposite %v2short %short_2 %short_n5
+%v2long_2_2 = OpConstantComposite %v2long %long_2 %long_2
+%v2long_2_3 = OpConstantComposite %v2long %long_2 %long_3
 %v2bool_null = OpConstantNull %v2bool
 %v2bool_true_false = OpConstantComposite %v2bool %true %false
 %v2bool_false_true = OpConstantComposite %v2bool %false %true
@@ -282,6 +395,7 @@
 %v2double_null = OpConstantNull %v2double
 %108 = OpConstant %half 0
 %half_1 = OpConstant %half 1
+%half_2 = OpConstant %half 2
 %half_0_1 = OpConstantComposite %v2half %108 %half_1
 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
@@ -290,7 +404,8 @@
 %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
 %v4float_1_2_3_4 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
 %v4float_null = OpConstantNull %v4float
-%mat4v4float_null = OpConstantComposite %mat4v4float %v4float_null %v4float_null %v4float_null %v4float_null
+%mat2v4float_null = OpConstantNull %mat2v4float
+%mat4v4float_null = OpConstantNull %mat4v4float
 %mat4v4float_1_2_3_4 = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4
 %mat4v4float_1_2_3_4_null = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_null %v4float_1_2_3_4 %v4float_null
 %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
@@ -301,7 +416,7 @@
 %v4double_1_2_3_4 = OpConstantComposite %v4double %double_1 %double_2 %double_3 %double_4
 %v4double_1_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5
 %v4double_null = OpConstantNull %v4double
-%mat4v4double_null = OpConstantComposite %mat4v4double %v4double_null %v4double_null %v4double_null %v4double_null
+%mat4v4double_null = OpConstantNull %mat4v4double
 %mat4v4double_1_2_3_4 = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4
 %mat4v4double_1_2_3_4_null = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_null %v4double_1_2_3_4 %v4double_null
 %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3
@@ -314,8 +429,11 @@
 %int_0xC05FD666 = OpConstant %int 0xC05FD666
 %int_0x66666666 = OpConstant %int 0x66666666
 %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666 = OpConstantComposite %v4int %int_0x00000000 %int_0x3FF00000 %int_0x66666666 %int_0xC05FD666
+%ushort_0x4400 = OpConstant %ushort 0x4400
+%short_0x4400 = OpConstant %short 0x4400
 %ushort_0xBC00 = OpConstant %ushort 0xBC00
 %short_0xBC00 = OpConstant %short 0xBC00
+%int_arr_2_undef = OpUndef %int_arr_2
 )";
 
   return header;
@@ -749,7 +867,7 @@
           "OpReturn\n" +
           "OpFunctionEnd",
       2, 1),
-  // Test case 44: UClamp 1 2 x
+  // Test case 46: UClamp 1 2 x
   InstructionFoldingCase<uint32_t>(
       Header() + "%main = OpFunction %void None %void_func\n" +
           "%main_lab = OpLabel\n" +
@@ -758,7 +876,7 @@
           "OpReturn\n" +
           "OpFunctionEnd",
       2, 2),
-  // Test case 45: UClamp 2 x 1
+  // Test case 47: UClamp 2 x 1
   InstructionFoldingCase<uint32_t>(
       Header() + "%main = OpFunction %void None %void_func\n" +
           "%main_lab = OpLabel\n" +
@@ -767,7 +885,7 @@
           "OpReturn\n" +
           "OpFunctionEnd",
       2, 1),
-    // Test case 46: Bit-cast int 0 to unsigned int
+    // Test case 48: Bit-cast int 0 to unsigned int
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -775,7 +893,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0),
-    // Test case 47: Bit-cast int -24 to unsigned int
+    // Test case 49: Bit-cast int -24 to unsigned int
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -783,7 +901,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, static_cast<uint32_t>(-24)),
-    // Test case 48: Bit-cast float 1.0f to unsigned int
+    // Test case 50: Bit-cast float 1.0f to unsigned int
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -791,7 +909,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, static_cast<uint32_t>(0x3f800000)),
-    // Test case 49: Bit-cast ushort 0xBC00 to ushort
+    // Test case 51: Bit-cast ushort 0xBC00 to ushort
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -799,7 +917,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0xBC00),
-    // Test case 50: Bit-cast short 0xBC00 to ushort
+    // Test case 52: Bit-cast short 0xBC00 to ushort
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -807,7 +925,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0xFFFFBC00),
-    // Test case 51: Bit-cast half 1 to ushort
+    // Test case 53: Bit-cast half 1 to ushort
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -815,7 +933,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0x3C00),
-    // Test case 52: Bit-cast ushort 0xBC00 to short
+    // Test case 54: Bit-cast ushort 0xBC00 to short
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -823,7 +941,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0xBC00),
-    // Test case 53: Bit-cast short 0xBC00 to short
+    // Test case 55: Bit-cast short 0xBC00 to short
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -831,7 +949,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0xFFFFBC00),
-    // Test case 54: Bit-cast half 1 to short
+    // Test case 56: Bit-cast half 1 to short
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -839,7 +957,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0x3C00),
-    // Test case 55: Bit-cast ushort 0xBC00 to half
+    // Test case 57: Bit-cast ushort 0xBC00 to half
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -847,7 +965,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0xBC00),
-    // Test case 56: Bit-cast short 0xBC00 to half
+    // Test case 58: Bit-cast short 0xBC00 to half
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -855,7 +973,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0xFFFFBC00),
-    // Test case 57: Bit-cast half 1 to half
+    // Test case 59: Bit-cast half 1 to half
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -863,7 +981,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0x3C00),
-    // Test case 58: Bit-cast ubyte 1 to byte
+    // Test case 60: Bit-cast ubyte 1 to byte
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -871,58 +989,302 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 1),
-    // Test case 59: Bit-cast byte -1 to ubyte
+    // Test case 61: Bit-cast byte -1 to ubyte
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
             "%2 = OpBitcast %ubyte %byte_n1\n" +
             "OpReturn\n" +
             "OpFunctionEnd",
-        2, 0xFFFFFFFF)
+        2, 0xFFFFFFFF),
+    // Test case 62: Negate 2.
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%2 = OpSNegate %int %int_2\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, -2),
+    // Test case 63: Negate negative short.
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%2 = OpSNegate %short %short_0xBC00\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, 0x4400 /* expected to be sign extended. */),
+    // Test case 64: Negate positive short.
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%2 = OpSNegate %short %short_0x4400\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, 0xFFFFBC00 /* expected to be sign extended. */),
+    // Test case 65: Negate a negative short.
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%2 = OpSNegate %ushort %ushort_0xBC00\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, 0x4400 /* expected to be zero extended. */),
+    // Test case 66: Negate positive short.
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%2 = OpSNegate %ushort %ushort_0x4400\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, 0xBC00 /* expected to be zero extended. */),
+    // Test case 67: Fold 2 + 3 (short)
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%2 = OpIAdd %short %short_2 %short_3\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, 5),
+    // Test case 68: Fold 2 + -5 (short)
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%2 = OpIAdd %short %short_2 %short_n5\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, -3),
+  // Test case 69: Fold int(3ll)
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpSConvert %int %long_3\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, 3),
+  // Test case 70: Fold short(-3ll)
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpSConvert %short %long_n3\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, -3),
+  // Test case 71: Fold short(32768ll) - This should do a sign extend when
+  // converting to short.
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpSConvert %short %long_32768\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, -32768),
+  // Test case 72: Fold short(-57344) - This should do a sign extend when
+  // converting to short making the upper bits 0.
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpSConvert %short %long_n57344\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, 8192),
+  // Test case 73: Fold int(-5(short)). The -5 should be interpreted as an unsigned value, and be zero extended to 32-bits.
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpUConvert %uint %short_n5\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, 65531),
+  // Test case 74: Fold short(-24(int)). The upper bits should be cleared. So 0xFFFFFFE8 should become 0x0000FFE8.
+  InstructionFoldingCase<uint32_t>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpUConvert %ushort %int_n24\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, 65512)
 ));
 // clang-format on
 
-using IntVectorInstructionFoldingTest =
-    ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
+using LongIntegerInstructionFoldingTest =
+    ::testing::TestWithParam<InstructionFoldingCase<uint64_t>>;
 
-TEST_P(IntVectorInstructionFoldingTest, Case) {
+TEST_P(LongIntegerInstructionFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
+  CheckForExpectedScalarConstant(
+      inst, tc.expected_result, [](const analysis::Constant* c) {
+        return c->AsScalarConstant()->GetU64BitValue();
+      });
+}
 
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  spv::Op original_opcode = inst->opcode();
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
+INSTANTIATE_TEST_SUITE_P(
+    TestCase, LongIntegerInstructionFoldingTest,
+    ::testing::Values(
+        // Test case 0: fold 1+4611686018427387904
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpIAdd %long %long_1 %long_4611686018427387904\n" +
+                "OpReturn\n" + "OpFunctionEnd",
+            2, 1 + 4611686018427387904),
+        // Test case 1: fold 1-4611686018427387904
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpISub %long %long_1 %long_4611686018427387904\n" +
+                "OpReturn\n" + "OpFunctionEnd",
+            2, 1 - 4611686018427387904),
+        // Test case 2: fold 2*4611686018427387904
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpIMul %long %long_2 %long_4611686018427387904\n" +
+                "OpReturn\n" + "OpFunctionEnd",
+            2, 9223372036854775808ull),
+        // Test case 3: fold 4611686018427387904/2 (unsigned)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpUDiv %ulong %ulong_4611686018427387904 %ulong_2\n" +
+                "OpReturn\n" + "OpFunctionEnd",
+            2, 4611686018427387904 / 2),
+        // Test case 4: fold 4611686018427387904/2 (signed)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpSDiv %long %long_4611686018427387904 %long_2\n" +
+                "OpReturn\n" + "OpFunctionEnd",
+            2, 4611686018427387904 / 2),
+        // Test case 5: fold -4611686018427387904/2 (signed)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpSDiv %long %long_n4611686018427387904 %long_2\n" +
+                "OpReturn\n" + "OpFunctionEnd",
+            2, -4611686018427387904 / 2),
+        // Test case 6: fold 4611686018427387904 mod 7 (unsigned)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpUMod %ulong %ulong_4611686018427387904 %ulong_7\n" +
+                "OpReturn\n" + "OpFunctionEnd",
+            2, 4611686018427387904ull % 7ull),
+        // Test case 7: fold 7 mod 3 (signed)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpSMod %long %long_7 %long_3\n" + "OpReturn\n" +
+                "OpFunctionEnd",
+            2, 1ull),
+        // Test case 8: fold 7 rem 3 (signed)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpSRem %long %long_7 %long_3\n" + "OpReturn\n" +
+                "OpFunctionEnd",
+            2, 1ull),
+        // Test case 9: fold 7 mod -3 (signed)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpSMod %long %long_7 %long_n3\n" + "OpReturn\n" +
+                "OpFunctionEnd",
+            2, -2ll),
+        // Test case 10: fold 7 rem 3 (signed)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpSRem %long %long_7 %long_n3\n" + "OpReturn\n" +
+                "OpFunctionEnd",
+            2, 1ll),
+        // Test case 11: fold -7 mod 3 (signed)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpSMod %long %long_n7 %long_3\n" + "OpReturn\n" +
+                "OpFunctionEnd",
+            2, 2ll),
+        // Test case 12: fold -7 rem 3 (signed)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpSRem %long %long_n7 %long_3\n" + "OpReturn\n" +
+                "OpFunctionEnd",
+            2, -1ll),
+        // Test case 13: fold long(-24)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" +
+                "%2 = OpSConvert %long %int_n24\n" + "OpReturn\n" +
+                "OpFunctionEnd",
+            2, -24ll),
+        // Test case 14: fold long(-24)
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" +
+                "%n = OpVariable %_ptr_int Function\n" +
+                "%load = OpLoad %int %n\n" + "%2 = OpSConvert %long %int_10\n" +
+                "OpReturn\n" + "OpFunctionEnd",
+            2, 10ll),
+        // Test case 15: fold long(-24(short)).
+        // The upper bits should be cleared. So 0xFFFFFFE8 should become
+        // 0x000000000000FFE8.
+        InstructionFoldingCase<uint64_t>(
+            Header() + "%main = OpFunction %void None %void_func\n" +
+                "%main_lab = OpLabel\n" + "%2 = OpUConvert %ulong %short_n5\n" +
+                "OpReturn\n" + "OpFunctionEnd",
+            2, 65531ull)));
 
-  // Make sure the instruction folded as expected.
-  EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
-  if (succeeded && inst != nullptr) {
-    EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
-    inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
-    std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
-    EXPECT_THAT(opcodes, Contains(inst->opcode()));
-    analysis::ConstantManager* const_mrg = context->get_constant_mgr();
-    const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
-    EXPECT_NE(result, nullptr);
-    if (result != nullptr) {
-      const std::vector<const analysis::Constant*>& componenets =
-          result->AsVectorConstant()->GetComponents();
-      EXPECT_EQ(componenets.size(), tc.expected_result.size());
-      for (size_t i = 0; i < componenets.size(); i++) {
-        EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32());
-      }
-    }
-  }
+using UIntVectorInstructionFoldingTest =
+    ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
+
+TEST_P(UIntVectorInstructionFoldingTest, Case) {
+  const auto& tc = GetParam();
+
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
+  CheckForExpectedVectorConstant(
+      inst, tc.expected_result,
+      [](const analysis::Constant* c) { return c->GetU32(); });
 }
 
 // clang-format off
-INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest,
+INSTANTIATE_TEST_SUITE_P(TestCase, UIntVectorInstructionFoldingTest,
 ::testing::Values(
     // Test case 0: fold 0*n
     InstructionFoldingCase<std::vector<uint32_t>>(
@@ -943,24 +1305,6 @@
           "OpReturn\n" +
           "OpFunctionEnd",
       2, {0,3}),
-    InstructionFoldingCase<std::vector<uint32_t>>(
-      Header() + "%main = OpFunction %void None %void_func\n" +
-          "%main_lab = OpLabel\n" +
-          "%n = OpVariable %_ptr_int Function\n" +
-          "%load = OpLoad %int %n\n" +
-          "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" +
-          "OpReturn\n" +
-          "OpFunctionEnd",
-      2, {0,0}),
-    InstructionFoldingCase<std::vector<uint32_t>>(
-      Header() + "%main = OpFunction %void None %void_func\n" +
-          "%main_lab = OpLabel\n" +
-          "%n = OpVariable %_ptr_int Function\n" +
-          "%load = OpLoad %int %n\n" +
-          "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" +
-          "OpReturn\n" +
-          "OpFunctionEnd",
-      2, {0,0}),
     // Test case 4: fold bit-cast int -24 to unsigned int
     InstructionFoldingCase<std::vector<uint32_t>>(
       Header() + "%main = OpFunction %void None %void_func\n" +
@@ -970,46 +1314,156 @@
           "%2 = OpBitcast %v2uint %v2int_min_max\n" +
           "OpReturn\n" +
           "OpFunctionEnd",
-      2, {2147483648, 2147483647})
+      2, {2147483648, 2147483647}),
+    // Test case 5: fold SNegate vector of uint
+    InstructionFoldingCase<std::vector<uint32_t>>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%n = OpVariable %_ptr_int Function\n" +
+          "%load = OpLoad %int %n\n" +
+          "%2 = OpSNegate %v2uint %v2uint_0x3f800000_0xbf800000\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, {static_cast<uint32_t>(-0x3f800000), static_cast<uint32_t>(-0xbf800000)}),
+    // Test case 6: fold vector components of uint (including integer overflow)
+    InstructionFoldingCase<std::vector<uint32_t>>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpIAdd %v2uint %v2uint_0x3f800000_0xbf800000 %v2uint_0x3f800000_0xbf800000\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, {0x7f000000u, 0x7f000000u}),
+    // Test case 6: fold vector components of uint
+    InstructionFoldingCase<std::vector<uint32_t>>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%2 = OpSConvert %v2int %v2short_2_n5\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, {2,static_cast<uint32_t>(-5)}),
+    // Test case 6: fold vector components of uint (incuding integer overflow)
+    InstructionFoldingCase<std::vector<uint32_t>>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%2 = OpUConvert %v2uint %v2short_2_n5\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, {2,65531})
 ));
 // clang-format on
 
+using IntVectorInstructionFoldingTest =
+    ::testing::TestWithParam<InstructionFoldingCase<std::vector<int32_t>>>;
+
+TEST_P(IntVectorInstructionFoldingTest, Case) {
+  const auto& tc = GetParam();
+
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
+
+  CheckForExpectedVectorConstant(
+      inst, tc.expected_result,
+      [](const analysis::Constant* c) { return c->GetS32(); });
+}
+
+// clang-format off
+INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest,
+::testing::Values(
+    // Test case 0: fold negate of a vector
+    InstructionFoldingCase<std::vector<int32_t>>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpSNegate %v2int %v2int_2_3\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, {-2, -3}),
+    // Test case 1: fold negate of a vector containing negative values.
+    InstructionFoldingCase<std::vector<int32_t>>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpSNegate %v2int %v2int_n1_n24\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, {1, 24}),
+    // Test case 2: fold negate of a vector at the limits
+    InstructionFoldingCase<std::vector<int32_t>>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpSNegate %v2int %v2int_min_max\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, {INT_MIN, -INT_MAX}),
+    // Test case 3: fold vector components of int
+    InstructionFoldingCase<std::vector<int32_t>>(
+      Header() + "%main = OpFunction %void None %void_func\n" +
+          "%main_lab = OpLabel\n" +
+          "%2 = OpIMul %v2int %v2int_2_3 %v2int_2_3\n" +
+          "OpReturn\n" +
+          "OpFunctionEnd",
+      2, {4,9})
+));
+// clang-format on
+
+using LongIntVectorInstructionFoldingTest =
+    ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint64_t>>>;
+
+TEST_P(LongIntVectorInstructionFoldingTest, Case) {
+  const auto& tc = GetParam();
+
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
+  CheckForExpectedVectorConstant(
+      inst, tc.expected_result,
+      [](const analysis::Constant* c) { return c->GetU64(); });
+}
+
+// clang-format off
+INSTANTIATE_TEST_SUITE_P(TestCase, LongIntVectorInstructionFoldingTest,
+  ::testing::Values(
+     // Test case 0: fold {2,2} + {2,3} (Testing that the vector logic works
+     // correctly. Scalar tests will check that the 64-bit values are correctly
+     // folded.)
+     InstructionFoldingCase<std::vector<uint64_t>>(
+         Header() + "%main = OpFunction %void None %void_func\n" +
+             "%main_lab = OpLabel\n" +
+             "%n = OpVariable %_ptr_int Function\n" +
+             "%load = OpLoad %int %n\n" +
+             "%2 = OpIAdd %v2long %v2long_2_2 %v2long_2_3\n" +
+             "OpReturn\n" +
+             "OpFunctionEnd",
+         2, {4,5}),
+      // Test case 0: fold {2,2} / {2,3} (Testing that the vector logic works
+      // correctly. Scalar tests will check that the 64-bit values are correctly
+      // folded.)
+     InstructionFoldingCase<std::vector<uint64_t>>(
+         Header() + "%main = OpFunction %void None %void_func\n" +
+             "%main_lab = OpLabel\n" +
+             "%n = OpVariable %_ptr_int Function\n" +
+             "%load = OpLoad %int %n\n" +
+             "%2 = OpSDiv %v2long %v2long_2_2 %v2long_2_3\n" +
+             "OpReturn\n" +
+             "OpFunctionEnd",
+         2, {1,0})
+  ));
+// clang-format on
+
 using DoubleVectorInstructionFoldingTest =
     ::testing::TestWithParam<InstructionFoldingCase<std::vector<double>>>;
 
 TEST_P(DoubleVectorInstructionFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
-
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-
-  // Make sure the instruction folded as expected.
-  EXPECT_TRUE(succeeded);
-  if (succeeded && inst != nullptr) {
-    EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
-    inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
-    std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
-    EXPECT_THAT(opcodes, Contains(inst->opcode()));
-    analysis::ConstantManager* const_mrg = context->get_constant_mgr();
-    const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
-    EXPECT_NE(result, nullptr);
-    if (result != nullptr) {
-      const std::vector<const analysis::Constant*>& componenets =
-          result->AsVectorConstant()->GetComponents();
-      EXPECT_EQ(componenets.size(), tc.expected_result.size());
-      for (size_t i = 0; i < componenets.size(); i++) {
-        EXPECT_EQ(tc.expected_result[i], componenets[i]->GetDouble());
-      }
-    }
-  }
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
+  CheckForExpectedVectorConstant(
+      inst, tc.expected_result,
+      [](const analysis::Constant* c) { return c->GetDouble(); });
 }
 
 // clang-format off
@@ -1104,37 +1558,10 @@
 TEST_P(FloatVectorInstructionFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
-
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  spv::Op original_opcode = inst->opcode();
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-
-  // Make sure the instruction folded as expected.
-  EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
-  if (succeeded && inst != nullptr) {
-    EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
-    inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
-    std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
-    EXPECT_THAT(opcodes, Contains(inst->opcode()));
-    analysis::ConstantManager* const_mrg = context->get_constant_mgr();
-    const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
-    EXPECT_NE(result, nullptr);
-    if (result != nullptr) {
-      const std::vector<const analysis::Constant*>& componenets =
-          result->AsVectorConstant()->GetComponents();
-      EXPECT_EQ(componenets.size(), tc.expected_result.size());
-      for (size_t i = 0; i < componenets.size(); i++) {
-        EXPECT_EQ(tc.expected_result[i], componenets[i]->GetFloat());
-      }
-    }
-  }
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1);
+  CheckForExpectedVectorConstant(inst, tc.expected_result, [](const analysis::Constant* c){ return c->GetFloat();});
 }
 
 // clang-format off
@@ -1239,39 +1666,89 @@
        2, {4.0,8.0,12.0,16.0})
 ));
 // clang-format on
+
+using FloatMatrixInstructionFoldingTest = ::testing::TestWithParam<
+    InstructionFoldingCase<std::vector<std::vector<float>>>>;
+
+TEST_P(FloatMatrixInstructionFoldingTest, Case) {
+  const auto& tc = GetParam();
+
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
+
+  EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
+  if (inst->opcode() == spv::Op::OpCopyObject) {
+    analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
+    inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
+    analysis::ConstantManager* const_mgr = context->get_constant_mgr();
+    const analysis::Constant* result = const_mgr->GetConstantFromInst(inst);
+    EXPECT_NE(result, nullptr);
+    if (result != nullptr) {
+      std::vector<const analysis::Constant*> matrix =
+          result->AsMatrixConstant()->GetComponents();
+      EXPECT_EQ(matrix.size(), tc.expected_result.size());
+      for (size_t c = 0; c < matrix.size(); c++) {
+        if (matrix[c]->AsNullConstant() != nullptr) {
+          matrix[c] = const_mgr->GetNullCompositeConstant(matrix[c]->type());
+        }
+        const analysis::VectorConstant* column_const =
+            matrix[c]->AsVectorConstant();
+        ASSERT_NE(column_const, nullptr);
+        const std::vector<const analysis::Constant*>& column =
+            column_const->GetComponents();
+        EXPECT_EQ(column.size(), tc.expected_result[c].size());
+        for (size_t r = 0; r < column.size(); r++) {
+          EXPECT_EQ(tc.expected_result[c][r], column[r]->GetFloat());
+        }
+      }
+    }
+  }
+}
+
+// clang-format off
+INSTANTIATE_TEST_SUITE_P(TestCase, FloatMatrixInstructionFoldingTest,
+::testing::Values(
+   // Test case 0: OpTranspose square null matrix
+   InstructionFoldingCase<std::vector<std::vector<float>>>(
+       Header() + "%main = OpFunction %void None %void_func\n" +
+           "%main_lab = OpLabel\n" +
+           "%2 = OpTranspose %mat4v4float %mat4v4float_null\n" +
+           "OpReturn\n" +
+           "OpFunctionEnd",
+       2, {{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f}}),
+   // Test case 1: OpTranspose rectangular null matrix
+   InstructionFoldingCase<std::vector<std::vector<float>>>(
+       Header() + "%main = OpFunction %void None %void_func\n" +
+           "%main_lab = OpLabel\n" +
+           "%2 = OpTranspose %mat4v2float %mat2v4float_null\n" +
+           "OpReturn\n" +
+           "OpFunctionEnd",
+       2, {{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f}}),
+   InstructionFoldingCase<std::vector<std::vector<float>>>(
+       Header() + "%main = OpFunction %void None %void_func\n" +
+           "%main_lab = OpLabel\n" +
+           "%2 = OpTranspose %mat4v4float %mat4v4float_1_2_3_4\n" +
+           "OpReturn\n" +
+           "OpFunctionEnd",
+       2, {{1.0f, 1.0f, 1.0f, 1.0f},{2.0f, 2.0f, 2.0f, 2.0f},{3.0f, 3.0f, 3.0f, 3.0f},{4.0f, 4.0f, 4.0f, 4.0f}})
+));
+// clang-format on
+
 using BooleanInstructionFoldingTest =
     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
 
 TEST_P(BooleanInstructionFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
-
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-
-  // Make sure the instruction folded as expected.
-  EXPECT_TRUE(succeeded);
-  if (inst != nullptr) {
-    EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
-    inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
-    std::vector<spv::Op> bool_opcodes = {spv::Op::OpConstantTrue,
-                                         spv::Op::OpConstantFalse};
-    EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
-    analysis::ConstantManager* const_mrg = context->get_constant_mgr();
-    const analysis::BoolConstant* result =
-        const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
-    EXPECT_NE(result, nullptr);
-    if (result != nullptr) {
-      EXPECT_EQ(result->value(), tc.expected_result);
-    }
-  }
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
+  CheckForExpectedScalarConstant(
+      inst, tc.expected_result,
+      [](const analysis::Constant* c) { return c->AsBoolConstant()->value(); });
 }
 
 // clang-format off
@@ -1857,35 +2334,15 @@
 TEST_P(FloatInstructionFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
 
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-
-  // Make sure the instruction folded as expected.
-  EXPECT_TRUE(succeeded);
-  if (inst != nullptr) {
-    EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
-    inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
-    EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
-    analysis::ConstantManager* const_mrg = context->get_constant_mgr();
-    const analysis::FloatConstant* result =
-        const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
-    EXPECT_NE(result, nullptr);
-    if (result != nullptr) {
-      if (!std::isnan(tc.expected_result)) {
-        EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
-      } else {
-        EXPECT_TRUE(std::isnan(result->GetFloatValue()));
-      }
-    }
-  }
+  CheckForExpectedScalarConstant(inst, tc.expected_result,
+                                 [](const analysis::Constant* c) {
+                                   return c->AsFloatConstant()->GetFloatValue();
+                                 });
 }
 
 // Not testing NaNs because there are no expectations concerning NaNs according
@@ -2290,35 +2747,14 @@
 TEST_P(DoubleInstructionFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
-
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-
-  // Make sure the instruction folded as expected.
-  EXPECT_TRUE(succeeded);
-  if (inst != nullptr) {
-    EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
-    inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
-    EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
-    analysis::ConstantManager* const_mrg = context->get_constant_mgr();
-    const analysis::FloatConstant* result =
-        const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
-    EXPECT_NE(result, nullptr);
-    if (result != nullptr) {
-      if (!std::isnan(tc.expected_result)) {
-        EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
-      } else {
-        EXPECT_TRUE(std::isnan(result->GetDoubleValue()));
-      }
-    }
-  }
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
+  CheckForExpectedScalarConstant(
+      inst, tc.expected_result, [](const analysis::Constant* c) {
+        return c->AsFloatConstant()->GetDoubleValue();
+      });
 }
 
 // clang-format off
@@ -3176,32 +3612,22 @@
 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      GetInstructionToFold(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_5);
 
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
   inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
                                                                      tc.id_map);
-
-  // Make sure the instruction folded as expected.
   EXPECT_NE(inst, nullptr);
-  if (inst != nullptr) {
-    EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
-    analysis::ConstantManager* const_mrg = context->get_constant_mgr();
-    const analysis::IntConstant* result =
-        const_mrg->GetConstantFromInst(inst)->AsIntConstant();
-    EXPECT_NE(result, nullptr);
-    if (result != nullptr) {
-      EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
-    }
-  }
+
+  CheckForExpectedScalarConstant(inst, tc.expected_result,
+                                 [](const analysis::Constant* c) {
+                                   return c->AsIntConstant()->GetU32BitValue();
+                                 });
 }
 // clang-format off
+
 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTestWithMap,
   ::testing::Values(
       // Test case 0: fold %3 = 0; %3 * n
@@ -3224,32 +3650,16 @@
 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
-
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      GetInstructionToFold(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_5);
   inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
                                                                      tc.id_map);
-
-  // Make sure the instruction folded as expected.
-  EXPECT_NE(inst, nullptr);
-  if (inst != nullptr) {
-    std::vector<spv::Op> bool_opcodes = {spv::Op::OpConstantTrue,
-                                         spv::Op::OpConstantFalse};
-    EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
-    analysis::ConstantManager* const_mrg = context->get_constant_mgr();
-    const analysis::BoolConstant* result =
-        const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
-    EXPECT_NE(result, nullptr);
-    if (result != nullptr) {
-      EXPECT_EQ(result->value(), tc.expected_result);
-    }
-  }
+  ASSERT_NE(inst, nullptr);
+  CheckForExpectedScalarConstant(
+      inst, tc.expected_result,
+      [](const analysis::Constant* c) { return c->AsBoolConstant()->value(); });
 }
 
 // clang-format off
@@ -3275,30 +3685,15 @@
 TEST_P(GeneralInstructionFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
 
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-
-  // Make sure the instruction folded as expected.
-  EXPECT_EQ(inst->result_id(), original_inst->result_id());
-  EXPECT_EQ(inst->type_id(), original_inst->type_id());
-  EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
-  if (succeeded) {
+  EXPECT_TRUE((inst == nullptr) == (tc.expected_result == 0));
+  if (inst != nullptr) {
     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
-  } else {
-    EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
-    for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
-      EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
-    }
   }
 }
 
@@ -3725,23 +4120,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 0),
-    // Test case 38: Don't fold 2 + 3 (long), bad length
-    InstructionFoldingCase<uint32_t>(
-        Header() + "%main = OpFunction %void None %void_func\n" +
-            "%main_lab = OpLabel\n" +
-            "%2 = OpIAdd %long %long_2 %long_3\n" +
-            "OpReturn\n" +
-            "OpFunctionEnd",
-        2, 0),
-    // Test case 39: Don't fold 2 + 3 (short), bad length
-    InstructionFoldingCase<uint32_t>(
-        Header() + "%main = OpFunction %void None %void_func\n" +
-            "%main_lab = OpLabel\n" +
-            "%2 = OpIAdd %short %short_2 %short_3\n" +
-            "OpReturn\n" +
-            "OpFunctionEnd",
-        2, 0),
-    // Test case 40: fold 1*n
+    // Test case 38: fold 1*n
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -3751,7 +4130,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 3),
-    // Test case 41: fold n*1
+    // Test case 39: fold n*1
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
             "%main_lab = OpLabel\n" +
@@ -3761,7 +4140,7 @@
             "OpReturn\n" +
             "OpFunctionEnd",
         2, 3),
-    // Test case 42: Don't fold comparisons of 64-bit types
+    // Test case 40: Don't fold comparisons of 64-bit types
     // (https://github.com/KhronosGroup/SPIRV-Tools/issues/3343).
     InstructionFoldingCase<uint32_t>(
         Header() + "%main = OpFunction %void None %void_func\n" +
@@ -4299,6 +4678,17 @@
             "%2 = OpDot %half %half_0_1 %half_0_1\n" +
             "OpReturn\n" +
             "OpFunctionEnd",
+        2, 0),
+    // Test case 23: Don't fold 1.0(half) / 2.0(half)
+    // We do not have to code to emulate 16-bit float operations. Just make sure we do not crash.
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%n = OpVariable %_ptr_half Function\n" +
+            "%3 = OpLoad %half %n\n" +
+            "%2 = OpFDiv %half %half_1 %half_2\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
         2, 0)
 ));
 
@@ -4611,7 +5001,31 @@
             "%2 = OpIAdd %v2int %v2int_0_0 %3\n" +
             "OpReturn\n" +
             "OpFunctionEnd",
-        2, 3)
+        2, 3),
+    // Test case 8: Don't fold because of undefined value. Using 4294967295
+    // means that entry is undefined. We do not expect it to ever happen, so
+    // not worth folding.
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%n = OpVariable %_ptr_int Function\n" +
+            "%load = OpLoad %int %n\n" +
+            "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, 0),
+    // Test case 9: Don't fold because of undefined value. Using 4294967295
+    // means that entry is undefined. We do not expect it to ever happen, so
+    // not worth folding.
+    InstructionFoldingCase<uint32_t>(
+        Header() + "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%n = OpVariable %_ptr_int Function\n" +
+            "%load = OpLoad %int %n\n" +
+            "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        2, 0)
 ));
 
 INSTANTIATE_TEST_SUITE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest,
@@ -4933,30 +5347,15 @@
 TEST_P(ToNegateFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) =
+      FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
 
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-
-  // Make sure the instruction folded as expected.
-  EXPECT_EQ(inst->result_id(), original_inst->result_id());
-  EXPECT_EQ(inst->type_id(), original_inst->type_id());
-  EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
-  if (succeeded) {
+  EXPECT_TRUE((inst == nullptr) == (tc.expected_result == 0));
+  if (inst != nullptr) {
     EXPECT_EQ(inst->opcode(), spv::Op::OpFNegate);
     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
-  } else {
-    EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
-    for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
-      EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
-    }
   }
 }
 
@@ -5055,19 +5454,12 @@
 TEST_P(MatchingInstructionFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1);
 
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-  EXPECT_EQ(succeeded, tc.expected_result);
-  if (succeeded) {
+  EXPECT_EQ(inst != nullptr, tc.expected_result);
+  if (inst != nullptr) {
     Match(tc.test_body, context.get());
   }
 }
@@ -7418,7 +7810,24 @@
 	    "%4 = OpCompositeExtract %int %struct_v2int_int_int 3\n" +
 	    "OpReturn\n" +
 	    "OpFunctionEnd",
-	4, false)
+	4, false),
+    // Test case 18: Fold when every element of an array is inserted.
+    InstructionFoldingCase<bool>(
+        Header() +
+            "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
+            "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
+            "; CHECK-DAG: [[arr_type:%\\w+]] = OpTypeArray [[int]] [[int2]]\n" +
+            "; CHECK-DAG: [[int10:%\\w+]] = OpConstant [[int]] 10\n" +
+            "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
+            "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[arr_type]] [[int10]] [[int1]]\n" +
+            "; CHECK: %5 = OpCopyObject [[arr_type]] [[construct]]\n" +
+            "%main = OpFunction %void None %void_func\n" +
+            "%main_lab = OpLabel\n" +
+            "%4 = OpCompositeInsert %int_arr_2 %int_10 %int_arr_2_undef 0\n" +
+            "%5 = OpCompositeInsert %int_arr_2 %int_1 %4 1\n" +
+            "OpReturn\n" +
+            "OpFunctionEnd",
+        5, true)
 ));
 
 INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest,
@@ -7797,27 +8206,13 @@
 TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1);
 
-  // Fold the instruction to test.
-  Instruction* inst = nullptr;
-  Function* func = &*context->module()->begin();
-  for (auto& bb : *func) {
-    Instruction* terminator = bb.terminator();
-    if (terminator->IsReturnOrAbort()) {
-      inst = terminator->PreviousNode();
-      break;
-    }
-  }
-  assert(inst && "Invalid test.  Could not find instruction to fold.");
-  std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-  EXPECT_EQ(succeeded, tc.expected_result);
-  if (succeeded) {
+  // Find the instruction to test.
+  EXPECT_EQ(inst != nullptr, tc.expected_result);
+  if (inst != nullptr) {
     Match(tc.test_body, context.get());
   }
 }
@@ -8157,8 +8552,9 @@
                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   ASSERT_NE(nullptr, context);
 
-  // Fold the instruction to test.
+  // Find the first entry point. That is the instruction we want to fold.
   Instruction* inst = nullptr;
+  ASSERT_FALSE(context->module()->entry_points().empty());
   inst = &*context->module()->entry_points().begin();
   assert(inst && "Invalid test.  Could not find entry point instruction to fold.");
   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
@@ -8251,19 +8647,12 @@
 TEST_P(SPV14FoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_4);
 
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-  EXPECT_EQ(succeeded, tc.expected_result);
-  if (succeeded) {
+  EXPECT_EQ(inst != nullptr, tc.expected_result);
+  if (inst !=  nullptr) {
     Match(tc.test_body, context.get());
   }
 }
@@ -8364,19 +8753,12 @@
 TEST_P(FloatControlsFoldingTest, Case) {
   const auto& tc = GetParam();
 
-  // Build module.
-  std::unique_ptr<IRContext> context =
-      BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
-                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  ASSERT_NE(nullptr, context);
+  std::unique_ptr<IRContext> context;
+  Instruction* inst;
+  std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_4);
 
-  // Fold the instruction to test.
-  analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
-  Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
-  std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
-  bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
-  EXPECT_EQ(succeeded, tc.expected_result);
-  if (succeeded) {
+  EXPECT_EQ(inst != nullptr, tc.expected_result);
+  if (inst != nullptr) {
     Match(tc.test_body, context.get());
   }
 }
@@ -8448,6 +8830,7 @@
       %v3int = OpTypeVector %int 3
     %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
    %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
+        %110 = OpConstantComposite %v2int %5 %5
         %101 = OpConstantComposite %v2int %int_n1 %int_n1
          %20 = OpConstantComposite %v2float %float_0 %float_0
        %main = OpFunction %void None %22
@@ -8507,7 +8890,12 @@
     InstructionFoldingCase<bool>(ImageOperandsTestBody(
       "         OpImageWrite %88 %5 %101 Offset %101      \n"
       "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n")
-      , 0 /* No result-id */, true)
+      , 0 /* No result-id */, true),
+    // Test case 8: OpImageFetch with zero constant Offset
+    InstructionFoldingCase<bool>(ImageOperandsTestBody(
+        "         %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %110      \n"
+        "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod %5 \n")
+        , 89, true)
 ));
 
 }  // namespace
diff --git a/third_party/SPIRV-Tools/test/opt/inline_test.cpp b/third_party/SPIRV-Tools/test/opt/inline_test.cpp
index 1e5d9f3..bf79181 100644
--- a/third_party/SPIRV-Tools/test/opt/inline_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/inline_test.cpp
@@ -4422,6 +4422,55 @@
   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
 }
 
+TEST_F(InlineTest, DecorateReturnVariableWithAliasedPointer) {
+  const std::string text = R"(OpCapability Int64
+               OpCapability VariablePointers
+               OpCapability PhysicalStorageBufferAddresses
+               OpCapability Shader
+               OpExtension "SPV_KHR_storage_buffer_storage_class"
+               OpExtension "SPV_KHR_variable_pointers"
+               OpExtension "SPV_KHR_physical_storage_buffer"
+               OpMemoryModel PhysicalStorageBuffer64 GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %1 LocalSize 8 8 1
+               OpDecorate %_ptr_PhysicalStorageBuffer__struct_5 ArrayStride 8
+               OpMemberDecorate %_struct_3 0 Offset 0
+               OpMemberDecorate %_struct_3 1 Offset 8
+               OpDecorate %_ptr_PhysicalStorageBuffer_int ArrayStride 4
+               OpMemberDecorate %_struct_5 0 Offset 0
+               OpMemberDecorate %_struct_5 1 Offset 4
+               OpDecorate %6 Aliased
+; CHECK:       OpDecorate %22 AliasedPointer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+               OpTypeForwardPointer %_ptr_PhysicalStorageBuffer__struct_5 PhysicalStorageBuffer
+  %_struct_3 = OpTypeStruct %int %_ptr_PhysicalStorageBuffer__struct_5
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
+  %_struct_5 = OpTypeStruct %int %int
+         %11 = OpTypeFunction %_ptr_PhysicalStorageBuffer_int %_ptr_PhysicalStorageBuffer__struct_5
+%_ptr_PhysicalStorageBuffer__struct_5 = OpTypePointer PhysicalStorageBuffer %_struct_5
+%_ptr_Function__struct_3 = OpTypePointer Function %_struct_3
+          %1 = OpFunction %void None %8
+         %13 = OpLabel
+         %14 = OpVariable %_ptr_Function__struct_3 Function
+         %15 = OpLoad %_struct_3 %14
+         %16 = OpCompositeExtract %_ptr_PhysicalStorageBuffer__struct_5 %15 1
+         %17 = OpFunctionCall %_ptr_PhysicalStorageBuffer_int %18 %16
+               OpReturn
+               OpFunctionEnd
+         %18 = OpFunction %_ptr_PhysicalStorageBuffer_int None %11
+          %6 = OpFunctionParameter %_ptr_PhysicalStorageBuffer__struct_5
+         %19 = OpLabel
+         %20 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %6 %int_0
+               OpReturnValue %20
+               OpFunctionEnd)";
+
+  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
+}
+
 // TODO(greg-lunarg): Add tests to verify handling of these cases:
 //
 //    Empty modules
diff --git a/third_party/SPIRV-Tools/test/opt/inst_bindless_check_test.cpp b/third_party/SPIRV-Tools/test/opt/inst_bindless_check_test.cpp
index dd4b6f6..08da367 100644
--- a/third_party/SPIRV-Tools/test/opt/inst_bindless_check_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/inst_bindless_check_test.cpp
@@ -27,504 +27,18 @@
 
 using InstBindlessTest = PassTest<::testing::Test>;
 
-static const std::string kOutputDecorations = R"(
-; CHECK: OpDecorate [[output_buffer_type:%inst_bindless_OutputBuffer]] Block
-; CHECK: OpMemberDecorate [[output_buffer_type]] 0 Offset 0
-; CHECK: OpMemberDecorate [[output_buffer_type]] 1 Offset 4
-; CHECK: OpDecorate [[output_buffer_var:%\w+]] DescriptorSet 7
-; CHECK: OpDecorate [[output_buffer_var]] Binding 0
+static const std::string kFuncName = "inst_bindless_check_desc";
+
+static const std::string kImportDeco = R"(
+;CHECK: OpDecorate %)" + kFuncName + R"( LinkageAttributes ")" +
+                                       kFuncName + R"(" Import
 )";
 
-static const std::string kOutputGlobals = R"(
-; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %uint %_runtimearr_uint
-; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]]
-; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer
+static const std::string kImportStub = R"(
+;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}}
+;CHECK: OpFunctionEnd
 )";
 
-static const std::string kStreamWrite6Begin = R"(
-; CHECK: %inst_bindless_stream_write_6 = OpFunction %void None {{%\w+}}
-; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_6:%\w+]] = OpFunctionParameter %uint
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1
-; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_12
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12
-; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2
-; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_12
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_23
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_1]]
-)";
-
-static const std::string kStreamWrite6End = R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_2]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_3]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_4]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_5]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_6]]
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpReturn
-; CHECK: OpFunctionEnd
-)";
-
-// clang-format off
-static const std::string kStreamWrite6Frag = kStreamWrite6Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
-; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite6End;
-
-static const std::string kStreamWrite6Tese = kStreamWrite6Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_2
-; CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %v3float %gl_TessCoord
-; CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite6End;
-
-static const std::string kStreamWrite6Vert = kStreamWrite6Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite6End;
-
-static const std::string kStreamWrite6Compute = kStreamWrite6Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite6End;
-
-static const std::string kStreamWrite6Ray = kStreamWrite6Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite6End;
-// clang-format on
-
-static const std::string kStreamWrite7Begin = R"(
-; CHECK: %inst_bindless_stream_write_7 = OpFunction %void None {{%\w+}}
-; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_6:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_7:%\w+]] = OpFunctionParameter %uint
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1
-; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_13
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_13
-; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2
-; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_13
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_23
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_1]]
-)";
-
-static const std::string kStreamWrite7End = R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_2]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_3]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_4]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_5]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_6]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_7]]
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpReturn
-; CHECK: OpFunctionEnd
-)";
-
-// clang-format off
-static const std::string kStreamWrite7Frag = kStreamWrite7Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
-; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite7End;
-
-static const std::string kStreamWrite7Vert = kStreamWrite7Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite7End;
-// clang-format on
-
-static const std::string kInputDecorations = R"(
-; CHECK: OpDecorate [[desc_set_struct:%inst_bindless_DescriptorSetData]] Block
-; CHECK: OpMemberDecorate [[desc_set_struct]] 0 Offset 0
-; CHECK: OpMemberDecorate [[desc_set_struct]] 1 Offset 4
-; CHECK: OpDecorate [[input_buffer_type:%inst_bindless_InputBuffer]] Block
-; CHECK: OpMemberDecorate [[input_buffer_type]] 0 Offset 0
-; CHECK: OpDecorate [[input_buffer_var:%\w+]] DescriptorSet 7
-; CHECK: OpDecorate [[input_buffer_var]] Binding 1
-)";
-
-static const std::string kInputGlobals = R"(
-; CHECK: [[desc_set_struct]] = OpTypeStruct %uint %_runtimearr_uint
-; CHECK: [[desc_set_ptr:%\w+]] = OpTypePointer PhysicalStorageBuffer [[desc_set_struct]]
-; CHECK: [[desc_set_ptr_array:%\w+]] = OpTypeArray [[desc_set_ptr]] %uint_32
-; CHECK: [[input_buffer_type]] = OpTypeStruct [[desc_set_ptr_array]]
-; CHECK: [[input_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[input_buffer_type]]
-; CHECK: [[input_buffer_var]] = OpVariable [[input_ptr_type]] StorageBuffer
-)";
-
-static const std::string kReadBindingLength = R"(
-; CHECK: %inst_bindless_read_binding_length = OpFunction %uint None {{%\w+}}
-; CHECK: [[bl_desc_set_idx:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[bl_binding_idx:%\w+]] = OpFunctionParameter %uint
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[bl_desc_set_idx]] %uint_32
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpReturnValue %uint_0
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[bl_desc_set_idx]]
-; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData {{%\w+}}
-; CHECK: {{%\w+}} = OpBitcast %v2uint {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
-; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
-; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpLogicalAnd %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpReturnValue %uint_0
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 8
-; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[bl_binding_idx]] {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpReturnValue %uint_0
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 [[bl_binding_idx]]
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4
-; CHECK: OpReturnValue {{%\w+}}
-; CHECK: OpFunctionEnd
-)";
-
-static const std::string kReadDescInit = R"(
-; CHECK: %inst_bindless_read_desc_init = OpFunction %uint None {{%\w+}}
-; CHECK: [[di_desc_set_idx:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[di_binding_idx:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[di_desc_idx:%\w+]] = OpFunctionParameter %uint
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_set_idx]] %uint_32
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpReturnValue %uint_0
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[di_desc_set_idx]]
-; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData {{%\w+}}
-; CHECK: {{%\w+}} = OpBitcast %v2uint {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
-; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
-; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpLogicalAnd %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpReturnValue %uint_0
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_0
-; CHECK: [[di_num_bindings:%\w+]] = OpLoad %uint {{%\w+}} Aligned 8
-; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_binding_idx]] [[di_num_bindings]]
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpReturnValue %uint_0
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4
-; CHECK: OpReturnValue {{%\w+}}
-; CHECK: OpFunctionEnd
-)";
-
-TEST_F(InstBindlessTest, NoInstrumentConstIndexInbounds) {
-  // Texture2D g_tColor[128];
-  //
-  // SamplerState g_sAniso;
-  //
-  // struct PS_INPUT
-  // {
-  //   float2 vTextureCoords : TEXCOORD2;
-  // };
-  //
-  // struct PS_OUTPUT
-  // {
-  //   float4 vColor : SV_Target0;
-  // };
-  //
-  // PS_OUTPUT MainPs(PS_INPUT i)
-  // {
-  //   PS_OUTPUT ps_output;
-  //
-  //   ps_output.vColor = g_tColor[ 37 ].Sample(g_sAniso, i.vTextureCoords.xy);
-  //   return ps_output;
-  // }
-
-  const std::string before =
-      R"(OpCapability Shader
-%1 = OpExtInstImport "GLSL.std.450"
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-OpExecutionMode %MainPs OriginUpperLeft
-OpSource HLSL 500
-OpName %MainPs "MainPs"
-OpName %g_tColor "g_tColor"
-OpName %g_sAniso "g_sAniso"
-OpName %i_vTextureCoords "i.vTextureCoords"
-OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
-OpDecorate %g_tColor DescriptorSet 3
-OpDecorate %g_tColor Binding 5
-OpDecorate %g_sAniso DescriptorSet 3
-OpDecorate %i_vTextureCoords Location 0
-OpDecorate %_entryPointOutput_vColor Location 0
-%void = OpTypeVoid
-%8 = OpTypeFunction %void
-%float = OpTypeFloat 32
-%v2float = OpTypeVector %float 2
-%v4float = OpTypeVector %float 4
-%int = OpTypeInt 32 1
-%int_0 = OpConstant %int 0
-%int_37 = OpConstant %int 37
-%15 = OpTypeImage %float 2D 0 0 0 1 Unknown
-%uint = OpTypeInt 32 0
-%uint_128 = OpConstant %uint 128
-%_arr_15_uint_128 = OpTypeArray %15 %uint_128
-%_ptr_UniformConstant__arr_15_uint_128 = OpTypePointer UniformConstant %_arr_15_uint_128
-%g_tColor = OpVariable %_ptr_UniformConstant__arr_15_uint_128 UniformConstant
-%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
-%21 = OpTypeSampler
-%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
-%g_sAniso = OpVariable %_ptr_UniformConstant_21 UniformConstant
-%23 = OpTypeSampledImage %15
-%_ptr_Input_v2float = OpTypePointer Input %v2float
-%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
-%_ptr_Output_v4float = OpTypePointer Output %v4float
-%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-%MainPs = OpFunction %void None %8
-%26 = OpLabel
-%27 = OpLoad %v2float %i_vTextureCoords
-%28 = OpAccessChain %_ptr_UniformConstant_15 %g_tColor %int_37
-%29 = OpLoad %15 %28
-%30 = OpLoad %21 %g_sAniso
-%31 = OpSampledImage %23 %29 %30
-%32 = OpImageSampleImplicitLod %v4float %31 %27
-OpStore %_entryPointOutput_vColor %32
-OpReturn
-OpFunctionEnd
-)";
-
-  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndCheck<InstBindlessCheckPass>(
-      before, before, true, true, 7u, 23u, false, false, false, false, false);
-}
-
-TEST_F(InstBindlessTest, NoInstrumentNonBindless) {
-  // This test verifies that the pass will correctly not instrument vanilla
-  // texture sample.
-  //
-  // Texture2D g_tColor;
-  //
-  // SamplerState g_sAniso;
-  //
-  // struct PS_INPUT
-  // {
-  //   float2 vTextureCoords : TEXCOORD2;
-  // };
-  //
-  // struct PS_OUTPUT
-  // {
-  //   float4 vColor : SV_Target0;
-  // };
-  //
-  // PS_OUTPUT MainPs(PS_INPUT i)
-  // {
-  //   PS_OUTPUT ps_output;
-  //   ps_output.vColor =
-  //       g_tColor.Sample(g_sAniso, i.vTextureCoords.xy);
-  //   return ps_output;
-  // }
-
-  const std::string whole_file =
-      R"(OpCapability Shader
-%1 = OpExtInstImport "GLSL.std.450"
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-OpExecutionMode %MainPs OriginUpperLeft
-OpSource HLSL 500
-OpName %MainPs "MainPs"
-OpName %g_tColor "g_tColor"
-OpName %g_sAniso "g_sAniso"
-OpName %i_vTextureCoords "i.vTextureCoords"
-OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
-OpDecorate %g_tColor DescriptorSet 6
-OpDecorate %g_tColor Binding 4
-OpDecorate %g_sAniso DescriptorSet 6
-OpDecorate %g_sAniso Binding 4
-OpDecorate %i_vTextureCoords Location 0
-OpDecorate %_entryPointOutput_vColor Location 0
-%void = OpTypeVoid
-%8 = OpTypeFunction %void
-%float = OpTypeFloat 32
-%v2float = OpTypeVector %float 2
-%v4float = OpTypeVector %float 4
-%12 = OpTypeImage %float 2D 0 0 0 1 Unknown
-%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
-%g_tColor = OpVariable %_ptr_UniformConstant_12 UniformConstant
-%14 = OpTypeSampler
-%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
-%g_sAniso = OpVariable %_ptr_UniformConstant_14 UniformConstant
-%16 = OpTypeSampledImage %12
-%_ptr_Input_v2float = OpTypePointer Input %v2float
-%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
-%_ptr_Output_v4float = OpTypePointer Output %v4float
-%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-%MainPs = OpFunction %void None %8
-%19 = OpLabel
-%20 = OpLoad %v2float %i_vTextureCoords
-%21 = OpLoad %12 %g_tColor
-%22 = OpLoad %14 %g_sAniso
-%23 = OpSampledImage %16 %21 %22
-%24 = OpImageSampleImplicitLod %v4float %23 %20
-OpStore %_entryPointOutput_vColor %24
-OpReturn
-OpFunctionEnd
-)";
-
-  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndCheck<InstBindlessCheckPass>(whole_file, whole_file, true,
-                                               true, 7u, 23u, false, false,
-                                               false, false, false);
-}
-
 TEST_F(InstBindlessTest, Simple) {
   // Texture2D g_tColor[128];
   //
@@ -555,11 +69,11 @@
 
   const std::string entry = R"(
 OpCapability Shader
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpCapability Linkage
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
 OpExecutionMode %MainPs OriginUpperLeft
 OpSource HLSL 500
 )";
@@ -580,10 +94,10 @@
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %g_sAniso DescriptorSet 0
 OpDecorate %i_vTextureCoords Location 0
-OpDecorate %_entryPointOutput_vColor Location 0
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+OpDecorate %_entryPointOutput_vColor Location 0)"
++ kImportDeco +
+R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 )";
 
   const std::string consts_types_vars = R"(
@@ -613,15 +127,10 @@
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-; CHECK: %bool = OpTypeBool
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %MainPs = OpFunction %void None %10
@@ -635,32 +144,30 @@
 %36 = OpSampledImage %26 %34 %35
 %37 = OpImageSampleImplicitLod %v4float %36 %30
 OpStore %_entryPointOutput_vColor %37
-; CHECK-NOT: %37 = OpImageSampleImplicitLod %v4float %36 %30
-; CHECK-NOT: OpStore %_entryPointOutput_vColor %37
-; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} %uint_128
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %16 %33
-; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
-; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_56 %uint_0 %uint_3 %uint_0 %32 %uint_128
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
+;CHECK-NOT: %37 = OpImageSampleImplicitLod %v4float %36 %30
+;CHECK-NOT: OpStore %_entryPointOutput_vColor %37
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_57 {{%\w+}} %uint_3 %uint_0 %32 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %16 %33
+;CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string output_func = kStreamWrite6Frag;
+  // clang-format on
 
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass, uint32_t, uint32_t, bool, bool>(
-      entry + names_annots + consts_types_vars + main_func + output_func, true,
-      7u, 23u, false, false, false, false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(
+      entry + names_annots + consts_types_vars + kImportStub + main_func, true,
+      23u);
 }
 
 TEST_F(InstBindlessTest, InstrumentMultipleInstructions) {
@@ -697,11 +204,11 @@
   // clang-format off
   const std::string defs = R"(
 OpCapability Shader
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpCapability Linkage
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
 OpExecutionMode %MainPs OriginUpperLeft
 OpSource HLSL 500
 OpName %MainPs "MainPs"
@@ -720,9 +227,8 @@
 OpDecorate %g_sAniso DescriptorSet 3
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %10 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -750,20 +256,14 @@
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-; CHECK: %bool = OpTypeBool
-; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
-  const std::string main_func =
-      R"(%MainPs = OpFunction %void None %10
+  const std::string main_func = R"(
+%MainPs = OpFunction %void None %10
 %30 = OpLabel
 %31 = OpLoad %v2float %i_vTextureCoords
 %32 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
@@ -773,20 +273,24 @@
 %36 = OpLoad %25 %g_sAniso
 %37 = OpSampledImage %27 %35 %36
 %38 = OpImageSampleImplicitLod %v4float %37 %31
-; CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31
-; CHECK: %48 = OpULessThan %bool %33 %uint_128
-; CHECK: OpSelectionMerge %49 None
-; CHECK: OpBranchConditional %48 %50 %51
-; CHECK: %50 = OpLabel
-; CHECK: %52 = OpLoad %17 %34
-; CHECK: %53 = OpSampledImage %27 %52 %36
-; CHECK: %54 = OpImageSampleImplicitLod %v4float %53 %31
-; CHECK: OpBranch %49
-; CHECK: %51 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_58 %uint_0 %uint_3 %uint_4 %33 %uint_128
-; CHECK: OpBranch %49
-; CHECK: %49 = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float %54 %50 [[null_v4float]] %51
+;CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_60 {{%\w+}} %uint_3 %uint_4 %33 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %17 %34
+;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
 %39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1
 %40 = OpLoad %uint %39
 %41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40
@@ -794,33 +298,35 @@
 %43 = OpSampledImage %27 %42 %36
 %44 = OpImageSampleImplicitLod %v4float %43 %31
 %45 = OpFAdd %v4float %38 %44
-; CHECK-NOT: %44 = OpImageSampleImplicitLod %v4float %43 %31
-; CHECK-NOT: %45 = OpFAdd %v4float %38 %44
-; CHECK: {{%\w+}} = OpULessThan %bool %40 %uint_128
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %17 %41
-; CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
-; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_64 %uint_0 %uint_3 %uint_4 %40 %uint_128
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: %45 = OpFAdd %v4float {{%\w+}} {{%\w+}}
+;CHECK-NOT: %44 = OpImageSampleImplicitLod %v4float %43 %31
+;CHECK-NOT: %45 = OpFAdd %v4float %38 %44
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_66 {{%\w+}} %uint_3 %uint_4 %40 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %17 %41
+;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: %45 = OpFAdd %v4float {{%\w+}} {{%\w+}}
 OpStore %_entryPointOutput_vColor %45
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string output_func = kStreamWrite6Frag;
+  // clang-format on
 
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + output_func,
-                                               true, 7u, 23u, false, false,
-                                               false, false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstrumentOpImage) {
@@ -832,11 +338,11 @@
   const std::string defs = R"(
 OpCapability Shader
 OpCapability StorageImageReadWithoutFormat
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpCapability Linkage
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
 OpExecutionMode %MainPs OriginUpperLeft
 OpSource HLSL 500
 OpName %MainPs "MainPs"
@@ -852,9 +358,8 @@
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -878,17 +383,10 @@
 %i_vTextureCoords = OpVariable %_ptr_Input_v2int Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-; CHECK: uint_0 = OpConstant %uint 0
-; CHECK: bool = OpTypeBool
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %MainPs = OpFunction %void None %3
@@ -901,32 +399,34 @@
 %75 = OpImage %20 %66
 %71 = OpImageRead %v4float %75 %53
 OpStore %_entryPointOutput_vColor %71
-; CHECK-NOT: %71 = OpImageRead %v4float %75 %53
-; CHECK-NOT: OpStore %_entryPointOutput_vColor %71
-; CHECK: %78 = OpULessThan %bool %64 %uint_128
-; CHECK: OpSelectionMerge %79 None
-; CHECK: OpBranchConditional %78 %80 %81
-; CHECK: %80 = OpLabel
-; CHECK: %82 = OpLoad %39 %65
-; CHECK: %83 = OpImage %20 %82
-; CHECK: %84 = OpImageRead %v4float %83 %53
-; CHECK: OpBranch %79
-; CHECK: %81 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_3 %uint_9 %64 %uint_128
-; CHECK: OpBranch %79
-; CHECK: %79 = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float %84 %80 [[null_v4float]] %81
-; CHECK: OpStore %_entryPointOutput_vColor {{%\w+}}
+;CHECK-NOT: %71 = OpImageRead %v4float %75 %53
+;CHECK-NOT: OpStore %_entryPointOutput_vColor %71
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_9 %64 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %39 %65
+;CHECK: {{%\w+}} = OpImage %20 {{%\w+}}
+;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %53
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}}
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string output_func = kStreamWrite6Frag;
+  // clang-format on
 
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + output_func,
-                                               true, 7u, 23u, false, false,
-                                               false, false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstrumentSampledImage) {
@@ -937,11 +437,11 @@
   // clang-format off
   const std::string defs = R"(
 OpCapability Shader
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpCapability Linkage
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
 OpExecutionMode %MainPs OriginUpperLeft
 OpSource HLSL 500
 OpName %MainPs "MainPs"
@@ -957,8 +457,8 @@
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -982,17 +482,10 @@
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-; CHECK: uint_0 = OpConstant %uint 0
-; CHECK: bool = OpTypeBool
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %MainPs = OpFunction %void None %3
@@ -1004,31 +497,33 @@
 %66 = OpLoad %39 %65
 %71 = OpImageSampleImplicitLod %v4float %66 %53
 OpStore %_entryPointOutput_vColor %71
-; CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %66 %53
-; CHECK-NOT: OpStore %_entryPointOutput_vColor %71
-; CHECK: %74 = OpULessThan %bool %64 %uint_128
-; CHECK: OpSelectionMerge %75 None
-; CHECK: OpBranchConditional %74 %76 %77
-; CHECK: %76 = OpLabel
-; CHECK: %78 = OpLoad %39 %65
-; CHECK: %79 = OpImageSampleImplicitLod %v4float %78 %53
-; CHECK: OpBranch %75
-; CHECK: %77 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_49 %uint_0 %uint_4 %uint_11 %64 %uint_128
-; CHECK: OpBranch %75
-; CHECK: %75 = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float %79 %76 [[null_v4float]] %77
-; CHECK: OpStore %_entryPointOutput_vColor {{%\w+}}
+;CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %66 %53
+;CHECK-NOT: OpStore %_entryPointOutput_vColor %71
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_50 {{%\w+}} %uint_4 %uint_11 %64 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %39 %65
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %53
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}}
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string output_func = kStreamWrite6Frag;
+  // clang-format on
 
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + output_func,
-                                               true, 7u, 23u, false, false,
-                                               false, false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstrumentImageWrite) {
@@ -1040,11 +535,11 @@
   const std::string defs = R"(
 OpCapability Shader
 OpCapability StorageImageWriteWithoutFormat
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpCapability Linkage
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
 OpExecutionMode %MainPs OriginUpperLeft
 OpSource HLSL 500
 OpName %MainPs "MainPs"
@@ -1060,9 +555,8 @@
 OpDecorate %PerViewConstantBuffer_t Block
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -1087,13 +581,10 @@
 %i_vTextureCoords = OpVariable %_ptr_Input_v2int Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-)" + kOutputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %MainPs = OpFunction %void None %3
@@ -1105,30 +596,33 @@
 %66 = OpLoad %20 %65
 OpImageWrite %66 %53 %80
 OpStore %_entryPointOutput_vColor %80
-; CHECK-NOT: OpImageWrite %66 %53 %80
-; CHECK-NOT: OpStore %_entryPointOutput_vColor %80
-; CHECK: %35 = OpULessThan %bool %30 %uint_128
-; CHECK: OpSelectionMerge %36 None
-; CHECK: OpBranchConditional %35 %37 %38
-; CHECK: %37 = OpLabel
-; CHECK: %39 = OpLoad %16 %31
-; CHECK: OpImageWrite %39 %28 %19
-; CHECK: OpBranch %36
-; CHECK: %38 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_30 %uint_2 %30 %uint_128
-; CHECK: OpBranch %36
-; CHECK: %36 = OpLabel
-; CHECK: OpStore %_entryPointOutput_vColor %19
+;CHECK-NOT: OpImageWrite %66 %53 %80
+;CHECK-NOT: OpStore %_entryPointOutput_vColor %80
+;CHECK: %32 = OpLoad %16 %31
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_30 %uint_2 %30 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %16 %31
+;CHECK: OpImageWrite {{%\w+}} %28 %19
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %_entryPointOutput_vColor %19
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string output_func = kStreamWrite6Frag;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + output_func,
-                                               true, 7u, 23u, false, false,
-                                               false, false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstrumentVertexSimple) {
@@ -1140,7 +634,7 @@
   const std::string defs = R"(
 OpCapability Shader
 OpCapability Sampled1D
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpCapability Linkage
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Vertex %main "main" %_ %coords2D
@@ -1159,10 +653,9 @@
 OpMemberName %foo 0 "g_idx"
 OpName %__0 ""
 OpName %coords2D "coords2D"
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
-; CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
 OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
 OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
 OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
@@ -1205,16 +698,11 @@
 %v2float = OpTypeVector %float 2
 %_ptr_Input_v2float = OpTypePointer Input %v2float
 %coords2D = OpVariable %_ptr_Input_v2float Input
-; CHECK: %bool = OpTypeBool
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
-; CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input
-; CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
+;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input
+;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -1232,34 +720,51 @@
 %38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37
 %40 = OpAccessChain %_ptr_Output_v4float %_ %int_0
 OpStore %40 %38
-; CHECK-NOT: %38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37
-; CHECK-NOT: %40 = OpAccessChain %_ptr_Output_v4float %_ %int_0
-; CHECK-NOT: OpStore %40 %38
-; CHECK: %46 = OpULessThan %bool %37 %uint_128
-; CHECK: OpSelectionMerge %47 None
-; CHECK: OpBranchConditional %46 %48 %49
-; CHECK: %48 = OpLabel
-; CHECK: %50 = OpLoad %25 %38
-; CHECK: %51 = OpImageSampleExplicitLod %v4float %50 %40 Lod %41
-; CHECK: OpBranch %47
-; CHECK: %49 = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %37
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_74 %uint_0 %uint_2 %uint_13 {{%\w+}} %uint_128
-; CHECK: OpBranch %47
-; CHECK: %47 = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float %51 %48 [[null_v4float]] %49
-; CHECK: %43 = OpAccessChain %_ptr_Output_v4float %_ %int_0
-; CHECK: OpStore %43 {{%\w+}}
+;CHECK-NOT: %38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37
+;CHECK-NOT: %40 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+;CHECK-NOT: OpStore %40 %38
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_70 {{%\w+}} %uint_7 %uint_5 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %int {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %int {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_25 %texSampler1D {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %float %coords1D
+;CHECK: {{%\w+}} = OpLoad %float %lod
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_75 {{%\w+}} %uint_2 %uint_13 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %25 %38
+;CHECK: {{%\w+}} = OpImageSampleExplicitLod %v4float {{%\w+}} %40 Lod %41
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: %43 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+;CHECK: OpStore %43 {{%\w+}}
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string output_func = kStreamWrite6Vert;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + output_func,
-                                               true, 7u, 23u, false, false,
-                                               false, false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstrumentTeseSimple) {
@@ -1284,10 +789,11 @@
 
   const std::string defs = R"(
 OpCapability Tessellation
+;CHECK: OpCapability Linkage
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint TessellationEvaluation %main "main" %_
-; CHECK: OpEntryPoint TessellationEvaluation %main "main" %_ %gl_PrimitiveID %gl_TessCoord
+;CHECK: OpEntryPoint TessellationEvaluation %main "main" %_ %gl_PrimitiveID %gl_TessCoord
 OpExecutionMode %main Triangles
 OpExecutionMode %main SpacingEqual
 OpExecutionMode %main VertexOrderCw
@@ -1319,10 +825,9 @@
 OpDecorate %ufoo Block
 OpDecorate %uniform_index_buffer DescriptorSet 9
 OpDecorate %uniform_index_buffer Binding 2
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId
-; CHECK: OpDecorate %gl_TessCoord BuiltIn TessCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId
+;CHECK: OpDecorate %gl_TessCoord BuiltIn TessCoord
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -1346,53 +851,322 @@
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
 %_ptr_Output_v4float = OpTypePointer Output %v4float
-; CHECK: %bool = OpTypeBool
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
-; CHECK: %gl_PrimitiveID = OpVariable %_ptr_Input_uint Input
-; CHECK: %v3float = OpTypeVector %float 3
-; CHECK: %_ptr_Input_v3float = OpTypePointer Input %v3float
-; CHECK: %gl_TessCoord = OpVariable %_ptr_Input_v3float Input
-; CHECK: %v3uint = OpTypeVector %uint 3
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
+;CHECK: %gl_PrimitiveID = OpVariable %_ptr_Input_uint Input
+;CHECK: %v3float = OpTypeVector %float 3
+;CHECK: %_ptr_Input_v3float = OpTypePointer Input %v3float
+;CHECK: %gl_TessCoord = OpVariable %_ptr_Input_v3float Input
+;CHECK: %v3uint = OpTypeVector %uint 3
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
-  const std::string main_func = R"(
+  const std::string main_func =
+      R"(
 %main = OpFunction %void None %3
 %5 = OpLabel
 %25 = OpAccessChain %_ptr_Uniform_uint %uniform_index_buffer %int_0
 %26 = OpLoad %uint %25
 %28 = OpAccessChain %_ptr_StorageBuffer_v4float %adds %26 %int_0
 %29 = OpLoad %v4float %28
-; CHECK-NOT: %29 = OpLoad %v4float %28
-; CHECK: %34 = OpULessThan %bool %28 %uint_11
-; CHECK: OpSelectionMerge %35 None
-; CHECK: OpBranchConditional %34 %36 %37
-; CHECK: %36 = OpLabel
-; CHECK: %38 = OpLoad %v4float %29
-; CHECK: OpBranch %35
-; CHECK: %37 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_63 %uint_0 %uint_9 %uint_1 %28 %uint_11
-; CHECK: OpBranch %35
-; CHECK: %35 = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float %38 %36 [[null_v4float]] %37
+;CHECK-NOT: %29 = OpLoad %v4float %28
+;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID
+;CHECK: {{%\w+}} = OpLoad %v3float %gl_TessCoord
+;CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_2 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_62 {{%\w+}} %uint_9 %uint_2 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %uint %27
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
 %31 = OpAccessChain %_ptr_Output_v4float %_ %int_0
 OpStore %31 %29
-; CHECK-NOT: OpStore %31 %29
-; CHECK: OpStore %31 {{%\w+}}
+;CHECK-NOT: OpStore %31 %29
+;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID
+;CHECK: {{%\w+}} = OpLoad %v3float %gl_TessCoord
+;CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_2 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_64 {{%\w+}} %uint_9 %uint_1 {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %v4float %29
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: %31 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+;CHECK: OpStore %31 [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string output_func = kStreamWrite6Tese;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + output_func,
-                                               true, 7u, 23u, false, false,
-                                               false, false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
+}
+
+TEST_F(InstBindlessTest, InstrumentTesc) {
+  // This test verifies that the pass will correctly instrument tessellation
+  // control shader
+  //
+  // clang-format off
+  //
+  // #version 450
+  // layout(vertices = 3) out;
+  // layout(set = 0, binding = 0) uniform texture1D _77;
+  // layout(set = 0, binding = 1) uniform sampler _78;
+
+  // layout(location = 1) flat in int _3[];
+  // layout(location = 0) out vec4 _5[3];
+
+  // void main()
+  // {
+  //     float param;
+  //     if (_3[gl_InvocationID] == 0)
+  //     {
+  //         param = 0.0234375;
+  //     }
+  //     else
+  //     {
+  //         param = 1.0156199932098388671875;
+  //     }
+  //     _5[gl_InvocationID] = textureLod(sampler1D(_77, _78), param, 0.0);
+  //     vec4 _203;
+  //     if (gl_InvocationID == 0)
+  //     {
+  //         _203 = gl_in[0].gl_Position;
+  //     }
+  //     else
+  //     {
+  //         _203 = gl_in[2].gl_Position;
+  //     }
+  //     gl_out[gl_InvocationID].gl_Position = _203;
+  //     gl_TessLevelInner[0] = 2.7999999523162841796875;
+  //     gl_TessLevelInner[1] = 2.7999999523162841796875;
+  //     gl_TessLevelOuter[0] = 2.7999999523162841796875;
+  //     gl_TessLevelOuter[1] = 2.7999999523162841796875;
+  //     gl_TessLevelOuter[2] = 2.7999999523162841796875;
+  //     gl_TessLevelOuter[3] = 2.7999999523162841796875;
+  // }
+  //
+  // clang-format on
+  //
+  //
+
+  // clang-format off
+  const std::string defs = R"(
+OpCapability Tessellation
+OpCapability Sampled1D
+;CHECK: OpCapability Linkage
+;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpExtension "SPV_KHR_physical_storage_buffer"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+;CHECK: OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint TessellationControl %main "main" %_3 %gl_InvocationID %_5 %gl_in %gl_out %gl_TessLevelInner %gl_TessLevelOuter
+;CHECK: OpEntryPoint TessellationControl %main "main" %_3 %gl_InvocationID %_5 %gl_in %gl_out %gl_TessLevelInner %gl_TessLevelOuter %gl_PrimitiveID
+OpExecutionMode %main OutputVertices 3
+OpSource GLSL 450
+OpName %main "main"
+OpName %_3 "_3"
+OpName %gl_InvocationID "gl_InvocationID"
+OpName %param "param"
+OpName %_5 "_5"
+OpName %_77 "_77"
+OpName %_78 "_78"
+OpName %_203 "_203"
+OpName %gl_PerVertex "gl_PerVertex"
+OpMemberName %gl_PerVertex 0 "gl_Position"
+OpMemberName %gl_PerVertex 1 "gl_PointSize"
+OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
+OpMemberName %gl_PerVertex 3 "gl_CullDistance"
+OpName %gl_in "gl_in"
+OpName %gl_PerVertex_0 "gl_PerVertex"
+OpMemberName %gl_PerVertex_0 0 "gl_Position"
+OpMemberName %gl_PerVertex_0 1 "gl_PointSize"
+OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance"
+OpMemberName %gl_PerVertex_0 3 "gl_CullDistance"
+OpName %gl_out "gl_out"
+OpName %gl_TessLevelInner "gl_TessLevelInner"
+OpName %gl_TessLevelOuter "gl_TessLevelOuter"
+OpDecorate %_3 Flat
+OpDecorate %_3 Location 1
+OpDecorate %gl_InvocationID BuiltIn InvocationId
+OpDecorate %_5 Location 0
+OpDecorate %_77 DescriptorSet 0
+OpDecorate %_77 Binding 0
+OpDecorate %_78 DescriptorSet 0
+OpDecorate %_78 Binding 1
+OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
+OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
+OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
+OpDecorate %gl_PerVertex Block
+OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
+OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize
+OpMemberDecorate %gl_PerVertex_0 2 BuiltIn ClipDistance
+OpMemberDecorate %gl_PerVertex_0 3 BuiltIn CullDistance
+OpDecorate %gl_PerVertex_0 Block
+OpDecorate %gl_TessLevelInner Patch
+OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
+OpDecorate %gl_TessLevelOuter Patch
+OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%_arr_int_uint_32 = OpTypeArray %int %uint_32
+%_ptr_Input__arr_int_uint_32 = OpTypePointer Input %_arr_int_uint_32
+%_3 = OpVariable %_ptr_Input__arr_int_uint_32 Input
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_InvocationID = OpVariable %_ptr_Input_int Input
+%int_0 = OpConstant %int 0
+%bool = OpTypeBool
+%float = OpTypeFloat 32
+%_ptr_Function_float = OpTypePointer Function %float
+%float_0_0234375 = OpConstant %float 0.0234375
+%float_1_01561999 = OpConstant %float 1.01561999
+%v4float = OpTypeVector %float 4
+%uint_3 = OpConstant %uint 3
+%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3
+%_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3
+%_5 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output
+%34 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_34 = OpTypePointer UniformConstant %34
+%_77 = OpVariable %_ptr_UniformConstant_34 UniformConstant
+%38 = OpTypeSampler
+%_ptr_UniformConstant_38 = OpTypePointer UniformConstant %38
+%_78 = OpVariable %_ptr_UniformConstant_38 UniformConstant
+%42 = OpTypeSampledImage %34
+%float_0 = OpConstant %float 0
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%uint_1 = OpConstant %uint 1
+%_arr_float_uint_1 = OpTypeArray %float %uint_1
+%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32
+%_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32
+%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%int_2 = OpConstant %int 2
+%gl_PerVertex_0 = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%_arr_gl_PerVertex_0_uint_3 = OpTypeArray %gl_PerVertex_0 %uint_3
+%_ptr_Output__arr_gl_PerVertex_0_uint_3 = OpTypePointer Output %_arr_gl_PerVertex_0_uint_3
+%gl_out = OpVariable %_ptr_Output__arr_gl_PerVertex_0_uint_3 Output
+%uint_2 = OpConstant %uint 2
+%_arr_float_uint_2 = OpTypeArray %float %uint_2
+%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2
+%gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output
+%float_2_79999995 = OpConstant %float 2.79999995
+%_ptr_Output_float = OpTypePointer Output %float
+%int_1 = OpConstant %int 1
+%uint_4 = OpConstant %uint 4
+%_arr_float_uint_4 = OpTypeArray %float %uint_4
+%_ptr_Output__arr_float_uint_4 = OpTypePointer Output %_arr_float_uint_4
+%gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output
+%int_3 = OpConstant %int 3
+)";
+
+  const std::string main_func =
+      R"(
+%main = OpFunction %void None %3
+%5 = OpLabel
+%param = OpVariable %_ptr_Function_float Function
+%_203 = OpVariable %_ptr_Function_v4float Function
+%14 = OpLoad %int %gl_InvocationID
+%15 = OpAccessChain %_ptr_Input_int %_3 %14
+%16 = OpLoad %int %15
+%19 = OpIEqual %bool %16 %int_0
+OpSelectionMerge %21 None
+OpBranchConditional %19 %20 %26
+%20 = OpLabel
+;CHECK-NOT: %15 = OpAccessChain %_ptr_Input_int %_3 %14
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %int %gl_InvocationID
+;CHECK: {{%\w+}} = OpAccessChain %_ptr_Input_int %_3 {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %int {{%\w+}}
+;CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %int_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+OpStore %param %float_0_0234375
+OpBranch %21
+%26 = OpLabel
+OpStore %param %float_1_01561999
+OpBranch %21
+%21 = OpLabel
+%33 = OpLoad %int %gl_InvocationID
+%37 = OpLoad %34 %_77
+%41 = OpLoad %38 %_78
+%43 = OpSampledImage %42 %37 %41
+%44 = OpLoad %float %param
+;CHECK: {{%\w+}} = OpLoad %int %gl_InvocationID
+;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_1 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_check_desc %uint_23 %uint_129 {{%\w+}} %uint_0 %uint_0 %uint_0 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+%46 = OpImageSampleExplicitLod %v4float %43 %44 Lod %float_0
+%48 = OpAccessChain %_ptr_Output_v4float %_5 %33
+OpStore %48 %46
+;CHECK-NOT: %48 = OpAccessChain %_ptr_Output_v4float %_5 %33
+;CHECK-NOT: OpStore %48 %46
+;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: [[access_chain:%\w+]] = OpAccessChain %_ptr_Output_v4float %_5 {{%\w+}}
+;CHECK: OpStore [[access_chain]] [[phi_result]]
+%49 = OpLoad %int %gl_InvocationID
+%50 = OpIEqual %bool %49 %int_0
+OpSelectionMerge %52 None
+OpBranchConditional %50 %51 %64
+%51 = OpLabel
+%62 = OpAccessChain %_ptr_Input_v4float %gl_in %int_0 %int_0
+%63 = OpLoad %v4float %62
+OpStore %_203 %63
+OpBranch %52
+%64 = OpLabel
+%66 = OpAccessChain %_ptr_Input_v4float %gl_in %int_2 %int_0
+%67 = OpLoad %v4float %66
+OpStore %_203 %67
+OpBranch %52
+%52 = OpLabel
+%72 = OpLoad %int %gl_InvocationID
+%73 = OpLoad %v4float %_203
+%74 = OpAccessChain %_ptr_Output_v4float %gl_out %72 %int_0
+OpStore %74 %73
+%81 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %int_0
+OpStore %81 %float_2_79999995
+%83 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %int_1
+OpStore %83 %float_2_79999995
+%88 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_0
+OpStore %88 %float_2_79999995
+%89 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_1
+OpStore %89 %float_2_79999995
+%90 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_2
+OpStore %90 %float_2_79999995
+%92 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_3
+OpStore %92 %float_2_79999995
+OpReturn
+OpFunctionEnd
+)";
+  // clang-format on
+
+  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, MultipleDebugFunctions) {
@@ -1402,11 +1176,11 @@
   // clang-format off
   const std::string defs = R"(
 OpCapability Shader
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpCapability Linkage
 %2 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
 OpExecutionMode %MainPs OriginUpperLeft
 %1 = OpString "foo5.frag"
 OpSource HLSL 500 %1
@@ -1435,9 +1209,8 @@
 OpDecorate %g_sAniso Binding 3
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %4 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -1471,16 +1244,10 @@
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-; CHECK: %bool = OpTypeBool
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string func1 = R"(
 %MainPs = OpFunction %void None %4
@@ -1515,41 +1282,43 @@
 %43 = OpAccessChain %_ptr_Function_v2float %i %int_0
 %44 = OpLoad %v2float %43
 %45 = OpImageSampleImplicitLod %v4float %41 %44
-; CHECK-NOT: %45 = OpImageSampleImplicitLod %v4float %41 %44
-; CHECK: OpNoLine
-; CHECK: %62 = OpULessThan %bool %50 %uint_128
-; CHECK: OpSelectionMerge %63 None
-; CHECK: OpBranchConditional %62 %64 %65
-; CHECK: %64 = OpLabel
-; CHECK: %66 = OpLoad %27 %51
-; CHECK: %67 = OpSampledImage %37 %66 %53
-; CHECK: OpLine %5 24 0
-; CHECK: %68 = OpImageSampleImplicitLod %v4float %67 %56
-; CHECK: OpNoLine
-; CHECK: OpBranch %63
-; CHECK: %65 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_109 %uint_0 %uint_1 %uint_2 %50 %uint_128
-; CHECK: OpBranch %63
-; CHECK: %63 = OpLabel
-; CHECK: [[phi_result:%\w+]] = OpPhi %v4float %68 %64 [[null_v4float]] %65
-; CHECK: OpLine %5 24 0
+;CHECK-NOT: %45 = OpImageSampleImplicitLod %v4float %41 %44
+;CHECK: {{%\w+}} = OpLoad %v2float {{%\w+}}
+;CHECK: OpNoLine
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_128 {{%\w+}} %uint_1 %uint_2 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %27 {{%\w+}}
+;CHECK: {{%\w+}} = OpSampledImage %37 {{%\w+}} {{%\w+}}
+;CHECK: OpLine %5 24 0
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} {{%\w+}}
+;CHECK: OpNoLine
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
 %47 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
 OpStore %47 %45
-; CHECK-NOT: OpStore %47 %45
-; CHECK: [[store_loc:%\w+]] = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
-; CHECK: OpStore [[store_loc]] [[phi_result]]
+;CHECK-NOT: OpStore %47 %45
+;CHECK: [[store_loc:%\w+]] = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
+;CHECK: OpStore [[store_loc]] [[phi_result]]
 OpLine %1 25 0
 %48 = OpLoad %PS_OUTPUT %ps_output
 OpReturnValue %48
 OpFunctionEnd
 )";
-
-  const std::string output_func = kStreamWrite6Frag;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(
-      defs + func1 + func2 + output_func, true, 7u, 23u, false, false, false,
-      false, false);
+      defs + kImportStub + func1 + func2, true, 23u);
 }
 
 TEST_F(InstBindlessTest, RuntimeArray) {
@@ -1561,12 +1330,12 @@
   const std::string defs = R"(
 OpCapability Shader
 OpCapability RuntimeDescriptorArray
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
 OpExecutionMode %MainPs OriginUpperLeft
 OpSource HLSL 500
 OpName %MainPs "MainPs"
@@ -1585,9 +1354,8 @@
 OpDecorate %g_sAniso Binding 3
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -1614,13 +1382,10 @@
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %MainPs = OpFunction %void None %3
@@ -1634,47 +1399,34 @@
 %68 = OpSampledImage %39 %66 %67
 %71 = OpImageSampleImplicitLod %v4float %68 %53
 OpStore %_entryPointOutput_vColor %71
-; CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %68 %53
-; CHECK-NOT: OpStore %_entryPointOutput_vColor %71
-; CHECK: [[length_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_2
-; CHECK: {{%\w+}} = OpULessThan %bool %32 [[length_result]]
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %16 %33
-; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
-; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %32
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[state_result]]
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %16 %33
-; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
-; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_59 %uint_1 %uint_1 %uint_2 %32 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_59 %uint_0 %uint_1 %uint_2 %32 {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpStore %_entryPointOutput_vColor [[phi_result_2]]
+;CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %68 %53
+;CHECK-NOT: OpStore %_entryPointOutput_vColor %71
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_60 {{%\w+}} %uint_1 %uint_2 %32 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %16 %33
+;CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %_entryPointOutput_vColor [[phi_result_1]]
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Frag + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptor) {
@@ -1688,11 +1440,11 @@
   // clang-format off
   const std::string defs = R"(
 OpCapability Shader
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpCapability Linkage
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
-; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
 OpExecutionMode %MainPs OriginUpperLeft
 OpSource HLSL 500
 OpName %MainPs "MainPs"
@@ -1706,9 +1458,8 @@
 OpDecorate %g_sAniso Binding 2
 OpDecorate %i_vTextureCoords Location 0
 OpDecorate %_entryPointOutput_vColor Location 0
-; check: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; check: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %8 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -1725,13 +1476,8 @@
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %MainPs = OpFunction %void None %8
@@ -1742,46 +1488,38 @@
 %23 = OpSampledImage %16 %21 %22
 %24 = OpImageSampleImplicitLod %v4float %23 %20
 OpStore %_entryPointOutput_vColor %24
-; CHECK-NOT: %24 = OpImageSampleImplicitLod %v4float %23 %20
-; CHECK-NOT: OpStore %_entryPointOutput_vColor %24
-; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[state_result]]
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %12 %g_tColor
-; CHECK: {{%\w+}} = OpSampledImage %16 {{%\w+}} %22
-; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_39 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
+;CHECK-NOT: %24 = OpImageSampleImplicitLod %v4float %23 %20
+;CHECK-NOT: OpStore %_entryPointOutput_vColor %24
+;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_40 {{%\w+}} %uint_1 %uint_2 %uint_0 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %12 %g_tColor
+;CHECK: {{%\w+}} = OpSampledImage %16 {{%\w+}} %22
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs = kReadDescInit + kStreamWrite6Frag;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, SPV14AddToEntryPoint) {
   const std::string text = R"(
-; CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]]
-; CHECK: OpDecorate [[v1]] DescriptorSet 7
-; CHECK: OpDecorate [[v2]] DescriptorSet 7
-; CHECK: [[v1]] = OpVariable {{%\w+}} StorageBuffer
-; CHECK: [[v2]] = OpVariable {{%\w+}} StorageBuffer
 OpCapability Shader
 OpExtension "SPV_EXT_descriptor_indexing"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var
+;CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} %gl_FragCoord
 OpExecutionMode %foo OriginUpperLeft
 OpDecorate %image_var DescriptorSet 4
 OpDecorate %image_var Binding 1
@@ -1824,23 +1562,19 @@
 )";
 
   SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
-                                               false, false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, SPV14AddToEntryPoints) {
   const std::string text = R"(
-; CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]]
-; CHECK: OpEntryPoint Fragment {{%\w+}} "bar" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]]
-; CHECK: OpDecorate [[v1]] DescriptorSet 7
-; CHECK: OpDecorate [[v2]] DescriptorSet 7
-; CHECK: [[v1]] = OpVariable {{%\w+}} StorageBuffer
-; CHECK: [[v2]] = OpVariable {{%\w+}} StorageBuffer
 OpCapability Shader
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var
+;CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} %gl_FragCoord
 OpEntryPoint Fragment %foo "bar" %gid %image_var %sampler_var
+;CHECK: OpEntryPoint Fragment {{%\w+}} "bar" {{%\w+}} {{%\w+}} {{%\w+}} %gl_FragCoord
 OpExecutionMode %foo OriginUpperLeft
 OpDecorate %image_var DescriptorSet 3
 OpDecorate %image_var Binding 2
@@ -1883,8 +1617,7 @@
 )";
 
   SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
-                                               false, false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) {
@@ -1907,12 +1640,12 @@
 OpCapability ShaderNonUniform
 OpCapability RuntimeDescriptorArray
 OpCapability UniformBufferArrayNonUniformIndexing
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %main "main" %b %nu_ii
-; CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
 OpExecutionMode %main OriginUpperLeft
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
@@ -1932,12 +1665,10 @@
 OpDecorate %nu_ii NonUniform
 OpDecorate %16 NonUniform
 OpDecorate %20 NonUniform
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + R"(
-; CHECK: OpDecorate {{%\w+}} NonUniform
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
-; CHECK: OpDecorate {{%\w+}} NonUniform
+;CHECK: OpDecorate {{%\w+}} NonUniform
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+;CHECK: OpDecorate {{%\w+}} NonUniform
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -1952,14 +1683,12 @@
 %nu_ii = OpVariable %_ptr_Input_int Input
 %int_0 = OpConstant %int 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: %v4float = OpTypeVector %float 4
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_float:%\w+]] = OpConstantNull %float
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %v4float = OpTypeVector %float 4
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_float:%\w+]] = OpConstantNull %float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -1968,46 +1697,33 @@
 %19 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %16 %int_0
 %20 = OpLoad %float %19
 OpStore %b %20
-; CHECK-NOT: %20 = OpLoad %float %19
-; CHECK-NOT: OpStore %b %20
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_6 %uint_3
-; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_6 %uint_3 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %float %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_6 %uint_3 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_6 %uint_3 [[bitcast_result]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}}
-; CHECK: OpStore %b [[phi_result_2]]
+;CHECK-NOT: %20 = OpLoad %float %19
+;CHECK-NOT: OpStore %b %20
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpBitcast %uint %7
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_6 %uint_3 {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %float %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpStore %b [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Frag + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) {
@@ -2030,12 +1746,12 @@
 OpCapability ShaderNonUniform
 OpCapability RuntimeDescriptorArray
 OpCapability StorageBufferArrayNonUniformIndexing
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %main "main" %b %nu_ii
-; CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
 OpExecutionMode %main OriginUpperLeft
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
@@ -2055,9 +1771,8 @@
 OpDecorate %nu_ii NonUniform
 OpDecorate %16 NonUniform
 OpDecorate %20 NonUniform
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -2072,16 +1787,13 @@
 %nu_ii = OpVariable %_ptr_Input_int Input
 %int_0 = OpConstant %int 0
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
-; CHECK: %uint = OpTypeInt 32 0
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: %v4float = OpTypeVector %float 4
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_float:%\w+]] = OpConstantNull %float
+;CHECK: %uint = OpTypeInt 32 0
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %v4float = OpTypeVector %float 4
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_float:%\w+]] = OpConstantNull %float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -2090,46 +1802,33 @@
 %19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0
 %20 = OpLoad %float %19
 OpStore %b %20
-; CHECK-NOT: %20 = OpLoad %float %19
-; CHECK-NOT: OpStore %b %20
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_7 %uint_3
-; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[bitcast_result_1:%\w+]] = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_7 %uint_3 [[bitcast_result_1]]
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %float %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_7 %uint_3 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[bitcast_result_2:%\w+]] = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_7 %uint_3 [[bitcast_result_2]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}}
-; CHECK: OpStore %b [[phi_result_2]]
+;CHECK-NOT: %20 = OpLoad %float %19
+;CHECK-NOT: OpStore %b %20
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpBitcast %uint %7
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_7 %uint_3 {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %float %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpStore %b [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Frag + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArray) {
@@ -2141,12 +1840,12 @@
 OpCapability ShaderNonUniform
 OpCapability RuntimeDescriptorArray
 OpCapability StorageBufferArrayNonUniformIndexing
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %main "main" %b %nu_ii
-; CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
 OpExecutionMode %main OriginUpperLeft
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
@@ -2166,12 +1865,10 @@
 OpDecorate %nu_ii NonUniform
 OpDecorate %16 NonUniform
 OpDecorate %20 NonUniform
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + R"(
-; CHECK: OpDecorate {{%\w+}} NonUniform
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
-; CHECK: OpDecorate {{%\w+}} NonUniform
+;CHECK: OpDecorate {{%\w+}} NonUniform
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+;CHECK: OpDecorate {{%\w+}} NonUniform
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -2186,14 +1883,12 @@
 %nu_ii = OpVariable %_ptr_Input_int Input
 %int_0 = OpConstant %int 0
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: %v4float = OpTypeVector %float 4
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_float:%\w+]] = OpConstantNull %float
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %v4float = OpTypeVector %float 4
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_float:%\w+]] = OpConstantNull %float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -2202,46 +1897,33 @@
 %19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0
 %20 = OpLoad %float %19
 OpStore %b %20
-; CHECK-NOT: %20 = OpLoad %float %19
-; CHECK-NOT: OpStore %b %20
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3
-; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %float %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_0 %uint_3 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_0 %uint_3 [[bitcast_result]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}}
-; CHECK: OpStore %b [[phi_result_2]]
+;CHECK-NOT: %20 = OpLoad %float %19
+;CHECK-NOT: OpStore %b %20
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpBitcast %uint %7
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_3 {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %float %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpStore %b {{%\w+}}
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Frag + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstInitLoadUBOScalar) {
@@ -2259,12 +1941,12 @@
   // clang-format off
   const std::string defs = R"(
 OpCapability Shader
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %main "main" %b
-; CHECK: OpEntryPoint Fragment %main "main" %b %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %main "main" %b %gl_FragCoord
 OpExecutionMode %main OriginUpperLeft
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
@@ -2278,9 +1960,8 @@
 OpDecorate %uname Block
 OpDecorate %uniformBuffer DescriptorSet 7
 OpDecorate %uniformBuffer Binding 3
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -2292,18 +1973,15 @@
 %int = OpTypeInt 32 1
 %int_0 = OpConstant %int 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-; CHECK: %int = OpTypeInt 32 1
-; CHECK: %_ptr_Uniform_float = OpTypePointer Uniform %float
-; CHECK: %uint = OpTypeInt 32 0
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: %v4float = OpTypeVector %float 4
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_float:%\w+]] = OpConstantNull %float
+;CHECK: %int = OpTypeInt 32 1
+;CHECK: %_ptr_Uniform_float = OpTypePointer Uniform %float
+;CHECK: %uint = OpTypeInt 32 0
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %v4float = OpTypeVector %float 4
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_float:%\w+]] = OpConstantNull %float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -2311,31 +1989,32 @@
 %15 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %int_0
 %16 = OpLoad %float %15
 OpStore %b %16
-; CHECK-NOT: %16 = OpLoad %float %15
-; CHECK-NOT: OpStore %b %16
-; CHECK: [[check_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_7 %uint_3 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[check_result]]
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %float %15
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_32 %uint_1 %uint_7 %uint_3 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
-; CHECK: OpStore %b [[phi_result]]
+;CHECK-NOT: %16 = OpLoad %float %15
+;CHECK-NOT: OpStore %b %16
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_33 {{%\w+}} %uint_7 %uint_3 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %float %15
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpStore %b [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs = kReadDescInit + kStreamWrite6Frag;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) {
@@ -2357,12 +2036,12 @@
 OpCapability ShaderNonUniform
 OpCapability RuntimeDescriptorArray
 OpCapability StorageBufferArrayNonUniformIndexing
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %main "main" %nu_ii %b
-; CHECK: OpEntryPoint Fragment %main "main" %nu_ii %b %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %main "main" %nu_ii %b %gl_FragCoord
 OpExecutionMode %main OriginUpperLeft
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
@@ -2381,9 +2060,8 @@
 OpDecorate %nu_ii NonUniform
 OpDecorate %14 NonUniform
 OpDecorate %b Location 1
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -2398,11 +2076,9 @@
 %_ptr_Input_float = OpTypePointer Input %float
 %b = OpVariable %_ptr_Input_float Input
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -2411,42 +2087,30 @@
 %18 = OpLoad %float %b
 %20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0
 OpStore %20 %18
-; CHECK-NOT: OpStore %20 %18
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_5 %uint_4
-; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_4 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpStore %20 %19
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_5 %uint_4 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_5 %uint_4 {{%\w+}} {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
+;CHECK-NOT: OpStore %20 %18
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpBitcast %uint %7
+;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_5 %uint_4 {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %20 %19
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Frag + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) {
@@ -2468,12 +2132,12 @@
 OpCapability Shader
 OpCapability ShaderNonUniform
 OpCapability UniformBufferArrayNonUniformIndexing
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %main "main" %b %nu_ii
-; CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
 OpExecutionMode %main OriginUpperLeft
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
@@ -2493,11 +2157,9 @@
 OpDecorate %nu_ii NonUniform
 OpDecorate %18 NonUniform
 OpDecorate %22 NonUniform
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
-)" + kInputDecorations + R"(
-; CHECK: OpDecorate [[load_result:%\w+]] NonUniform
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+;CHECK: OpDecorate [[load_result:%\w+]] NonUniform
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -2514,14 +2176,10 @@
 %nu_ii = OpVariable %_ptr_Input_int Input
 %int_0 = OpConstant %int 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kOutputGlobals + R"(
-; CHECK: %v4float = OpTypeVector %float 4
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: [[null_float:%\w+]] = OpConstantNull %float
-)" + kInputGlobals;
-  // clang-format on
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_float:%\w+]] = OpConstantNull %float
+)";
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -2530,44 +2188,33 @@
 %21 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %18 %int_0
 %22 = OpLoad %float %21
 OpStore %b %22
-; CHECK-NOT: %22 = OpLoad %float %21
-; CHECK-NOT: OpStore %b %22
-; CHECK: {{%\w+}} = OpULessThan %bool %7 %uint_128
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[load_result]] = OpLoad %float %22
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_46 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_46 %uint_0 %uint_1 %uint_3 {{%\w+}} %uint_128
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}}
-; CHECK: OpStore %b [[phi_result_2]]
+;CHECK-NOT: %22 = OpLoad %float %21
+;CHECK-NOT: OpStore %b %22
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpBitcast %uint %7
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_47 {{%\w+}} %uint_1 %uint_3 {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %float %22
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpStore %b {{%\w+}}
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs = kStreamWrite6Frag + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest,
@@ -2593,12 +2240,12 @@
   const std::string defs = R"(
 OpCapability Shader
 OpCapability RuntimeDescriptorArray
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint GLCompute %main "main"
-; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
+;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
 OpExecutionMode %main LocalSize 1 1 1
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
@@ -2616,9 +2263,8 @@
 OpDecorate %images DescriptorSet 2
 OpDecorate %images Binding 1
 OpDecorate %images NonWritable
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %uint = OpTypeInt 32 0
@@ -2640,14 +2286,12 @@
 %v4float = OpTypeVector %float 4
 %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: %v3uint = OpTypeVector %uint 3
-; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint
-; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: %v3uint = OpTypeVector %uint 3
+;CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint
+;CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
+;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -2660,70 +2304,64 @@
 %29 = OpCompositeExtract %float %27 0
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
-; CHECK-NOT: OpStore %31 %29
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_0 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %uint %25
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_47 %uint_1 %uint_2 %uint_0 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
-; CHECK: %28 = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_2 %uint_1
-; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_1 [[phi_result_1]]
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_50 %uint_1 %uint_2 %uint_1 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_50 %uint_0 %uint_2 %uint_1 {{%\w+}} {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float [[phi_result_2]] {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_0 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[desc_state_result]]
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_53 %uint_1 %uint_2 %uint_0 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
+;CHECK-NOT: OpStore %31 %29
+;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_48 {{%\w+}} %uint_2 %uint_0 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %uint %25
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_51 {{%\w+}} %uint_2 %uint_1 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
+;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0
+;CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_54 {{%\w+}} %uint_2 %uint_0 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %31 {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Compute + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest,
@@ -2748,13 +2386,13 @@
   const std::string defs = R"(
 OpCapability RuntimeDescriptorArray
 OpCapability RayTracingNV
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
 OpExtension "SPV_NV_ray_tracing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint RayGenerationNV %main "main"
-; CHECK: OpEntryPoint RayGenerationNV %main "main" [[launch_id:%\w+]]
+;CHECK: OpEntryPoint RayGenerationNV %main "main" [[launch_id:%\w+]]
 OpSource GLSL 460
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
 OpSourceExtension "GL_NV_ray_tracing"
@@ -2772,9 +2410,8 @@
 OpDecorate %images DescriptorSet 3
 OpDecorate %images Binding 5
 OpDecorate %images NonWritable
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
+)" + kImportDeco + R"(
+;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %uint = OpTypeInt 32 0
@@ -2796,11 +2433,9 @@
 %v4float = OpTypeVector %float 4
 %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -2813,70 +2448,64 @@
 %29 = OpCompositeExtract %float %27 0
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
-; CHECK-NOT: OpStore %31 %29
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_1 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %uint %25
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_3 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
-; CHECK: %28 = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_3 %uint_5
-; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_5 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_3 %uint_5 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_3 %uint_5 {{%\w+}} {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
-; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_1 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpStore %31 %30
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_3 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
+;CHECK-NOT: OpStore %31 %29
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_3 %uint_1 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %uint %25
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_5 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
+;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0
+;CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_3 %uint_1 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore {{%\w+}} {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Ray + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest,
@@ -2901,13 +2530,13 @@
   const std::string defs = R"(
 OpCapability RuntimeDescriptorArray
 OpCapability RayTracingNV
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
 OpExtension "SPV_NV_ray_tracing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint IntersectionNV %main "main"
-; CHECK: OpEntryPoint IntersectionNV %main "main" [[launch_id:%\w+]]
+;CHECK: OpEntryPoint IntersectionNV %main "main" [[launch_id:%\w+]]
 OpSource GLSL 460
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
 OpSourceExtension "GL_NV_ray_tracing"
@@ -2925,9 +2554,8 @@
 OpDecorate %images DescriptorSet 5
 OpDecorate %images Binding 3
 OpDecorate %images NonWritable
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
+)" + kImportDeco + R"(
+;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %uint = OpTypeInt 32 0
@@ -2949,12 +2577,10 @@
 %v4float = OpTypeVector %float 4
 %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
+;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -2967,70 +2593,63 @@
 %29 = OpCompositeExtract %float %27 0
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
-; CHECK-NOT: OpStore %31 %29
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_1 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %uint %25
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_5 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
-; CHECK: %28 = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_5 %uint_3
-; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_3 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_5 %uint_3 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_5 %uint_3 {{%\w+}} {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
-; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_1 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpStore %31 %30
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_5 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
+;CHECK-NOT: OpStore %31 %29
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_5 %uint_1 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %uint %25
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_5 %uint_3 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
+;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0
+;CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_5 %uint_1 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %31 {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Ray + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest,
@@ -3055,13 +2674,13 @@
   const std::string defs = R"(
 OpCapability RuntimeDescriptorArray
 OpCapability RayTracingNV
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
 OpExtension "SPV_NV_ray_tracing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint AnyHitNV %main "main"
-; CHECK: OpEntryPoint AnyHitNV %main "main" [[launch_id:%\w+]]
+;CHECK: OpEntryPoint AnyHitNV %main "main" [[launch_id:%\w+]]
 OpSource GLSL 460
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
 OpSourceExtension "GL_NV_ray_tracing"
@@ -3079,9 +2698,8 @@
 OpDecorate %images DescriptorSet 2
 OpDecorate %images Binding 3
 OpDecorate %images NonWritable
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
+)" + kImportDeco + R"(
+;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %uint = OpTypeInt 32 0
@@ -3103,12 +2721,10 @@
 %v4float = OpTypeVector %float 4
 %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
+;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -3121,70 +2737,70 @@
 %29 = OpCompositeExtract %float %27 0
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
-; CHECK-NOT: OpStore %31 %29
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_1 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %uint %25
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_2 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
-; CHECK: %28 = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_2 %uint_3
-; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_3 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_2 %uint_3 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_2 %uint_3 {{%\w+}} {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
-; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_1 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpStore %31 %30
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_2 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
+;CHECK-NOT: %20 = OpLoad %uint %19
+;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+;CHECK-NOT: %23 = OpLoad %13 %22
+;CHECK-NOT: %27 = OpImageRead %v4float %23 %25
+;CHECK-NOT: %29 = OpCompositeExtract %float %27 0
+;CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+;CHECK-NOT: OpStore %31 %29
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %uint %25
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
+;CHECK: %28 = OpLoad %13 %27
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_2 %uint_3 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %13 %27
+;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
+;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %31 %30
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Ray + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest,
@@ -3209,13 +2825,13 @@
   const std::string defs = R"(
 OpCapability RuntimeDescriptorArray
 OpCapability RayTracingNV
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
 OpExtension "SPV_NV_ray_tracing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint ClosestHitNV %main "main"
-; CHECK: OpEntryPoint ClosestHitNV %main "main" [[launch_id:%\w+]]
+;CHECK: OpEntryPoint ClosestHitNV %main "main" [[launch_id:%\w+]]
 OpSource GLSL 460
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
 OpSourceExtension "GL_NV_ray_tracing"
@@ -3233,9 +2849,8 @@
 OpDecorate %images DescriptorSet 1
 OpDecorate %images Binding 3
 OpDecorate %images NonWritable
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
+)" + kImportDeco + R"(
+;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %uint = OpTypeInt 32 0
@@ -3257,12 +2872,10 @@
 %v4float = OpTypeVector %float 4
 %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
+;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -3275,70 +2888,70 @@
 %29 = OpCompositeExtract %float %27 0
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
-; CHECK-NOT: OpStore %31 %29
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %uint %25
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
-; CHECK: %28 = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_3
-; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_1 %uint_3 {{%\w+}} {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
-; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpStore %31 %30
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_1 %uint_2
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
+;CHECK-NOT: %20 = OpLoad %uint %19
+;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+;CHECK-NOT: %23 = OpLoad %13 %22
+;CHECK-NOT: %27 = OpImageRead %v4float %23 %25
+;CHECK-NOT: %29 = OpCompositeExtract %float %27 0
+;CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+;CHECK-NOT: OpStore %31 %29
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %uint %25
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
+;CHECK: %28 = OpLoad %13 %27
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %13 %27
+;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
+;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %31 %30
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Ray + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest,
@@ -3363,13 +2976,13 @@
   const std::string defs = R"(
 OpCapability RuntimeDescriptorArray
 OpCapability RayTracingNV
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
 OpExtension "SPV_NV_ray_tracing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint MissNV %main "main"
-; CHECK: OpEntryPoint MissNV %main "main" [[launch_id:%\w+]]
+;CHECK: OpEntryPoint MissNV %main "main" [[launch_id:%\w+]]
 OpSource GLSL 460
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
 OpSourceExtension "GL_NV_ray_tracing"
@@ -3387,9 +3000,8 @@
 OpDecorate %images DescriptorSet 1
 OpDecorate %images Binding 3
 OpDecorate %images NonWritable
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
+)" + kImportDeco + R"(
+;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %uint = OpTypeInt 32 0
@@ -3411,12 +3023,10 @@
 %v4float = OpTypeVector %float 4
 %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
+;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -3429,70 +3039,67 @@
 %29 = OpCompositeExtract %float %27 0
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
-; CHECK-NOT OpStore %31 %29
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %uint %25
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
-; CHECK: %28 = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_3
-; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_1 %uint_3 {{%\w+}} {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
-; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpStore %31 %30
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
+;CHECK-NOT: %20 = OpLoad %uint %19
+;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+;CHECK-NOT: %27 = OpImageRead %v4float %23 %25
+;CHECK-NOT: %29 = OpCompositeExtract %float %27 0
+;CHECK-NOT OpStore %31 %29
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %uint %25
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %13 %27
+;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
+;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %31 %30
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Ray + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest,
@@ -3517,13 +3124,13 @@
   const std::string defs = R"(
 OpCapability RuntimeDescriptorArray
 OpCapability RayTracingNV
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
 OpExtension "SPV_NV_ray_tracing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint CallableNV %main "main"
-; CHECK: OpEntryPoint CallableNV %main "main" [[launch_id:%\w+]]
+;CHECK: OpEntryPoint CallableNV %main "main" [[launch_id:%\w+]]
 OpSource GLSL 460
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
 OpSourceExtension "GL_NV_ray_tracing"
@@ -3541,9 +3148,8 @@
 OpDecorate %images DescriptorSet 1
 OpDecorate %images Binding 3
 OpDecorate %images NonWritable
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
+)" + kImportDeco + R"(
+;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %uint = OpTypeInt 32 0
@@ -3565,11 +3171,9 @@
 %v4float = OpTypeVector %float 4
 %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-)" + kInputGlobals + kOutputGlobals + R"(
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -3580,72 +3184,71 @@
 %23 = OpLoad %13 %22
 %27 = OpImageRead %v4float %23 %25
 %29 = OpCompositeExtract %float %27 0
+;CHECK-NOT: %20 = OpLoad %uint %19
+;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %uint %25
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
+;CHECK-NOT: %23 = OpLoad %13 %22
+;CHECK-NOT: %27 = OpImageRead %v4float %23 %25
+;CHECK-NOT: %29 = OpCompositeExtract %float %27 0
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %13 %27
+;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
+;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
-; CHECK-NOT: OpStore %31 %29
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %uint %25
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
-; CHECK: %28 = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_3
-; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_1 %uint_3 {{%\w+}} {{%\w+}}
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
-; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpStore %31 %30
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
+;CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+;CHECK-NOT: OpStore %31 %29
+;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %31 %30
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs =
-      kReadBindingLength + kStreamWrite6Ray + kReadDescInit;
+  // clang-format on
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) {
@@ -3680,12 +3283,12 @@
 OpCapability Shader
 OpCapability ShaderNonUniformEXT
 OpCapability SampledImageArrayNonUniformIndexingEXT
+;CHECK: OpCapability Linkage
 OpExtension "SPV_EXT_descriptor_indexing"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %main "main" %inTexcoord %outColor
-; CHECK: OpEntryPoint Fragment %main "main" %inTexcoord %outColor %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %main "main" %inTexcoord %outColor %gl_FragCoord
 OpExecutionMode %main OriginUpperLeft
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_nonuniform_qualifier"
@@ -3715,12 +3318,11 @@
 OpDecorate %uniforms DescriptorSet 1
 OpDecorate %uniforms Binding 0
 OpDecorate %outColor Location 0
-; CHECK: OpDecorate %63 NonUniform
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
-)" + kInputDecorations + R"(
-; CHECK: OpDecorate [[desc_state_result:%\w+]] NonUniform
+;CHECK: OpDecorate {{%\w+}} NonUniform
+;CHECK: OpDecorate {{%\w+}} NonUniform
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+;CHECK: OpDecorate [[desc_state_result:%\w+]] NonUniform
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %int = OpTypeInt 32 1
@@ -3752,12 +3354,9 @@
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %outColor = OpVariable %_ptr_Output_v4float Output
 %float_0 = OpConstant %float 0
-)" + kOutputGlobals + R"(
-; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-)" + kInputGlobals + R"(
-; CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
 )";
-  // clang-format on
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -3774,6 +3373,26 @@
 %32 = OpLoad %v2float %inTexcoord
 %34 = OpImageSampleImplicitLod %v4float %28 %32
 %36 = OpCompositeExtract %float %34 0
+;CHECK-NOT: %34 = OpImageSampleImplicitLod %v4float %28 %32
+;CHECK-NOT: %36 = OpCompositeExtract %float %34 0
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpBitcast %uint %19
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_80 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %13 %21
+;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %26
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %32
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
 OpStore %x %36
 %39 = OpLoad %13 %uniformTex
 %40 = OpLoad %23 %uniformSampler
@@ -3782,38 +3401,48 @@
 %47 = OpAccessChain %_ptr_Uniform_v2float %uniforms %int_0
 %48 = OpLoad %v2float %47
 %49 = OpFMul %v2float %42 %48
+;CHECK-NOT: %48 = OpLoad %v2float %47
+;CHECK-NOT: %49 = OpFMul %v2float %42 %48
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_88 {{%\w+}} %uint_1 %uint_0 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %v2float %47
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
+;CHECK: %49 = OpFMul %v2float %42 [[phi_result]]
 %50 = OpImageSampleImplicitLod %v4float %41 %49
 %51 = OpCompositeExtract %float %50 0
-; CHECK-NOT: %51 = OpCompositeExtract %float %50 0
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_0 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %v2float %47
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_87 %uint_1 %uint_1 %uint_0 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
-; CHECK: %49 = OpFMul %v2float %42 {{%\w+}}
-; CHECK: {{%\w+}} = OpSampledImage %27 %39 %40
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0
-; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpLoad %13 %uniformTex
-; CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %40
-; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %49
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_89 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-; CHECK: %51 = OpCompositeExtract %float {{%\w+}} 0
+OpStore %y %51
+;CHECK-NOT: %50 = OpImageSampleImplicitLod %v4float %41 %49
+;CHECK-NOT: %51 = OpCompositeExtract %float %50 0
+;CHECK: {{%\w+}} = OpSampledImage %27 %39 %40
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_90 {{%\w+}} %uint_1 %uint_2 %uint_0 %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %13 %uniformTex
+;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %40
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %49
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: %51 = OpCompositeExtract %float {{%\w+}} 0
 OpStore %y %51
 %54 = OpLoad %float %x
 %55 = OpLoad %float %y
@@ -3822,13 +3451,11 @@
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string new_funcs = kStreamWrite6Frag + kReadDescInit;
+  // clang-format on
 
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
-                                               true, 7u, 23u, true, true, false,
-                                               false, false);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
+                                               true, 23u);
 }
 
 TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
@@ -3870,143 +3497,145 @@
 
   // clang-format off
   const std::string text = R"(
-               OpCapability Shader
-;CHECK:        OpExtension "SPV_KHR_storage_buffer_storage_class"
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
-;CHECK:        OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord
-               OpExecutionMode %MainPs OriginUpperLeft
-               OpSource HLSL 500
-               OpName %MainPs "MainPs"
-               OpName %PerViewPushConst_t "PerViewPushConst_t"
-               OpMemberName %PerViewPushConst_t 0 "g_B"
-               OpName %_ ""
-               OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
-               OpMemberName %PerViewConstantBuffer_t 0 "g_TexOff0"
-               OpMemberName %PerViewConstantBuffer_t 1 "g_TexOff1"
-               OpName %__0 ""
-               OpName %g_tColor "g_tColor"
-               OpName %g_sAniso "g_sAniso"
-               OpName %i_vTextureCoords "i.vTextureCoords"
-               OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
-               OpMemberDecorate %PerViewPushConst_t 0 Offset 0
-               OpDecorate %PerViewPushConst_t Block
-               OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
-               OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 8
-               OpDecorate %PerViewConstantBuffer_t Block
-               OpDecorate %__0 DescriptorSet 0
-               OpDecorate %__0 Binding 1
-               OpDecorate %g_tColor DescriptorSet 0
-               OpDecorate %g_tColor Binding 0
-               OpDecorate %g_sAniso DescriptorSet 0
-               OpDecorate %g_sAniso Binding 2
-               OpDecorate %i_vTextureCoords Location 0
-               OpDecorate %_entryPointOutput_vColor Location 0
- ;CHECK:       OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
- ;CHECK:       OpDecorate %gl_FragCoord BuiltIn FragCoord
-       %void = OpTypeVoid
-          %3 = OpTypeFunction %void
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-    %v4float = OpTypeVector %float 4
-       %uint = OpTypeInt 32 0
+OpCapability Shader
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+OpExecutionMode %MainPs OriginUpperLeft
+OpSource HLSL 500
+OpName %MainPs "MainPs"
+OpName %PerViewPushConst_t "PerViewPushConst_t"
+OpMemberName %PerViewPushConst_t 0 "g_B"
+OpName %_ ""
+OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
+OpMemberName %PerViewConstantBuffer_t 0 "g_TexOff0"
+OpMemberName %PerViewConstantBuffer_t 1 "g_TexOff1"
+OpName %__0 ""
+OpName %g_tColor "g_tColor"
+OpName %g_sAniso "g_sAniso"
+OpName %i_vTextureCoords "i.vTextureCoords"
+OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
+OpMemberDecorate %PerViewPushConst_t 0 Offset 0
+OpDecorate %PerViewPushConst_t Block
+OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
+OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 8
+OpDecorate %PerViewConstantBuffer_t Block
+OpDecorate %__0 DescriptorSet 0
+OpDecorate %__0 Binding 1
+OpDecorate %g_tColor DescriptorSet 0
+OpDecorate %g_tColor Binding 0
+OpDecorate %g_sAniso DescriptorSet 0
+OpDecorate %g_sAniso Binding 2
+OpDecorate %i_vTextureCoords Location 0
+OpDecorate %_entryPointOutput_vColor Location 0
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v2float = OpTypeVector %float 2
+%v4float = OpTypeVector %float 4
+%uint = OpTypeInt 32 0
 %PerViewPushConst_t = OpTypeStruct %uint
 %_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t
-          %_ = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
+%_ = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
 %_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
-       %bool = OpTypeBool
-     %uint_0 = OpConstant %uint 0
+%bool = OpTypeBool
+%uint_0 = OpConstant %uint 0
 %PerViewConstantBuffer_t = OpTypeStruct %v2float %v2float
 %_ptr_Uniform_PerViewConstantBuffer_t = OpTypePointer Uniform %PerViewConstantBuffer_t
-        %__0 = OpVariable %_ptr_Uniform_PerViewConstantBuffer_t Uniform
+%__0 = OpVariable %_ptr_Uniform_PerViewConstantBuffer_t Uniform
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-      %int_1 = OpConstant %int 1
-         %49 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%int_1 = OpConstant %int 1
+%49 = OpTypeImage %float 2D 0 0 0 1 Unknown
 %_ptr_UniformConstant_49 = OpTypePointer UniformConstant %49
-   %g_tColor = OpVariable %_ptr_UniformConstant_49 UniformConstant
-         %53 = OpTypeSampler
+%g_tColor = OpVariable %_ptr_UniformConstant_49 UniformConstant
+%53 = OpTypeSampler
 %_ptr_UniformConstant_53 = OpTypePointer UniformConstant %53
-   %g_sAniso = OpVariable %_ptr_UniformConstant_53 UniformConstant
-         %57 = OpTypeSampledImage %49
+%g_sAniso = OpVariable %_ptr_UniformConstant_53 UniformConstant
+%57 = OpTypeSampledImage %49
 %_ptr_Input_v2float = OpTypePointer Input %v2float
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
- )" + kInputGlobals + kOutputGlobals + R"(
- ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float
- ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
- ;CHECK:     %v4uint = OpTypeVector %uint 4
- ;CHECK:        [[null_v2float:%\w+]] = OpConstantNull %v2float
-     %MainPs = OpFunction %void None %3
-          %5 = OpLabel
- ;CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 %uint_0
- ;CHECK:        OpBranch %117
- ;CHECK: %117 = OpLabel
- ;CHECK:        OpBranch %116
- ;CHECK: %116 = OpLabel
-         %69 = OpLoad %v2float %i_vTextureCoords
-         %82 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
-         %83 = OpLoad %uint %82
-         %84 = OpINotEqual %bool %83 %uint_0
-               OpSelectionMerge %91 None
-               OpBranchConditional %84 %85 %88
-         %85 = OpLabel
-         %86 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_0
-         %87 = OpLoad %v2float %86
- ;CHECK-NOT:     %87 = OpLoad %v2float %86
- ;CHECK: %119 = OpIAdd %uint %uint_0 %uint_7
- ;CHECK: {{%\w+}} = OpULessThan %bool %119 [[desc_state_result]]
- ;CHECK: OpSelectionMerge {{%\w+}} None
- ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
- ;CHECK: {{%\w+}} = OpLabel
- ;CHECK: {{%\w+}} = OpLoad %v2float %86
- ;CHECK: OpBranch {{%\w+}}
- ;CHECK: {{%\w+}} = OpLabel
- ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_71 %uint_4 %uint_0 %uint_1 %uint_0 %119 {{%\w+}}
- ;CHECK: OpBranch {{%\w+}}
- ;CHECK: {{%\w+}} = OpLabel
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
+ )" + kImportStub + R"(
+%MainPs = OpFunction %void None %3
+%5 = OpLabel
+%69 = OpLoad %v2float %i_vTextureCoords
+%82 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
+%83 = OpLoad %uint %82
+%84 = OpINotEqual %bool %83 %uint_0
+OpSelectionMerge %91 None
+OpBranchConditional %84 %85 %88
+%85 = OpLabel
+%86 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_0
+%87 = OpLoad %v2float %86
+;CHECK-NOT:     %87 = OpLoad %v2float %86
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_72 {{%\w+}} %uint_0 %uint_1 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional [[desc_state_result]] {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %v2float %86
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
  ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
-               OpBranch %91
-         %88 = OpLabel
-         %89 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_1
-         %90 = OpLoad %v2float %89
- ;CHECK-NOT:     %90 = OpLoad %v2float %89
- ;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_7
- ;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
- ;CHECK: OpSelectionMerge {{%\w+}} None
- ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
- ;CHECK: {{%\w+}} = OpLabel
- ;CHECK: {{%\w+}} = OpLoad %v2float %89
- ;CHECK: OpBranch {{%\w+}}
- ;CHECK: {{%\w+}} = OpLabel
- ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_75 %uint_4 %uint_0 %uint_1 %uint_0 {{%\w+}} {{%\w+}}
- ;CHECK: OpBranch {{%\w+}}
- ;CHECK: {{%\w+}} = OpLabel
- ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
-               OpBranch %91
-         %91 = OpLabel
-        %115 = OpPhi %v2float %87 %85 %90 %88
- ;CHECK-NOT:       %115 = OpPhi %v2float %87 %85 %90 %88
- ;CHECK: %115 = OpPhi %v2float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
-         %95 = OpFAdd %v2float %69 %115
-         %96 = OpLoad %49 %g_tColor
-         %97 = OpLoad %53 %g_sAniso
-         %98 = OpSampledImage %57 %96 %97
-        %100 = OpImageSampleImplicitLod %v4float %98 %95
-               OpStore %_entryPointOutput_vColor %100
-               OpReturn
-               OpFunctionEnd
-)" + kReadDescInit + kStreamWrite7Frag;
+OpBranch %91
+%88 = OpLabel
+%89 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_1
+%90 = OpLoad %v2float %89
+;CHECK-NOT:     %90 = OpLoad %v2float %89
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_7
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_76 {{%\w+}} %uint_0 %uint_1 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %v2float %89
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
+OpBranch %91
+%91 = OpLabel
+%115 = OpPhi %v2float %87 %85 %90 %88
+;CHECK-NOT:       %115 = OpPhi %v2float %87 %85 %90 %88
+;CHECK: %115 = OpPhi %v2float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+%95 = OpFAdd %v2float %69 %115
+%96 = OpLoad %49 %g_tColor
+%97 = OpLoad %53 %g_sAniso
+%98 = OpSampledImage %57 %96 %97
+%100 = OpImageSampleImplicitLod %v4float %98 %95
+OpStore %_entryPointOutput_vColor %100
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, false, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) {
@@ -4047,132 +3676,129 @@
 
   // clang-format off
   const std::string text = R"(
-               OpCapability Shader
-;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
-               OpExecutionMode %MainPs OriginUpperLeft
-               OpSource HLSL 500
-               OpName %MainPs "MainPs"
-               OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
-               OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
-               OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
-               OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
-               OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
-               OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
-               OpName %_ ""
-               OpName %PerViewPushConst_t "PerViewPushConst_t"
-               OpMemberName %PerViewPushConst_t 0 "g_c"
-               OpName %__0 ""
-               OpName %g_tColor "g_tColor"
-               OpName %g_sAniso "g_sAniso"
-               OpName %i_vTextureCoords "i.vTextureCoords"
-               OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64
-               OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80
-               OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0
-               OpDecorate %_BindlessFastEnvMapCB_PS_t Block
-               OpDecorate %_ DescriptorSet 0
-               OpDecorate %_ Binding 2
-               OpMemberDecorate %PerViewPushConst_t 0 Offset 0
-               OpDecorate %PerViewPushConst_t Block
-               OpDecorate %g_tColor DescriptorSet 0
-               OpDecorate %g_tColor Binding 0
-               OpDecorate %g_sAniso DescriptorSet 0
-               OpDecorate %g_sAniso Binding 1
-               OpDecorate %i_vTextureCoords Location 0
-               OpDecorate %_entryPointOutput_vColor Location 0
-;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-;CHECK:               OpDecorate %gl_FragCoord BuiltIn FragCoord
-       %void = OpTypeVoid
-          %3 = OpTypeFunction %void
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-    %v4float = OpTypeVector %float 4
-    %v3float = OpTypeVector %float 3
+OpCapability Shader
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
+OpExecutionMode %MainPs OriginUpperLeft
+OpSource HLSL 500
+OpName %MainPs "MainPs"
+OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
+OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
+OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
+OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
+OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
+OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
+OpName %_ ""
+OpName %PerViewPushConst_t "PerViewPushConst_t"
+OpMemberName %PerViewPushConst_t 0 "g_c"
+OpName %__0 ""
+OpName %g_tColor "g_tColor"
+OpName %g_sAniso "g_sAniso"
+OpName %i_vTextureCoords "i.vTextureCoords"
+OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64
+OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80
+OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0
+OpDecorate %_BindlessFastEnvMapCB_PS_t Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 2
+OpMemberDecorate %PerViewPushConst_t 0 Offset 0
+OpDecorate %PerViewPushConst_t Block
+OpDecorate %g_tColor DescriptorSet 0
+OpDecorate %g_tColor Binding 0
+OpDecorate %g_sAniso DescriptorSet 0
+OpDecorate %g_sAniso Binding 1
+OpDecorate %i_vTextureCoords Location 0
+OpDecorate %_entryPointOutput_vColor Location 0
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v2float = OpTypeVector %float 2
+%v4float = OpTypeVector %float 4
+%v3float = OpTypeVector %float 3
 %mat4v3float = OpTypeMatrix %v3float 4
 %PerBatchEnvMapConstantBuffer_t = OpTypeStruct %mat4v3float %v4float %v2float
-       %uint = OpTypeInt 32 0
-   %uint_128 = OpConstant %uint 128
+%uint = OpTypeInt 32 0
+%uint_128 = OpConstant %uint 128
 %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 = OpTypeArray %PerBatchEnvMapConstantBuffer_t %uint_128
 %_BindlessFastEnvMapCB_PS_t = OpTypeStruct %_arr_PerBatchEnvMapConstantBuffer_t_uint_128
 %_ptr_Uniform__BindlessFastEnvMapCB_PS_t = OpTypePointer Uniform %_BindlessFastEnvMapCB_PS_t
-          %_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
+%_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
 %PerViewPushConst_t = OpTypeStruct %uint
 %_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t
-        %__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
+%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
 %_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
-      %int_2 = OpConstant %int 2
+%int_2 = OpConstant %int 2
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-         %46 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%46 = OpTypeImage %float 2D 0 0 0 1 Unknown
 %_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
-   %g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant
-         %50 = OpTypeSampler
+%g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant
+%50 = OpTypeSampler
 %_ptr_UniformConstant_50 = OpTypePointer UniformConstant %50
-   %g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant
-         %54 = OpTypeSampledImage %46
+%g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant
+%54 = OpTypeSampledImage %46
 %_ptr_Input_v2float = OpTypePointer Input %v2float
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-)" + kInputGlobals + kOutputGlobals + R"(
-;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float
-;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-;CHECK:     %v4uint = OpTypeVector %uint 4
-;CHECK:        [[null_v2float:%\w+]] = OpConstantNull %v2float
-     %MainPs = OpFunction %void None %3
-          %5 = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
-         %66 = OpLoad %v2float %i_vTextureCoords
-         %79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0
-         %80 = OpLoad %uint %79
-         %81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2
-         %82 = OpLoad %v2float %81
-;CHECK-NOT:     %82 = OpLoad %v2float %81
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
+)" + kImportStub + R"(
+%MainPs = OpFunction %void None %3
+%5 = OpLabel
+%66 = OpLoad %v2float %i_vTextureCoords
+%79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0
+%80 = OpLoad %uint %79
+%81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2
+%82 = OpLoad %v2float %81
+;CHECK-NOT: %82 = OpLoad %v2float %81
 ;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80
 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64
 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
-;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}}
 ;CHECK: OpSelectionMerge {{%\w+}} None
 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: {{%\w+}} = OpLoad %v2float %81
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_78 %uint_4 %uint_0 %uint_2 %uint_0 {{%\w+}} {{%\w+}}
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
-         %86 = OpFAdd %v2float %66 %82
-;CHECK-NOT:         %86 = OpFAdd %v2float %66 %82
-;CHECK:             %86 = OpFAdd %v2float %66 {{%\w+}}
-         %87 = OpLoad %46 %g_tColor
-         %88 = OpLoad %50 %g_sAniso
-         %89 = OpSampledImage %54 %87 %88
-         %91 = OpImageSampleImplicitLod %v4float %89 %86
-               OpStore %_entryPointOutput_vColor %91
-               OpReturn
-               OpFunctionEnd
-)" + kReadDescInit + kStreamWrite7Frag;
+%86 = OpFAdd %v2float %66 %82
+;CHECK-NOT: %86 = OpFAdd %v2float %66 %82
+;CHECK: %86 = OpFAdd %v2float %66 {{%\w+}}
+%87 = OpLoad %46 %g_tColor
+%88 = OpLoad %50 %g_sAniso
+%89 = OpSampledImage %54 %87 %88
+%91 = OpImageSampleImplicitLod %v4float %89 %86
+OpStore %_entryPointOutput_vColor %91
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, false, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
@@ -4183,129 +3809,131 @@
 
   // clang-format off
   const std::string text = R"(
-               OpCapability Shader
-;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
-;CHECK:        OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord
-               OpExecutionMode %MainPs OriginUpperLeft
-               OpSource HLSL 500
-               OpName %MainPs "MainPs"
-               OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
-               OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
-               OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
-               OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
-               OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
-               OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
-               OpName %_ ""
-               OpName %PerViewPushConst_t "PerViewPushConst_t"
-               OpMemberName %PerViewPushConst_t 0 "g_c"
-               OpName %__0 ""
-               OpName %g_tColor "g_tColor"
-               OpName %g_sAniso "g_sAniso"
-               OpName %i_vTextureCoords "i.vTextureCoords"
-               OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64
-               OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80
-               OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0
-               OpDecorate %_BindlessFastEnvMapCB_PS_t Block
-               OpDecorate %_ DescriptorSet 0
-               OpDecorate %_ Binding 2
-               OpMemberDecorate %PerViewPushConst_t 0 Offset 0
-               OpDecorate %PerViewPushConst_t Block
-               OpDecorate %g_tColor DescriptorSet 0
-               OpDecorate %g_tColor Binding 0
-               OpDecorate %g_sAniso DescriptorSet 0
-               OpDecorate %g_sAniso Binding 1
-               OpDecorate %i_vTextureCoords Location 0
-               OpDecorate %_entryPointOutput_vColor Location 0
-;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-;CHECK:               OpDecorate %gl_FragCoord BuiltIn FragCoord
-       %void = OpTypeVoid
-          %3 = OpTypeFunction %void
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-    %v4float = OpTypeVector %float 4
-    %v3float = OpTypeVector %float 3
+OpCapability Shader
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+OpExecutionMode %MainPs OriginUpperLeft
+OpSource HLSL 500
+OpName %MainPs "MainPs"
+OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
+OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
+OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
+OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
+OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
+OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
+OpName %_ ""
+OpName %PerViewPushConst_t "PerViewPushConst_t"
+OpMemberName %PerViewPushConst_t 0 "g_c"
+OpName %__0 ""
+OpName %g_tColor "g_tColor"
+OpName %g_sAniso "g_sAniso"
+OpName %i_vTextureCoords "i.vTextureCoords"
+OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64
+OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80
+OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0
+OpDecorate %_BindlessFastEnvMapCB_PS_t Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 2
+OpMemberDecorate %PerViewPushConst_t 0 Offset 0
+OpDecorate %PerViewPushConst_t Block
+OpDecorate %g_tColor DescriptorSet 0
+OpDecorate %g_tColor Binding 0
+OpDecorate %g_sAniso DescriptorSet 0
+OpDecorate %g_sAniso Binding 1
+OpDecorate %i_vTextureCoords Location 0
+OpDecorate %_entryPointOutput_vColor Location 0
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v2float = OpTypeVector %float 2
+%v4float = OpTypeVector %float 4
+%v3float = OpTypeVector %float 3
 %mat4v3float = OpTypeMatrix %v3float 4
 %PerBatchEnvMapConstantBuffer_t = OpTypeStruct %mat4v3float %v4float %v2float
-       %uint = OpTypeInt 32 0
-   %uint_128 = OpConstant %uint 128
+%uint = OpTypeInt 32 0
+%uint_128 = OpConstant %uint 128
 %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 = OpTypeArray %PerBatchEnvMapConstantBuffer_t %uint_128
 %_BindlessFastEnvMapCB_PS_t = OpTypeStruct %_arr_PerBatchEnvMapConstantBuffer_t_uint_128
 %_ptr_Uniform__BindlessFastEnvMapCB_PS_t = OpTypePointer Uniform %_BindlessFastEnvMapCB_PS_t
-          %_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
+%_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
 %PerViewPushConst_t = OpTypeStruct %uint
 %_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t
-        %__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
+%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
 %_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
-      %int_2 = OpConstant %int 2
+%int_2 = OpConstant %int 2
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-         %46 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%46 = OpTypeImage %float 2D 0 0 0 1 Unknown
 %_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
-   %g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant
-         %50 = OpTypeSampler
+%g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant
+%50 = OpTypeSampler
 %_ptr_UniformConstant_50 = OpTypePointer UniformConstant %50
-   %g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant
-         %54 = OpTypeSampledImage %46
+%g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant
+%54 = OpTypeSampledImage %46
 %_ptr_Input_v2float = OpTypePointer Input %v2float
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-)" + kInputGlobals + kOutputGlobals + R"(
+;CHECK: %v4uint = OpTypeVector %uint 4
 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
 ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-;CHECK: %v4uint = OpTypeVector %uint 4
 ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
 ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-     %MainPs = OpFunction %void None %3
-          %5 = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0
-;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
-         %66 = OpLoad %v2float %i_vTextureCoords
-         %79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0
-         %80 = OpLoad %uint %79
-         %81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2
-         %82 = OpLoad %v2float %81
-         %86 = OpFAdd %v2float %66 %82
+)" + kImportStub + R"(
+%MainPs = OpFunction %void None %3
+%5 = OpLabel
+%66 = OpLoad %v2float %i_vTextureCoords
+%79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0
+%80 = OpLoad %uint %79
+%81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2
+%82 = OpLoad %v2float %81
+%86 = OpFAdd %v2float %66 %82
 ;CHECK-NOT: %82 = OpLoad %v2float %81
 ;CHECK-NOT: %86 = OpFAdd %v2float %66 %82
 ;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80
 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64
 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
-;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}}
 ;CHECK: OpSelectionMerge {{%\w+}} None
 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: {{%\w+}} = OpLoad %v2float %81
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_78 %uint_4 %uint_0 %uint_2 %uint_0 {{%\w+}} {{%\w+}}
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
 ;CHECK: %86 = OpFAdd %v2float %66 {{%\w+}}
-         %87 = OpLoad %46 %g_tColor
-         %88 = OpLoad %50 %g_sAniso
-         %89 = OpSampledImage %54 %87 %88
-         %91 = OpImageSampleImplicitLod %v4float %89 %86
-               OpStore %_entryPointOutput_vColor %91
+%87 = OpLoad %46 %g_tColor
+%88 = OpLoad %50 %g_sAniso
+%89 = OpSampledImage %54 %87 %88
+%91 = OpImageSampleImplicitLod %v4float %89 %86
+OpStore %_entryPointOutput_vColor %91
 ;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86
 ;CHECK-NOT:       OpStore %_entryPointOutput_vColor %91
-;CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_84 {{%\w+}} %uint_0 %uint_0 %uint_0 %uint_0
 ;CHECK: OpSelectionMerge {{%\w+}} None
 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
@@ -4314,20 +3942,18 @@
 ;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %86
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0 %uint_0 %uint_0
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
 ;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}}
-               OpReturn
-               OpFunctionEnd
-)" + kReadDescInit + kStreamWrite7Frag;
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
-                                               true, false, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, Descriptor16BitIdxRef) {
@@ -4338,124 +3964,107 @@
 
   // clang-format off
   const std::string text = R"(
-               OpCapability Shader
-               OpCapability Int16
-               OpCapability StoragePushConstant16
-;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
-;CHECK:        OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %inst_bindless_output_buffer %gl_FragCoord %inst_bindless_input_buffer
-               OpExecutionMode %MainPs OriginUpperLeft
-               OpSource HLSL 500
-               OpName %MainPs "MainPs"
-               OpName %g_tColor "g_tColor"
-               OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
-               OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
-               OpName %_ ""
-               OpName %g_sAniso "g_sAniso"
-               OpName %i_vTextureCoords "i.vTextureCoords"
-               OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
-               OpDecorate %g_tColor DescriptorSet 1
-               OpDecorate %g_tColor Binding 2
-               OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
-               OpDecorate %PerViewConstantBuffer_t Block
-               OpDecorate %g_sAniso DescriptorSet 1
-               OpDecorate %g_sAniso Binding 2
-               OpDecorate %i_vTextureCoords Location 0
-               OpDecorate %_entryPointOutput_vColor Location 0
-;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-;CHECK:               OpDecorate %gl_FragCoord BuiltIn FragCoord
-)" + kInputDecorations + R"(
-       %void = OpTypeVoid
-         %10 = OpTypeFunction %void
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-    %v4float = OpTypeVector %float 4
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
-         %16 = OpTypeImage %float 2D 0 0 0 1 Unknown
-       %uint = OpTypeInt 32 0
-   %uint_128 = OpConstant %uint 128
+OpCapability Shader
+OpCapability Int16
+OpCapability StoragePushConstant16
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+OpExecutionMode %MainPs OriginUpperLeft
+OpSource HLSL 500
+OpName %MainPs "MainPs"
+OpName %g_tColor "g_tColor"
+OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
+OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
+OpName %_ ""
+OpName %g_sAniso "g_sAniso"
+OpName %i_vTextureCoords "i.vTextureCoords"
+OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
+OpDecorate %g_tColor DescriptorSet 1
+OpDecorate %g_tColor Binding 2
+OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
+OpDecorate %PerViewConstantBuffer_t Block
+OpDecorate %g_sAniso DescriptorSet 1
+OpDecorate %g_sAniso Binding 2
+OpDecorate %i_vTextureCoords Location 0
+OpDecorate %_entryPointOutput_vColor Location 0
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%10 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v2float = OpTypeVector %float 2
+%v4float = OpTypeVector %float 4
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%16 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%uint = OpTypeInt 32 0
+%uint_128 = OpConstant %uint 128
 %_arr_16_uint_128 = OpTypeArray %16 %uint_128
 %_ptr_UniformConstant__arr_16_uint_128 = OpTypePointer UniformConstant %_arr_16_uint_128
-   %g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant
-     %ushort = OpTypeInt 16 0
+%g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant
+%ushort = OpTypeInt 16 0
 %PerViewConstantBuffer_t = OpTypeStruct %ushort
 %_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
-          %_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
+%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
 %_ptr_PushConstant_ushort = OpTypePointer PushConstant %ushort
 %_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16
-         %25 = OpTypeSampler
+%25 = OpTypeSampler
 %_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25
-   %g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant
-         %27 = OpTypeSampledImage %16
+%g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant
+%27 = OpTypeSampledImage %16
 %_ptr_Input_v2float = OpTypePointer Input %v2float
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-)" + kOutputGlobals + R"(
-;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float
-;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-;CHECK:        [[null_v4float:%\w+]] = OpConstantNull %v4float
-)" + kInputGlobals + R"(
-     %MainPs = OpFunction %void None %10
-         %30 = OpLabel
-;CHECK:               OpBranch {{%\w+}}
-;CHECK:        {{%\w+}} = OpLabel
-;CHECK:               OpBranch %39
-;CHECK:         %39 = OpLabel
-         %31 = OpLoad %v2float %i_vTextureCoords
-         %32 = OpAccessChain %_ptr_PushConstant_ushort %_ %int_0
-         %33 = OpLoad %ushort %32
-         %34 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %33
-         %35 = OpLoad %16 %34
-         %36 = OpLoad %25 %g_sAniso
-         %37 = OpSampledImage %27 %35 %36
-         %38 = OpImageSampleImplicitLod %v4float %37 %31
-               OpStore %_entryPointOutput_vColor %38
-;CHECK-NOT:         %38 = OpImageSampleImplicitLod %v4float %37 %31
-;CHECK-NOT:               OpStore %_entryPointOutput_vColor %38
-;CHECK:         %41 = OpUConvert %uint %33
-;CHECK:         {{%\w+}} = OpULessThan %bool %41 %uint_128
-;CHECK:               OpSelectionMerge {{%\w+}} None
-;CHECK:               OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-;CHECK:        {{%\w+}} = OpLabel
-;CHECK:        {{%\w+}} = OpLoad %16 %34
-;CHECK:        {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
-;CHECK:        {{%\w+}} = OpUConvert %uint %33
-;CHECK:        {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 {{%\w+}}
-;CHECK:        {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
-;CHECK:               OpSelectionMerge {{%\w+}} None
-;CHECK:               OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-;CHECK:        {{%\w+}} = OpLabel
-;CHECK:        {{%\w+}} = OpLoad %16 %34
-;CHECK:        {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
-;CHECK:        {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31
-;CHECK:               OpBranch {{%\w+}}
-;CHECK:        {{%\w+}} = OpLabel
-;CHECK:        {{%\w+}} = OpUConvert %uint %33
-;CHECK:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_60 %uint_1 %uint_1 %uint_2 {{%\w+}} %uint_0
-;CHECK:               OpBranch {{%\w+}}
-;CHECK:        {{%\w+}} = OpLabel
-;CHECK:        [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
-;CHECK:               OpBranch %44
-;CHECK:         %46 = OpLabel
-;CHECK:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_60 %uint_0 %uint_1 %uint_2 %41 %uint_128
-;CHECK:               OpBranch %44
-;CHECK:         %44 = OpLabel
-;CHECK:        [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] %46
-;CHECK:               OpStore %_entryPointOutput_vColor [[phi_result_2]]
-               OpReturn
-               OpFunctionEnd
-)" + kStreamWrite6Frag + kReadDescInit;
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+)" + kImportStub + R"(
+%MainPs = OpFunction %void None %10
+%30 = OpLabel
+;CHECK:  OpBranch %39
+;CHECK:  %39 = OpLabel
+%31 = OpLoad %v2float %i_vTextureCoords
+%32 = OpAccessChain %_ptr_PushConstant_ushort %_ %int_0
+%33 = OpLoad %ushort %32
+%34 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %33
+%35 = OpLoad %16 %34
+%36 = OpLoad %25 %g_sAniso
+%37 = OpSampledImage %27 %35 %36
+%38 = OpImageSampleImplicitLod %v4float %37 %31
+OpStore %_entryPointOutput_vColor %38
+;CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31
+;CHECK-NOT: OpStore %_entryPointOutput_vColor %38
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpUConvert %uint %33
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_61 {{%\w+}} %uint_1 %uint_2 {{%\w+}} %uint_0
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %16 %34
+;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
-                                               false, false, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
@@ -4496,136 +4105,133 @@
 
   // clang-format off
   const std::string text = R"(
-               OpCapability Shader
-               OpCapability Int16
-               OpCapability StoragePushConstant16
-;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
-;CHECK:        OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord
-               OpExecutionMode %MainPs OriginUpperLeft
-               OpSource HLSL 500
-               OpName %MainPs "MainPs"
-               OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
-               OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
-               OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
-               OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
-               OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
-               OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
-               OpName %_ ""
-               OpName %PerViewPushConst_t "PerViewPushConst_t"
-               OpMemberName %PerViewPushConst_t 0 "g_c"
-               OpName %__0 ""
-               OpName %g_tColor "g_tColor"
-               OpName %g_sAniso "g_sAniso"
-               OpName %i_vTextureCoords "i.vTextureCoords"
-               OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48
-               OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64
-               OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80
-               OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0
-               OpDecorate %_BindlessFastEnvMapCB_PS_t Block
-               OpDecorate %_ DescriptorSet 0
-               OpDecorate %_ Binding 0
-               OpMemberDecorate %PerViewPushConst_t 0 Offset 0
-               OpDecorate %PerViewPushConst_t Block
-               OpDecorate %g_tColor DescriptorSet 0
-               OpDecorate %g_tColor Binding 0
-               OpDecorate %g_sAniso DescriptorSet 0
-               OpDecorate %g_sAniso Binding 0
-               OpDecorate %i_vTextureCoords Location 0
-               OpDecorate %_entryPointOutput_vColor Location 0
-;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + kOutputDecorations + R"(
-;CHECK:               OpDecorate %gl_FragCoord BuiltIn FragCoord
-       %void = OpTypeVoid
-         %14 = OpTypeFunction %void
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-    %v4float = OpTypeVector %float 4
-    %v3float = OpTypeVector %float 3
+OpCapability Shader
+OpCapability Int16
+OpCapability StoragePushConstant16
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
+;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
+OpExecutionMode %MainPs OriginUpperLeft
+OpSource HLSL 500
+OpName %MainPs "MainPs"
+OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
+OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
+OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
+OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
+OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
+OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
+OpName %_ ""
+OpName %PerViewPushConst_t "PerViewPushConst_t"
+OpMemberName %PerViewPushConst_t 0 "g_c"
+OpName %__0 ""
+OpName %g_tColor "g_tColor"
+OpName %g_sAniso "g_sAniso"
+OpName %i_vTextureCoords "i.vTextureCoords"
+OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48
+OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64
+OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80
+OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0
+OpDecorate %_BindlessFastEnvMapCB_PS_t Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 0
+OpMemberDecorate %PerViewPushConst_t 0 Offset 0
+OpDecorate %PerViewPushConst_t Block
+OpDecorate %g_tColor DescriptorSet 0
+OpDecorate %g_tColor Binding 0
+OpDecorate %g_sAniso DescriptorSet 0
+OpDecorate %g_sAniso Binding 0
+OpDecorate %i_vTextureCoords Location 0
+OpDecorate %_entryPointOutput_vColor Location 0
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%14 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v2float = OpTypeVector %float 2
+%v4float = OpTypeVector %float 4
+%v3float = OpTypeVector %float 3
 %mat4v3float = OpTypeMatrix %v3float 4
 %PerBatchEnvMapConstantBuffer_t = OpTypeStruct %mat4v3float %v4float %v2float
-       %uint = OpTypeInt 32 0
-   %uint_128 = OpConstant %uint 128
+%uint = OpTypeInt 32 0
+%uint_128 = OpConstant %uint 128
 %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 = OpTypeArray %PerBatchEnvMapConstantBuffer_t %uint_128
 %_BindlessFastEnvMapCB_PS_t = OpTypeStruct %_arr_PerBatchEnvMapConstantBuffer_t_uint_128
 %_ptr_Uniform__BindlessFastEnvMapCB_PS_t = OpTypePointer Uniform %_BindlessFastEnvMapCB_PS_t
-          %_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
-     %ushort = OpTypeInt 16 0
+%_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%ushort = OpTypeInt 16 0
 %PerViewPushConst_t = OpTypeStruct %ushort
 %_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t
-        %__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
+%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
 %_ptr_PushConstant_ushort = OpTypePointer PushConstant %ushort
-      %int_2 = OpConstant %int 2
+%int_2 = OpConstant %int 2
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-         %30 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%30 = OpTypeImage %float 2D 0 0 0 1 Unknown
 %_ptr_UniformConstant_30 = OpTypePointer UniformConstant %30
-   %g_tColor = OpVariable %_ptr_UniformConstant_30 UniformConstant
-         %32 = OpTypeSampler
+%g_tColor = OpVariable %_ptr_UniformConstant_30 UniformConstant
+%32 = OpTypeSampler
 %_ptr_UniformConstant_32 = OpTypePointer UniformConstant %32
-   %g_sAniso = OpVariable %_ptr_UniformConstant_32 UniformConstant
-         %34 = OpTypeSampledImage %30
+%g_sAniso = OpVariable %_ptr_UniformConstant_32 UniformConstant
+%34 = OpTypeSampledImage %30
 %_ptr_Input_v2float = OpTypePointer Input %v2float
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-)" + kInputGlobals + kOutputGlobals + R"(
-;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float
-;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-;CHECK:        [[null_v2float:%\w+]] = OpConstantNull %v2float
-     %MainPs = OpFunction %void None %14
-         %37 = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
-         %38 = OpLoad %v2float %i_vTextureCoords
-         %39 = OpAccessChain %_ptr_PushConstant_ushort %__0 %int_0
-         %40 = OpLoad %ushort %39
-         %41 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %40 %int_2
-         %42 = OpLoad %v2float %41
-         %43 = OpFAdd %v2float %38 %42
-;CHECK-NOT:     %42 = OpLoad %v2float %41
-;CHECK-NOT:     %43 = OpFAdd %v2float %38 %42
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
+)" + kImportStub + R"(
+%MainPs = OpFunction %void None %14
+%37 = OpLabel
+%38 = OpLoad %v2float %i_vTextureCoords
+%39 = OpAccessChain %_ptr_PushConstant_ushort %__0 %int_0
+%40 = OpLoad %ushort %39
+%41 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %40 %int_2
+%42 = OpLoad %v2float %41
+%43 = OpFAdd %v2float %38 %42
+;CHECK-NOT: %42 = OpLoad %v2float %41
+;CHECK-NOT: %43 = OpFAdd %v2float %38 %42
 ;CHECK: {{%\w+}} = OpUConvert %uint %40
 ;CHECK: {{%\w+}} = OpIMul %uint %uint_80 {{%\w+}}
 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64
 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
-;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_82 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
 ;CHECK: OpSelectionMerge {{%\w+}} None
 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: {{%\w+}} = OpLoad %v2float %41
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_81 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}}
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
 ;CHECK: %43 = OpFAdd %v2float %38 {{%\w+}}
-         %44 = OpLoad %30 %g_tColor
-         %45 = OpLoad %32 %g_sAniso
-         %46 = OpSampledImage %34 %44 %45
-         %47 = OpImageSampleImplicitLod %v4float %46 %43
-               OpStore %_entryPointOutput_vColor %47
-               OpReturn
-               OpFunctionEnd
-               )" + kReadDescInit + kStreamWrite7Frag;
+%44 = OpLoad %30 %g_tColor
+%45 = OpLoad %32 %g_sAniso
+%46 = OpSampledImage %34 %44 %45
+%47 = OpImageSampleImplicitLod %v4float %46 %43
+OpStore %_entryPointOutput_vColor %47
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, false, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
@@ -4649,102 +4255,98 @@
 
   // clang-format off
   std::string text = R"(
-               OpCapability Shader
-;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
-;CHECK:        OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_VertexIndex %gl_InstanceIndex
-               OpSource GLSL 450
-               OpSourceExtension "GL_EXT_scalar_block_layout"
-               OpName %main "main"
-               OpName %v_vtxResult "v_vtxResult"
-               OpName %Block "Block"
-               OpMemberName %Block 0 "var"
-               OpName %_ ""
-               OpName %a_position "a_position"
-               OpDecorate %v_vtxResult RelaxedPrecision
-               OpDecorate %v_vtxResult Location 0
-               OpMemberDecorate %Block 0 RowMajor
-               OpMemberDecorate %Block 0 RelaxedPrecision
-               OpMemberDecorate %Block 0 Offset 0
-               OpMemberDecorate %Block 0 MatrixStride 16
-               OpDecorate %Block Block
-               OpDecorate %_ DescriptorSet 0
-               OpDecorate %_ Binding 0
-               OpDecorate %21 RelaxedPrecision
-;CHECK-NOT:           OpDecorate %21 RelaxedPrecision
+OpCapability Shader
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
+;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %gl_VertexIndex %gl_InstanceIndex
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_scalar_block_layout"
+OpName %main "main"
+OpName %v_vtxResult "v_vtxResult"
+OpName %Block "Block"
+OpMemberName %Block 0 "var"
+OpName %_ ""
+OpName %a_position "a_position"
+OpDecorate %v_vtxResult RelaxedPrecision
+OpDecorate %v_vtxResult Location 0
+OpMemberDecorate %Block 0 RowMajor
+OpMemberDecorate %Block 0 RelaxedPrecision
+OpMemberDecorate %Block 0 Offset 0
+OpMemberDecorate %Block 0 MatrixStride 16
+OpDecorate %Block Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 0
+OpDecorate %21 RelaxedPrecision
+;CHECK-NOT: OpDecorate %21 RelaxedPrecision
 ;CHECK: OpDecorate %v_vtxResult RelaxedPrecision
 ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision
-               OpDecorate %a_position Location 0
-;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + R"(
-;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
-)" + kOutputDecorations + R"(
+OpDecorate %a_position Location 0
+)" + kImportDeco + R"(
 ;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
 ;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
-       %void = OpTypeVoid
-          %3 = OpTypeFunction %void
-      %float = OpTypeFloat 32
+;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
 %_ptr_Output_float = OpTypePointer Output %float
 %v_vtxResult = OpVariable %_ptr_Output_float Output
-    %v2float = OpTypeVector %float 2
+%v2float = OpTypeVector %float 2
 %mat4v2float = OpTypeMatrix %v2float 4
-      %Block = OpTypeStruct %mat4v2float
+%Block = OpTypeStruct %mat4v2float
 %_ptr_Uniform_Block = OpTypePointer Uniform %Block
-          %_ = OpVariable %_ptr_Uniform_Block Uniform
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
-      %int_2 = OpConstant %int 2
-       %uint = OpTypeInt 32 0
-     %uint_1 = OpConstant %uint 1
+%_ = OpVariable %_ptr_Uniform_Block Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%int_2 = OpConstant %int 2
+%uint = OpTypeInt 32 0
+%uint_1 = OpConstant %uint 1
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-    %v4float = OpTypeVector %float 4
+%v4float = OpTypeVector %float 4
 %_ptr_Input_v4float = OpTypePointer Input %v4float
- %a_position = OpVariable %_ptr_Input_v4float Input
-)" + kInputGlobals + kOutputGlobals + R"(
-;CHECK:%_ptr_Input_uint = OpTypePointer Input %uint
-;CHECK:%gl_VertexIndex = OpVariable %_ptr_Input_uint Input
-;CHECK:%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
+%a_position = OpVariable %_ptr_Input_v4float Input
+;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
+;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input
+;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
 ;CHECK: [[null_float:%\w+]] = OpConstantNull %float
-       %main = OpFunction %void None %3
-          %5 = OpLabel
-;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+)" + kImportStub + R"(
+%main = OpFunction %void None %3
+%5 = OpLabel
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
-         %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
-         %21 = OpLoad %float %20
-;CHECK-NOT:     %21 = OpLoad %float %20
+%20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
+%21 = OpLoad %float %20
+;CHECK-NOT: %21 = OpLoad %float %20
 ;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_2
 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
 ;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %uint_1
 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} [[desc_state]]
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
 ;CHECK: OpSelectionMerge {{%\w+}} None
-;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: [[load_result]] = OpLoad %float %20
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: {{\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_45 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}}
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}}
-               OpStore %v_vtxResult %21
-;CHECK-NOT:    OpStore %v_vtxResult %21
-;CHECK:  OpStore %v_vtxResult [[phi_result]]
-               OpReturn
-               OpFunctionEnd
-               )" + kReadDescInit + kStreamWrite7Vert;
+OpStore %v_vtxResult %21
+;CHECK-NOT: OpStore %v_vtxResult %21$
+;CHECK: OpStore %v_vtxResult [[phi_result]]
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, false, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) {
@@ -4768,103 +4370,99 @@
 
   // clang-format off
   const std::string text = R"(
-               OpCapability Shader
-;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
-;CHECK:        OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_VertexIndex %gl_InstanceIndex
-               OpSource GLSL 450
-               OpSourceExtension "GL_EXT_scalar_block_layout"
-               OpName %main "main"
-               OpName %v_vtxResult "v_vtxResult"
-               OpName %Block "Block"
-               OpMemberName %Block 0 "var"
-               OpName %_ ""
-               OpName %a_position "a_position"
-               OpDecorate %v_vtxResult RelaxedPrecision
-               OpDecorate %v_vtxResult Location 0
-               OpMemberDecorate %Block 0 ColMajor
-               OpMemberDecorate %Block 0 RelaxedPrecision
-               OpMemberDecorate %Block 0 Offset 0
-               OpMemberDecorate %Block 0 MatrixStride 8
-               OpDecorate %Block Block
-               OpDecorate %_ DescriptorSet 0
-               OpDecorate %_ Binding 0
-               OpDecorate %21 RelaxedPrecision
-;CHECK-NOT:    OpDecorate %21 RelaxedPrecision
+OpCapability Shader
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
+;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %gl_VertexIndex %gl_InstanceIndex
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_scalar_block_layout"
+OpName %main "main"
+OpName %v_vtxResult "v_vtxResult"
+OpName %Block "Block"
+OpMemberName %Block 0 "var"
+OpName %_ ""
+OpName %a_position "a_position"
+OpDecorate %v_vtxResult RelaxedPrecision
+OpDecorate %v_vtxResult Location 0
+OpMemberDecorate %Block 0 ColMajor
+OpMemberDecorate %Block 0 RelaxedPrecision
+OpMemberDecorate %Block 0 Offset 0
+OpMemberDecorate %Block 0 MatrixStride 8
+OpDecorate %Block Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 0
+OpDecorate %21 RelaxedPrecision
+;CHECK-NOT: OpDecorate %21 RelaxedPrecision
 ;CHECK: OpDecorate %v_vtxResult RelaxedPrecision
 ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision
-               OpDecorate %a_position Location 0
-;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + R"(
-;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
-)" + kOutputDecorations + R"(
+OpDecorate %a_position Location 0
+)" + kImportDeco + R"(
 ;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
 ;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
-       %void = OpTypeVoid
-          %3 = OpTypeFunction %void
-      %float = OpTypeFloat 32
+;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
 %_ptr_Output_float = OpTypePointer Output %float
 %v_vtxResult = OpVariable %_ptr_Output_float Output
-    %v2float = OpTypeVector %float 2
+%v2float = OpTypeVector %float 2
 %mat4v2float = OpTypeMatrix %v2float 4
-      %Block = OpTypeStruct %mat4v2float
+%Block = OpTypeStruct %mat4v2float
 %_ptr_Uniform_Block = OpTypePointer Uniform %Block
-          %_ = OpVariable %_ptr_Uniform_Block Uniform
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
-      %int_2 = OpConstant %int 2
-       %uint = OpTypeInt 32 0
-     %uint_1 = OpConstant %uint 1
+%_ = OpVariable %_ptr_Uniform_Block Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%int_2 = OpConstant %int 2
+%uint = OpTypeInt 32 0
+%uint_1 = OpConstant %uint 1
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-    %v4float = OpTypeVector %float 4
+%v4float = OpTypeVector %float 4
 %_ptr_Input_v4float = OpTypePointer Input %v4float
- %a_position = OpVariable %_ptr_Input_v4float Input
-)" + kInputGlobals + kOutputGlobals + R"(
-;CHECK:%_ptr_Input_uint = OpTypePointer Input %uint
-;CHECK:%gl_VertexIndex = OpVariable %_ptr_Input_uint Input
-;CHECK:%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
+%a_position = OpVariable %_ptr_Input_v4float Input
+;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
+;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input
+;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
 ;CHECK: [[null_float:%\w+]] = OpConstantNull %float
+)" + kImportStub + R"(
 %main = OpFunction %void None %3
-          %5 = OpLabel
-;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
-;CHECK: OpBranch %26
-;CHECK: %26 = OpLabel
-;CHECK: OpBranch %25
-;CHECK: %25 = OpLabel
-         %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
-         %21 = OpLoad %float %20
-;CHECK-NOT:     %21 = OpLoad %float %20
-;CHECK: %29 = OpIMul %uint %uint_8 %int_2
-;CHECK: %30 = OpIAdd %uint %uint_0 %29
-;CHECK: %32 = OpIMul %uint %uint_4 %uint_1
-;CHECK: %33 = OpIAdd %uint %30 %32
-;CHECK: %35 = OpIAdd %uint %33 %uint_3
-;CHECK: {{%\w+}} = OpULessThan %bool %35 [[desc_state]]
+%5 = OpLabel
+%20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
+%21 = OpLoad %float %20
+;CHECK-NOT: %21 = OpLoad %float %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpIMul %uint %uint_8 %int_2
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
+;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %uint_1
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
 ;CHECK: OpSelectionMerge {{%\w+}} None
-;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK:[[load_result]] = OpLoad %float %20
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_45 %uint_4 %uint_0 %uint_0 %uint_0 %35 {{%\w+}}
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}}
-               OpStore %v_vtxResult %21
-;CHECK-NOT:           OpStore %v_vtxResult %21
+OpStore %v_vtxResult %21
+;CHECK-NOT: OpStore %v_vtxResult %21$
 ;CHECK: OpStore %v_vtxResult [[phi_result]]
-               OpReturn
-               OpFunctionEnd
-               )" + kReadDescInit + kStreamWrite7Vert;
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   ValidatorOptions()->uniform_buffer_standard_layout = true;
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, false, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) {
@@ -4888,109 +4486,103 @@
 
   // clang-format off
   const std::string text = R"(
-               OpCapability Shader
-;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
-;CHECK:        OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_VertexIndex %gl_InstanceIndex
-               OpSource GLSL 450
-               OpSourceExtension "GL_EXT_scalar_block_layout"
-               OpName %main "main"
-               OpName %v_vtxResult "v_vtxResult"
-               OpName %Block "Block"
-               OpMemberName %Block 0 "var"
-               OpName %_ ""
-               OpName %a_position "a_position"
-               OpDecorate %v_vtxResult Location 0
-               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 32
-               OpDecorate %_arr__arr_mat2v2float_uint_4_uint_3 ArrayStride 128
-               OpMemberDecorate %Block 0 RowMajor
-               OpMemberDecorate %Block 0 RelaxedPrecision
-               OpMemberDecorate %Block 0 Offset 0
-               OpMemberDecorate %Block 0 MatrixStride 16
-               OpDecorate %Block Block
-               OpDecorate %_ DescriptorSet 3
-               OpDecorate %_ Binding 7
-               OpDecorate %26 RelaxedPrecision
-;CHECK-NOT:               OpDecorate %26 RelaxedPrecision
+OpCapability Shader
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
+;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %gl_VertexIndex %gl_InstanceIndex
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_scalar_block_layout"
+OpName %main "main"
+OpName %v_vtxResult "v_vtxResult"
+OpName %Block "Block"
+OpMemberName %Block 0 "var"
+OpName %_ ""
+OpName %a_position "a_position"
+OpDecorate %v_vtxResult Location 0
+OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 32
+OpDecorate %_arr__arr_mat2v2float_uint_4_uint_3 ArrayStride 128
+OpMemberDecorate %Block 0 RowMajor
+OpMemberDecorate %Block 0 RelaxedPrecision
+OpMemberDecorate %Block 0 Offset 0
+OpMemberDecorate %Block 0 MatrixStride 16
+OpDecorate %Block Block
+OpDecorate %_ DescriptorSet 3
+OpDecorate %_ Binding 7
+OpDecorate %26 RelaxedPrecision
+;CHECK-NOT: OpDecorate %26 RelaxedPrecision
 ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision
-               OpDecorate %a_position Location 0
-;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + R"(
-;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
-)" + kOutputDecorations + R"(
+OpDecorate %a_position Location 0
+)" + kImportDeco + R"(
 ;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
 ;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
-       %void = OpTypeVoid
-          %3 = OpTypeFunction %void
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
+;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v2float = OpTypeVector %float 2
 %_ptr_Output_v2float = OpTypePointer Output %v2float
 %v_vtxResult = OpVariable %_ptr_Output_v2float Output
 %mat2v2float = OpTypeMatrix %v2float 2
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
+%uint = OpTypeInt 32 0
+%uint_4 = OpConstant %uint 4
 %_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
-     %uint_3 = OpConstant %uint 3
+%uint_3 = OpConstant %uint 3
 %_arr__arr_mat2v2float_uint_4_uint_3 = OpTypeArray %_arr_mat2v2float_uint_4 %uint_3
-      %Block = OpTypeStruct %_arr__arr_mat2v2float_uint_4_uint_3
+%Block = OpTypeStruct %_arr__arr_mat2v2float_uint_4_uint_3
 %_ptr_Uniform_Block = OpTypePointer Uniform %Block
-          %_ = OpVariable %_ptr_Uniform_Block Uniform
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
-      %int_2 = OpConstant %int 2
-      %int_3 = OpConstant %int 3
-      %int_1 = OpConstant %int 1
+%_ = OpVariable %_ptr_Uniform_Block Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%int_2 = OpConstant %int 2
+%int_3 = OpConstant %int 3
+%int_1 = OpConstant %int 1
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-    %v4float = OpTypeVector %float 4
+%v4float = OpTypeVector %float 4
 %_ptr_Input_v4float = OpTypePointer Input %v4float
- %a_position = OpVariable %_ptr_Input_v4float Input
-)" + kInputGlobals + kOutputGlobals + R"(
-;CHECK:%_ptr_Input_uint = OpTypePointer Input %uint
-;CHECK:%gl_VertexIndex = OpVariable %_ptr_Input_uint Input
-;CHECK:%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
+%a_position = OpVariable %_ptr_Input_v4float Input
+;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
+;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input
+;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
 ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
-       %main = OpFunction %void None %3
-          %5 = OpLabel
-;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_7 %uint_0
-;CHECK: OpBranch %31
-;CHECK: %31 = OpLabel
-;CHECK: OpBranch %30
-;CHECK: %30 = OpLabel
-         %25 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %int_2 %int_3 %int_1
-         %26 = OpLoad %v2float %25
-               OpStore %v_vtxResult %26
+)" + kImportStub + R"(
+%main = OpFunction %void None %3
+%5 = OpLabel
+%25 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %int_2 %int_3 %int_1
+;CHECK: {{%\w+}} = OpIMul %uint %uint_128 %int_2
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
+;CHECK: {{%\w+}} = OpIMul %uint %uint_32 %int_3
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_1
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_19
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
+%26 = OpLoad %v2float %25
+OpStore %v_vtxResult %26
 ;CHECK-NOT: %26 = OpLoad %v2float %25
-;CHECK-NOT:    OpStore %v_vtxResult %26
-;CHECK: %34 = OpIMul %uint %uint_128 %int_2
-;CHECK: %35 = OpIAdd %uint %uint_0 %34
-;CHECK: %37 = OpIMul %uint %uint_32 %int_3
-;CHECK: %38 = OpIAdd %uint %35 %37
-;CHECK: %40 = OpIMul %uint %uint_4 %int_1
-;CHECK: %41 = OpIAdd %uint %38 %40
-;CHECK: %43 = OpIAdd %uint %41 %uint_19
-;CHECK: {{%\w+}} = OpULessThan %bool %43 [[desc_state]]
+;CHECK-NOT: OpStore %v_vtxResult %26
 ;CHECK: OpSelectionMerge {{%\w+}} None
-;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: [[load_result]] = OpLoad %v2float %25
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_51 %uint_4 %uint_3 %uint_7 %uint_0 {{%\w+}} {{%\w+}}
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: [[phi_result]] = OpPhi %v2float [[load_result]] {{%\w+}} [[null_v2float]] {{%\w+}}
 ;CHECK: OpStore %v_vtxResult [[phi_result]]
-               OpReturn
-               OpFunctionEnd
-               )" + kReadDescInit + kStreamWrite7Vert;
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, false, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, ImageBufferOOBRead) {
@@ -5007,86 +4599,76 @@
 
   // clang-format off
   const std::string text = R"(
-                          OpCapability Shader
-                          OpCapability ImageBuffer
-;CHECK:                   OpCapability ImageQuery
-;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
-                     %1 = OpExtInstImport "GLSL.std.450"
-                          OpMemoryModel Logical GLSL450
-                          OpEntryPoint Fragment %main "main" %x %s %ii
-                          OpExecutionMode %main OriginUpperLeft
-                          OpSource GLSL 450
-                          OpName %main "main"
-                          OpName %x "x"
-                          OpName %s "s"
-                          OpName %ii "ii"
-                          OpDecorate %x Location 11
-                          OpDecorate %s DescriptorSet 3
-                          OpDecorate %s Binding 7
-                          OpDecorate %s NonWritable
-                          OpDecorate %ii Flat
-                          OpDecorate %ii Location 13
-;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
-                  %void = OpTypeVoid
-                     %3 = OpTypeFunction %void
-                 %float = OpTypeFloat 32
-               %v4float = OpTypeVector %float 4
-           %_ptr_Output_v4float = OpTypePointer Output %v4float
-                     %x = OpVariable %_ptr_Output_v4float Output
-                    %10 = OpTypeImage %float Buffer 0 0 0 2 R32f
-           %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
-                     %s = OpVariable %_ptr_UniformConstant_10 UniformConstant
-                   %int = OpTypeInt 32 1
-           %_ptr_Input_int = OpTypePointer Input %int
-                    %ii = OpVariable %_ptr_Input_int Input
-;CHECK:           %uint = OpTypeInt 32 0
-;CHECK:           %bool = OpTypeBool
-;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-;CHECK:    %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
-;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+OpCapability Shader
+OpCapability ImageBuffer
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %x %s %ii
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 450
+OpName %main "main"
+OpName %x "x"
+OpName %s "s"
+OpName %ii "ii"
+OpDecorate %x Location 11
+OpDecorate %s DescriptorSet 3
+OpDecorate %s Binding 7
+OpDecorate %s NonWritable
+OpDecorate %ii Flat
+OpDecorate %ii Location 13
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%x = OpVariable %_ptr_Output_v4float Output
+%10 = OpTypeImage %float Buffer 0 0 0 2 R32f
+%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
+%s = OpVariable %_ptr_UniformConstant_10 UniformConstant
+%int = OpTypeInt 32 1
+%_ptr_Input_int = OpTypePointer Input %int
+%ii = OpVariable %_ptr_Input_int Input
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
 ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-                  %main = OpFunction %void None %3
-                     %5 = OpLabel
-;CHECK:                   OpBranch %21
-;CHECK:             %21 = OpLabel
-;CHECK:                   OpBranch %20
-;CHECK:             %20 = OpLabel
-;CHECK:                   OpBranch %19
-;CHECK:             %19 = OpLabel
-                    %13 = OpLoad %10 %s
-                    %17 = OpLoad %int %ii
-                    %18 = OpImageRead %v4float %13 %17
-                          OpStore %x %18
-;CHECK-NOT:         %18 = OpImageRead %v4float %13 %17
-;CHECK-NOT:               OpStore %x %18
-;CHECK:             %23 = OpBitcast %uint %17
-;CHECK:             %25 = OpImageQuerySize %uint %13
-;CHECK:             %27 = OpULessThan %bool %23 %25
-;CHECK:                   OpSelectionMerge %29 None
-;CHECK:                   OpBranchConditional %27 %30 %31
-;CHECK:             %30 = OpLabel
-;CHECK:             %32 = OpLoad %10 %s
-;CHECK:             %33 = OpImageRead %v4float %32 %17
-;CHECK:                   OpBranch %29
-;CHECK:             %31 = OpLabel
-;CHECK:             {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_33 %uint_7 %uint_3 %uint_7 %uint_0 %23 %25
-;CHECK:                   OpBranch %29
-;CHECK:             %29 = OpLabel
-;CHECK:             [[phi_result:%\w+]] = OpPhi %v4float %33 %30 [[null_v4float]] %31
-;CHECK:                   OpStore %x [[phi_result]]
-                          OpReturn
-                          OpFunctionEnd
-                          )" + kStreamWrite7Frag;
+%main = OpFunction %void None %3
+%5 = OpLabel
+;CHECK: OpBranch %19
+;CHECK: %19 = OpLabel
+%13 = OpLoad %10 %s
+%17 = OpLoad %int %ii
+%18 = OpImageRead %v4float %13 %17
+OpStore %x %18
+;CHECK-NOT: %18 = OpImageRead %v4float %13 %17
+;CHECK-NOT: OpStore %x %18
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_34 {{%\w+}} %uint_3 %uint_7 %uint_0 %22
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %10 %s
+;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %17
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %x [[phi_result]]
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, true, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, ImageBufferOOBWrite) {
@@ -5103,85 +4685,75 @@
 
   // clang-format off
   const std::string text = R"(
-                          OpCapability Shader
-                          OpCapability ImageBuffer
-;CHECK:                   OpCapability ImageQuery
-;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
-                     %1 = OpExtInstImport "GLSL.std.450"
-                          OpMemoryModel Logical GLSL450
-                          OpEntryPoint Fragment %main "main" %s %ii %x
-;CHECK:                   OpEntryPoint Fragment %main "main" %s %ii %x %inst_bindless_output_buffer %gl_FragCoord
-                          OpExecutionMode %main OriginUpperLeft
-                          OpSource GLSL 450
-                          OpName %main "main"
-                          OpName %s "s"
-                          OpName %ii "ii"
-                          OpName %x "x"
-                          OpDecorate %s DescriptorSet 3
-                          OpDecorate %s Binding 7
-                          OpDecorate %s NonReadable
-                          OpDecorate %ii Flat
-                          OpDecorate %ii Location 13
-                          OpDecorate %x Location 11
-;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
-                  %void = OpTypeVoid
-                     %3 = OpTypeFunction %void
-                 %float = OpTypeFloat 32
-                     %7 = OpTypeImage %float Buffer 0 0 0 2 R32f
-           %_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7
-                     %s = OpVariable %_ptr_UniformConstant_7 UniformConstant
-                   %int = OpTypeInt 32 1
-           %_ptr_Input_int = OpTypePointer Input %int
-                    %ii = OpVariable %_ptr_Input_int Input
-               %v4float = OpTypeVector %float 4
-           %_ptr_Output_v4float = OpTypePointer Output %v4float
-                     %x = OpVariable %_ptr_Output_v4float Output
-;CHECK:           %uint = OpTypeInt 32 0
-;CHECK:           %bool = OpTypeBool
-;CHECK:        {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint %uint
-;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-;CHECK:    %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
-;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-;CHECK:         %v4uint = OpTypeVector %uint 4
-                  %main = OpFunction %void None %3
-                     %5 = OpLabel
-;CHECK:                   OpBranch %21
-;CHECK:             %21 = OpLabel
-;CHECK:                   OpBranch %20
-;CHECK:             %20 = OpLabel
-;CHECK:                   OpBranch %19
-;CHECK:             %19 = OpLabel
-                    %10 = OpLoad %7 %s
-                    %14 = OpLoad %int %ii
-                    %18 = OpLoad %v4float %x
-                          OpImageWrite %10 %14 %18
-;CHECK-NOT:               OpImageWrite %10 %14 %18
-;CHECK:             %23 = OpBitcast %uint %14
-;CHECK:             %25 = OpImageQuerySize %uint %10
-;CHECK:             %27 = OpULessThan %bool %23 %25
-;CHECK:                   OpSelectionMerge %29 None
-;CHECK:                   OpBranchConditional %27 %30 %31
-;CHECK:             %30 = OpLabel
-;CHECK:             %32 = OpLoad %7 %s
-;CHECK:                   OpImageWrite %32 %14 %18
-;CHECK:                   OpBranch %29
-;CHECK:             %31 = OpLabel
-;CHECK:             {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_34 %uint_7 %uint_3 %uint_7 %uint_0 %23 %25
-;CHECK:                   OpBranch %29
-;CHECK:             %29 = OpLabel
-                          OpReturn
-                          OpFunctionEnd
-                          )" + kStreamWrite7Frag;
+OpCapability Shader
+OpCapability ImageBuffer
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %s %ii %x
+;CHECK: OpEntryPoint Fragment %main "main" %s %ii %x %gl_FragCoord
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 450
+OpName %main "main"
+OpName %s "s"
+OpName %ii "ii"
+OpName %x "x"
+OpDecorate %s DescriptorSet 3
+OpDecorate %s Binding 7
+OpDecorate %s NonReadable
+OpDecorate %ii Flat
+OpDecorate %ii Location 13
+OpDecorate %x Location 11
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%7 = OpTypeImage %float Buffer 0 0 0 2 R32f
+%_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7
+%s = OpVariable %_ptr_UniformConstant_7 UniformConstant
+%int = OpTypeInt 32 1
+%_ptr_Input_int = OpTypePointer Input %int
+%ii = OpVariable %_ptr_Input_int Input
+%v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%x = OpVariable %_ptr_Output_v4float Output
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+)" + kImportStub + R"(
+%main = OpFunction %void None %3
+%5 = OpLabel
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: %19 = OpLabel
+%10 = OpLoad %7 %s
+%14 = OpLoad %int %ii
+%18 = OpLoad %v4float %x
+OpImageWrite %10 %14 %18
+;CHECK-NOT: OpImageWrite %10 %14 %18
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_35 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %7 %s
+;CHECK: OpImageWrite {{%\w+}} %14 %18
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, true, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, TextureBufferOOBFetch) {
@@ -5198,86 +4770,75 @@
 
   // clang-format off
   const std::string text = R"(
-                          OpCapability Shader
-                          OpCapability SampledBuffer
-;CHECK:                   OpCapability ImageQuery
-;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
-                     %1 = OpExtInstImport "GLSL.std.450"
-                          OpMemoryModel Logical GLSL450
-                          OpEntryPoint Fragment %main "main" %x %s %ii
-;CHECK:                   OpEntryPoint Fragment %main "main" %x %s %ii %inst_bindless_output_buffer %gl_FragCoord
-                          OpExecutionMode %main OriginUpperLeft
-                          OpSource GLSL 450
-                          OpName %main "main"
-                          OpName %x "x"
-                          OpName %s "s"
-                          OpName %ii "ii"
-                          OpDecorate %x Location 11
-                          OpDecorate %s DescriptorSet 3
-                          OpDecorate %s Binding 7
-                          OpDecorate %ii Flat
-                          OpDecorate %ii Location 13
-;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
-                  %void = OpTypeVoid
-                     %3 = OpTypeFunction %void
-                 %float = OpTypeFloat 32
-               %v4float = OpTypeVector %float 4
-           %_ptr_Output_v4float = OpTypePointer Output %v4float
-                     %x = OpVariable %_ptr_Output_v4float Output
-                    %10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
-           %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
-                     %s = OpVariable %_ptr_UniformConstant_10 UniformConstant
-                   %int = OpTypeInt 32 1
-           %_ptr_Input_int = OpTypePointer Input %int
-                    %ii = OpVariable %_ptr_Input_int Input
-;CHECK:           %uint = OpTypeInt 32 0
-;CHECK:           %bool = OpTypeBool
-;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-;CHECK:    %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
-;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+OpCapability Shader
+OpCapability SampledBuffer
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %x %s %ii
+;CHECK: OpEntryPoint Fragment %main "main" %x %s %ii %gl_FragCoord
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 450
+OpName %main "main"
+OpName %x "x"
+OpName %s "s"
+OpName %ii "ii"
+OpDecorate %x Location 11
+OpDecorate %s DescriptorSet 3
+OpDecorate %s Binding 7
+OpDecorate %ii Flat
+OpDecorate %ii Location 13
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%x = OpVariable %_ptr_Output_v4float Output
+%10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
+%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
+%s = OpVariable %_ptr_UniformConstant_10 UniformConstant
+%int = OpTypeInt 32 1
+%_ptr_Input_int = OpTypePointer Input %int
+%ii = OpVariable %_ptr_Input_int Input
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
 ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-                  %main = OpFunction %void None %3
-                     %5 = OpLabel
-;CHECK:                   OpBranch %21
-;CHECK:             %21 = OpLabel
-;CHECK:                   OpBranch %20
-;CHECK:             %20 = OpLabel
-;CHECK:                   OpBranch %19
-;CHECK:             %19 = OpLabel
-                    %13 = OpLoad %10 %s
-                    %17 = OpLoad %int %ii
-                    %18 = OpImageFetch %v4float %13 %17
-                          OpStore %x %18
-;CHECK-NOT:         %18 = OpImageFetch %v4float %13 %17
-;CHECK-NOT:               OpStore %x %18
-;CHECK:             %23 = OpBitcast %uint %17
-;CHECK:             %25 = OpImageQuerySize %uint %13
-;CHECK:             %27 = OpULessThan %bool %23 %25
-;CHECK:                   OpSelectionMerge %29 None
-;CHECK:                   OpBranchConditional %27 %30 %31
-;CHECK:             %30 = OpLabel
-;CHECK:             %32 = OpLoad %10 %s
-;CHECK:             %33 = OpImageFetch %v4float %32 %17
-;CHECK:                   OpBranch %29
-;CHECK:             %31 = OpLabel
-;CHECK:             {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_32 %uint_6 %uint_3 %uint_7 %uint_0 %23 %25
-;CHECK:                   OpBranch %29
-;CHECK:             %29 = OpLabel
-;CHECK:             [[phi_result:%\w+]] = OpPhi %v4float %33 %30 [[null_v4float]] %31
-;CHECK:                   OpStore %x [[phi_result]]
-                          OpReturn
-                          OpFunctionEnd
-                          )" + kStreamWrite7Frag;
+%main = OpFunction %void None %3
+%5 = OpLabel
+;CHECK: OpBranch %19
+;CHECK: %19 = OpLabel
+%13 = OpLoad %10 %s
+%17 = OpLoad %int %ii
+%18 = OpImageFetch %v4float %13 %17
+OpStore %x %18
+;CHECK-NOT: %18 = OpImageFetch %v4float %13 %17
+;CHECK-NOT: OpStore %x %18
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_33 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %10 %s
+;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} %17
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %x [[phi_result]]
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, true, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, SamplerBufferOOBFetch) {
@@ -5294,89 +4855,80 @@
 
   // clang-format off
   const std::string text = R"(
-                          OpCapability Shader
-                          OpCapability SampledBuffer
-;CHECK:                   OpCapability ImageQuery
-;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
-                     %1 = OpExtInstImport "GLSL.std.450"
-                          OpMemoryModel Logical GLSL450
-                          OpEntryPoint Fragment %main "main" %x %s %ii
-;CHECK:                   OpEntryPoint Fragment %main "main" %x %s %ii %inst_bindless_output_buffer %gl_FragCoord
-                          OpExecutionMode %main OriginUpperLeft
-                          OpSource GLSL 450
-                          OpName %main "main"
-                          OpName %x "x"
-                          OpName %s "s"
-                          OpName %ii "ii"
-                          OpDecorate %x Location 11
-                          OpDecorate %s DescriptorSet 3
-                          OpDecorate %s Binding 7
-                          OpDecorate %ii Flat
-                          OpDecorate %ii Location 13
-;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
-                  %void = OpTypeVoid
-                     %3 = OpTypeFunction %void
-                 %float = OpTypeFloat 32
-               %v4float = OpTypeVector %float 4
-           %_ptr_Output_v4float = OpTypePointer Output %v4float
-                     %x = OpVariable %_ptr_Output_v4float Output
-                    %10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
-                    %11 = OpTypeSampledImage %10
-           %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
-                     %s = OpVariable %_ptr_UniformConstant_11 UniformConstant
-                   %int = OpTypeInt 32 1
-           %_ptr_Input_int = OpTypePointer Input %int
-                    %ii = OpVariable %_ptr_Input_int Input
-;CHECK:           %uint = OpTypeInt 32 0
-;CHECK:           %bool = OpTypeBool
-;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-;CHECK:    %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
-;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+OpCapability Shader
+OpCapability SampledBuffer
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %x %s %ii
+;CHECK: OpEntryPoint Fragment %main "main" %x %s %ii %gl_FragCoord
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 450
+OpName %main "main"
+OpName %x "x"
+OpName %s "s"
+OpName %ii "ii"
+OpDecorate %x Location 11
+OpDecorate %s DescriptorSet 3
+OpDecorate %s Binding 7
+OpDecorate %ii Flat
+OpDecorate %ii Location 13
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%x = OpVariable %_ptr_Output_v4float Output
+%10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
+%11 = OpTypeSampledImage %10
+%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
+%s = OpVariable %_ptr_UniformConstant_11 UniformConstant
+%int = OpTypeInt 32 1
+%_ptr_Input_int = OpTypePointer Input %int
+%ii = OpVariable %_ptr_Input_int Input
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
 ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
-                  %main = OpFunction %void None %3
-                     %5 = OpLabel
-;CHECK:                   OpBranch %23
-;CHECK:             %23 = OpLabel
-;CHECK:                   OpBranch %22
-;CHECK:             %22 = OpLabel
-;CHECK:                   OpBranch %21
-;CHECK:             %21 = OpLabel
-                    %14 = OpLoad %11 %s
-                    %18 = OpLoad %int %ii
-                    %19 = OpImage %10 %14
-                    %20 = OpImageFetch %v4float %19 %18
-                          OpStore %x %20
-;CHECK-NOT:         %20 = OpImageFetch %v4float %19 %18
-;CHECK-NOT:               OpStore %x %20
-;CHECK:             %25 = OpBitcast %uint %18
-;CHECK:             %27 = OpImageQuerySize %uint %19
-;CHECK:             %29 = OpULessThan %bool %25 %27
-;CHECK:                   OpSelectionMerge %31 None
-;CHECK:                   OpBranchConditional %29 %32 %33
-;CHECK:             %32 = OpLabel
-;CHECK:             %34 = OpLoad %11 %s
-;CHECK:             %35 = OpImage %10 %34
-;CHECK:             %36 = OpImageFetch %v4float %35 %18
-;CHECK:                   OpBranch %31
-;CHECK:             %33 = OpLabel
-;CHECK:             {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_34 %uint_6 %uint_3 %uint_7 %uint_0 %25 %27
-;CHECK:                   OpBranch %31
-;CHECK:             %31 = OpLabel
-;CHECK:             [[phi_result:%\w+]] = OpPhi %v4float %36 %32 [[null_v4float]] %33
-;CHECK:                   OpStore %x [[phi_result]]
-                          OpReturn
-                          OpFunctionEnd
-                          )" + kStreamWrite7Frag;
+)" + kImportStub + R"(
+%main = OpFunction %void None %3
+%5 = OpLabel
+;CHECK: OpBranch %21
+;CHECK: %21 = OpLabel
+%14 = OpLoad %11 %s
+%18 = OpLoad %int %ii
+%19 = OpImage %10 %14
+%20 = OpImageFetch %v4float %19 %18
+OpStore %x %20
+;CHECK-NOT: %20 = OpImageFetch %v4float %19 %18
+;CHECK-NOT: OpStore %x %20
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_35 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %11 %s
+;CHECK: {{%\w+}} = OpImage %10 {{%\w+}}
+;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %x [[phi_result]]
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, true, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) {
@@ -5394,98 +4946,86 @@
 
   // clang-format off
   const std::string text = R"(
-                          OpCapability Shader
-                          OpCapability SampledBuffer
-;CHECK:                   OpCapability ImageQuery
-;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
-                     %1 = OpExtInstImport "GLSL.std.450"
-                          OpMemoryModel Logical GLSL450
-                          OpEntryPoint Fragment %main "main" %x %tBuf %s %ii
-;CHECK:                   OpEntryPoint Fragment %main "main" %x %tBuf %s %ii %inst_bindless_output_buffer %gl_FragCoord
-                          OpExecutionMode %main OriginUpperLeft
-                          OpSource GLSL 450
-                          OpName %main "main"
-                          OpName %x "x"
-                          OpName %tBuf "tBuf"
-                          OpName %s "s"
-                          OpName %ii "ii"
-                          OpDecorate %x Location 11
-                          OpDecorate %tBuf DescriptorSet 3
-                          OpDecorate %tBuf Binding 7
-                          OpDecorate %s DescriptorSet 3
-                          OpDecorate %s Binding 8
-                          OpDecorate %ii Flat
-                          OpDecorate %ii Location 13
-;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
-                  %void = OpTypeVoid
-                     %3 = OpTypeFunction %void
-                 %float = OpTypeFloat 32
-               %v4float = OpTypeVector %float 4
-           %_ptr_Output_v4float = OpTypePointer Output %v4float
-                     %x = OpVariable %_ptr_Output_v4float Output
-                    %10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
-           %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
-                  %tBuf = OpVariable %_ptr_UniformConstant_10 UniformConstant
-                    %14 = OpTypeSampler
-           %_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
-                     %s = OpVariable %_ptr_UniformConstant_14 UniformConstant
-                    %18 = OpTypeSampledImage %10
-                   %int = OpTypeInt 32 1
-           %_ptr_Input_int = OpTypePointer Input %int
-                    %ii = OpVariable %_ptr_Input_int Input
-;CHECK:           %uint = OpTypeInt 32 0
-;CHECK:           %bool = OpTypeBool
-;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-;CHECK:    %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
-;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-;CHECK:            [[null_v4float:%\w+]] = OpConstantNull %v4float
-                  %main = OpFunction %void None %3
-                     %5 = OpLabel
-;CHECK:                   OpBranch %28
-;CHECK:             %28 = OpLabel
-;CHECK:                   OpBranch %27
-;CHECK:             %27 = OpLabel
-;CHECK:                   OpBranch %26
-;CHECK:             %26 = OpLabel
-                    %13 = OpLoad %10 %tBuf
-                    %17 = OpLoad %14 %s
-                    %19 = OpSampledImage %18 %13 %17
-                    %23 = OpLoad %int %ii
-                    %24 = OpImage %10 %19
-                    %25 = OpImageFetch %v4float %24 %23
-                          OpStore %x %25
-;CHECK-NOT:         %25 = OpImageFetch %v4float %24 %23
-;CHECK-NOT:               OpStore %x %25
-;CHECK:             %30 = OpBitcast %uint %23
-;CHECK:             %32 = OpImageQuerySize %uint %24
-;CHECK:             %34 = OpULessThan %bool %30 %32
-;CHECK:                   OpSelectionMerge %36 None
-;CHECK:                   OpBranchConditional %34 %37 %38
-;CHECK:             %37 = OpLabel
-;CHECK:             %39 = OpLoad %10 %tBuf
-;CHECK:             %40 = OpSampledImage %18 %39 %17
-;CHECK:             %41 = OpImage %10 %40
-;CHECK:             %42 = OpImageFetch %v4float %41 %23
-;CHECK:                   OpBranch %36
-;CHECK:             %38 = OpLabel
-;CHECK:            {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_42 %uint_6 %uint_3 %uint_7 %uint_0 %30 %32
-;CHECK:                   OpBranch %36
-;CHECK:             %36 = OpLabel
-;CHECK:            [[phi_result:%\w+]] = OpPhi %v4float %42 %37 [[null_v4float]] %38
-;CHECK:                   OpStore %x [[phi_result]]
-                          OpReturn
-                          OpFunctionEnd
-                          )" + kStreamWrite7Frag;
+OpCapability Shader
+OpCapability SampledBuffer
+;CHECK: OpCapability Linkage
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %x %tBuf %s %ii
+;CHECK: OpEntryPoint Fragment %main "main" %x %tBuf %s %ii %gl_FragCoord
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 450
+OpName %main "main"
+OpName %x "x"
+OpName %tBuf "tBuf"
+OpName %s "s"
+OpName %ii "ii"
+OpDecorate %x Location 11
+OpDecorate %tBuf DescriptorSet 3
+OpDecorate %tBuf Binding 7
+OpDecorate %s DescriptorSet 3
+OpDecorate %s Binding 8
+OpDecorate %ii Flat
+OpDecorate %ii Location 13
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%x = OpVariable %_ptr_Output_v4float Output
+%10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
+%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
+%tBuf = OpVariable %_ptr_UniformConstant_10 UniformConstant
+%14 = OpTypeSampler
+%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
+%s = OpVariable %_ptr_UniformConstant_14 UniformConstant
+%18 = OpTypeSampledImage %10
+%int = OpTypeInt 32 1
+%_ptr_Input_int = OpTypePointer Input %int
+%ii = OpVariable %_ptr_Input_int Input
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
+%main = OpFunction %void None %3
+%5 = OpLabel
+%13 = OpLoad %10 %tBuf
+%17 = OpLoad %14 %s
+%19 = OpSampledImage %18 %13 %17
+%23 = OpLoad %int %ii
+%24 = OpImage %10 %19
+%25 = OpImageFetch %v4float %24 %23
+OpStore %x %25
+;CHECK-NOT: %25 = OpImageFetch %v4float %24 %23
+;CHECK-NOT: OpStore %x %25
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_43 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %10 %tBuf
+;CHECK: {{%\w+}} = OpSampledImage %18 {{%\w+}} %17
+;CHECK: {{%\w+}} = OpImage %10 {{%\w+}}
+;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} %23
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %x [[phi_result]]
+OpReturn
+OpFunctionEnd
+)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true, true, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 TEST_F(InstBindlessTest, DeviceBufferAddressOOB) {
@@ -5509,11 +5049,13 @@
   const std::string text = R"(
 OpCapability Shader
 OpCapability PhysicalStorageBufferAddresses
+;CHECK: OpCapability Linkage
 ;CHECK: OpCapability Int64
+OpExtension "SPV_KHR_physical_storage_buffer"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel PhysicalStorageBuffer64 GLSL450
 OpEntryPoint Vertex %main "main" %u_info
-;CHECK: OpEntryPoint Vertex %main "main" %u_info %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_VertexIndex %gl_InstanceIndex
+;CHECK: OpEntryPoint Vertex %main "main" %u_info %gl_VertexIndex %gl_InstanceIndex
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_buffer_reference"
 OpName %main "main"
@@ -5531,9 +5073,8 @@
 OpMemberDecorate %bufStruct 0 Offset 0
 OpDecorate %bufStruct Block
 OpDecorate %u_info DescriptorSet 0
-OpDecorate %u_info Binding 0)"
-    + kInputDecorations + kOutputDecorations +
-R"(%void = OpTypeVoid
+OpDecorate %u_info Binding 0
+%void = OpTypeVoid
 %3 = OpTypeFunction %void
 %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
@@ -5552,18 +5093,11 @@
 %bool = OpTypeBool
 %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
 %int_n559035791 = OpConstant %int -559035791
-%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int)"
-    + kInputGlobals + kOutputGlobals +
-R"(%main = OpFunction %void None %3
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
+)" + kImportStub + R"(
+%main = OpFunction %void None %3
 %5 = OpLabel
 %i = OpVariable %_ptr_Function_int Function
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
-;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
-;CHECK: OpBranch {{%\w+}}
-;CHECK: {{%\w+}} = OpLabel
 OpStore %i %int_0
 OpBranch %10
 %10 = OpLabel
@@ -5572,37 +5106,41 @@
 %14 = OpLabel
 %15 = OpLoad %int %i
 %26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1
-%27 = OpLoad %int %26
-%29 = OpSLessThan %bool %15 %27
-;CHECK-NOT: %27 = OpLoad %int %26
-;CHECK-NOT: %29 = OpSLessThan %bool %15 %27
 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_3
-;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_56 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
 ;CHECK: OpSelectionMerge {{%\w+}} None
 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: [[load_result:%\w+]] = OpLoad %int %26
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_54 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}}
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: [[phi_result:%\w+]] = OpPhi %int [[load_result]] {{%\w+}} {{%\w+}} {{%\w+}}
-;CHECK: {{%\w+}} = OpSLessThan %bool %15 [[phi_result]]
+%27 = OpLoad %int %26
+%29 = OpSLessThan %bool %15 %27
+;CHECK-NOT: %27 = OpLoad %int %26
+;CHECK-NOT: %29 = OpSLessThan %bool %15 %27
+;CHECK: %29 = OpSLessThan %bool %15 [[phi_result]]
 OpBranchConditional %29 %11 %12
 %11 = OpLabel
 %31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
 %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
 ;CHECK-NOT: %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7
-;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_61 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
 ;CHECK: OpSelectionMerge {{%\w+}} None
 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
 ;CHECK: [[load_result_2:%\w+]] = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
-;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_59 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}}
 ;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct {{%\w+}}
 ;CHECK: OpBranch {{%\w+}}
 ;CHECK: {{%\w+}} = OpLabel
@@ -5620,14 +5158,144 @@
 OpBranch %10
 %12 = OpLabel
 OpReturn
-OpFunctionEnd)"
-    + kReadDescInit + kStreamWrite7Vert;
+OpFunctionEnd)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false, true,
-                                               true, true, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
+}
+
+TEST_F(InstBindlessTest, VertexIndexOOB) {
+  // #version 450
+  // layout(std140, binding = 0) uniform foo { uint tex_index[1]; }
+  // uniform_index_buffer; layout(location = 0) out flat uint index; vec2
+  // vertices[3]; void main() {
+  //     vertices[0] = vec2(-1.0, -1.0);
+  //     vertices[1] = vec2( 1.0, -1.0);
+  //     vertices[2] = vec2( 0.0,  1.0);
+  //     gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);
+  //     index = uniform_index_buffer.tex_index[0];
+  // }
+  // clang-format off
+  const std::string text = R"(
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %vertices %_ %gl_VertexIndex %index %uniform_index_buffer
+OpSource GLSL 450
+OpName %main "main"
+OpName %vertices "vertices"
+OpName %gl_PerVertex "gl_PerVertex"
+OpMemberName %gl_PerVertex 0 "gl_Position"
+OpMemberName %gl_PerVertex 1 "gl_PointSize"
+OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
+OpMemberName %gl_PerVertex 3 "gl_CullDistance"
+OpName %_ ""
+OpName %gl_VertexIndex "gl_VertexIndex"
+OpName %index "index"
+OpName %foo "foo"
+OpMemberName %foo 0 "tex_index"
+OpName %uniform_index_buffer "uniform_index_buffer"
+OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
+OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
+OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
+OpDecorate %gl_PerVertex Block
+OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+OpDecorate %index Flat
+OpDecorate %index Location 0
+OpDecorate %_arr_uint_uint_1 ArrayStride 16
+OpMemberDecorate %foo 0 Offset 0
+OpDecorate %foo Block
+OpDecorate %uniform_index_buffer DescriptorSet 0
+OpDecorate %uniform_index_buffer Binding 0
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v2float = OpTypeVector %float 2
+%uint = OpTypeInt 32 0
+%uint_3 = OpConstant %uint 3
+%_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3
+%_ptr_Private__arr_v2float_uint_3 = OpTypePointer Private %_arr_v2float_uint_3
+%vertices = OpVariable %_ptr_Private__arr_v2float_uint_3 Private
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%float_n1 = OpConstant %float -1
+%16 = OpConstantComposite %v2float %float_n1 %float_n1
+%_ptr_Private_v2float = OpTypePointer Private %v2float
+%int_1 = OpConstant %int 1
+%float_1 = OpConstant %float 1
+%21 = OpConstantComposite %v2float %float_1 %float_n1
+%int_2 = OpConstant %int 2
+%float_0 = OpConstant %float 0
+%25 = OpConstantComposite %v2float %float_0 %float_1
+%v4float = OpTypeVector %float 4
+%uint_1 = OpConstant %uint 1
+%_arr_float_uint_1 = OpTypeArray %float %uint_1
+%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+%_ = OpVariable %_ptr_Output_gl_PerVertex Output
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexIndex = OpVariable %_ptr_Input_int Input
+%int_3 = OpConstant %int 3
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_ptr_Output_uint = OpTypePointer Output %uint
+%index = OpVariable %_ptr_Output_uint Output
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+%foo = OpTypeStruct %_arr_uint_uint_1
+%_ptr_Uniform_foo = OpTypePointer Uniform %foo
+%uniform_index_buffer = OpVariable %_ptr_Uniform_foo Uniform
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+)" + kImportStub + R"(
+%main = OpFunction %void None %3
+%5 = OpLabel
+%18 = OpAccessChain %_ptr_Private_v2float %vertices %int_0
+OpStore %18 %16
+%22 = OpAccessChain %_ptr_Private_v2float %vertices %int_1
+OpStore %22 %21
+%26 = OpAccessChain %_ptr_Private_v2float %vertices %int_2
+OpStore %26 %25
+%35 = OpLoad %int %gl_VertexIndex
+%37 = OpSMod %int %35 %int_3
+%38 = OpAccessChain %_ptr_Private_v2float %vertices %37
+%39 = OpLoad %v2float %38
+%40 = OpCompositeExtract %float %39 0
+%41 = OpCompositeExtract %float %39 1
+%42 = OpCompositeConstruct %v4float %40 %41 %float_0 %float_1
+%44 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+OpStore %44 %42
+%52 = OpAccessChain %_ptr_Uniform_uint %uniform_index_buffer %int_0 %int_0
+%53 = OpLoad %uint %52
+;CHECK-NOT: %53 = OpLoad %uint %52
+;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %int_0
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
+;CHECK: {{%\w+}} = OpLoad %int %gl_VertexIndex
+;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_87 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %uint %52
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpStore %index [[phi_result]]
+OpStore %index %53
+;CHECK-NOT: OpStore %index %53
+OpReturn
+;CHECK: OpReturn
+OpFunctionEnd)";
+  // clang-format on
+
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
+  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
 }
 
 // TODO(greg-lunarg): Add tests to verify handling of these cases:
diff --git a/third_party/SPIRV-Tools/test/opt/inst_buff_addr_check_test.cpp b/third_party/SPIRV-Tools/test/opt/inst_buff_addr_check_test.cpp
index 80e6b7a..72d3438 100644
--- a/third_party/SPIRV-Tools/test/opt/inst_buff_addr_check_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/inst_buff_addr_check_test.cpp
@@ -26,161 +26,14 @@
 namespace opt {
 namespace {
 
-static const std::string kOutputDecorations = R"(
-; CHECK: OpDecorate [[output_buffer_type:%inst_buff_addr_OutputBuffer]] Block
-; CHECK: OpMemberDecorate [[output_buffer_type]] 0 Offset 0
-; CHECK: OpMemberDecorate [[output_buffer_type]] 1 Offset 4
-; CHECK: OpDecorate [[output_buffer_var:%\w+]] DescriptorSet 7
-; CHECK: OpDecorate [[output_buffer_var]] Binding 0
+static const std::string kFuncName = "inst_buff_addr_search_and_test";
+static const std::string kImportDeco = R"(
+;CHECK: OpDecorate %)" + kFuncName + R"( LinkageAttributes ")" +
+                                       kFuncName + R"(" Import
 )";
-
-static const std::string kOutputGlobals = R"(
-; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %uint %_runtimearr_uint
-; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]]
-; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer
-)";
-
-static const std::string kStreamWrite4Begin = R"(
-; CHECK: {{%\w+}} = OpFunction %void None {{%\w+}}
-; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1
-; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_10
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10
-; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2
-; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
-; CHECK: OpSelectionMerge {{%\w+}} None
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_10
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_23
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_1]]
-)";
-
-static const std::string kStreamWrite4End = R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_2]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_3]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_4]]
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpReturn
-; CHECK: OpFunctionEnd
-)";
-
-// clang-format off
-static const std::string kStreamWrite4Frag = kStreamWrite4Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
-; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite4End;
-
-static const std::string kStreamWrite4Compute = kStreamWrite4Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite4End;
-// clang-format on
-
-// clang-format off
-static const std::string kStreamWrite4Vert = kStreamWrite4Begin + R"(
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-)" + kStreamWrite4End;
-// clang-format on
-
-static const std::string kInputDecorations = R"(
-; CHECK: OpDecorate [[input_buffer_type:%inst_buff_addr_InputBuffer]] Block
-; CHECK: OpMemberDecorate [[input_buffer_type]] 0 Offset 0
-; CHECK: OpDecorate [[input_buffer_var:%\w+]] DescriptorSet 7
-; CHECK: OpDecorate [[input_buffer_var]] Binding 2
-)";
-
-static const std::string kInputGlobals = R"(
-; CHECK: [[input_buffer_type]] = OpTypeStruct %_runtimearr_ulong
-; CHECK: [[input_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[input_buffer_type]]
-; CHECK: [[input_buffer_var]] = OpVariable [[input_ptr_type]] StorageBuffer
-)";
-
-static const std::string kSearchAndTest = R"(
-; CHECK: {{%\w+}} = OpFunction %bool None {{%\w+}}
-; CHECK: [[param_1:%\w+]] = OpFunctionParameter %ulong
-; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpPhi %uint %uint_1 {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: OpLoopMerge {{%\w+}} {{%\w+}} None
-; CHECK: OpBranch {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
-; CHECK: {{%\w+}} = OpUGreaterThan %bool {{%\w+}} [[param_1]]
-; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpISub %uint {{%\w+}} %uint_1
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
-; CHECK: {{%\w+}} = OpISub %ulong [[param_1]] {{%\w+}}
-; CHECK: {{%\w+}} = OpUConvert %ulong [[param_2]]
-; CHECK: {{%\w+}} = OpIAdd %ulong {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 %uint_0
-; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
-; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}}
-; CHECK: {{%\w+}} = OpISub %uint {{%\w+}} %uint_1
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
-; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
-; CHECK: OpReturnValue {{%\w+}}
-; CHECK: OpFunctionEnd
+static const std::string kImportStub = R"(
+;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}}
+;CHECK: OpFunctionEnd
 )";
 // clang-format on
 
@@ -209,13 +62,13 @@
   const std::string defs = R"(
 OpCapability Shader
 OpCapability PhysicalStorageBufferAddresses
-; CHECK: OpCapability Int64
+;CHECK: OpCapability Int64
 OpExtension "SPV_EXT_physical_storage_buffer"
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel PhysicalStorageBuffer64 GLSL450
 OpEntryPoint GLCompute %main "main"
-; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
+;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
 OpExecutionMode %main LocalSize 1 1 1
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_buffer_reference"
@@ -240,11 +93,8 @@
 OpDecorate %bufStruct Block
 OpDecorate %u_info DescriptorSet 0
 OpDecorate %u_info Binding 0
-; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8
-)" + kInputDecorations + R"(
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
 )";
 
   const std::string globals = R"(
@@ -265,19 +115,11 @@
 %int_1 = OpConstant %int 1
 %int_3239 = OpConstant %int 3239
 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
-; CHECK: %ulong = OpTypeInt 64 0
-; CHECK: %bool = OpTypeBool
-; CHECK: %28 = OpTypeFunction %bool %ulong %uint
-; CHECK: %_runtimearr_ulong = OpTypeRuntimeArray %ulong
-)" + kInputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong
-; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kOutputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %v3uint = OpTypeVector %uint 3
-; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint
-; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
+;CHECK: %ulong = OpTypeInt 64 0
+;CHECK: %bool = OpTypeBool
+;CHECK: %v3uint = OpTypeVector %uint 3
+;CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint
+;CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
 )";
 // clang-format off
 
@@ -287,36 +129,35 @@
 %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
 %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
 %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
-; CHECK-NOT: %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
-; CHECK-NOT: %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
-; CHECK-NOT: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
-; CHECK: %20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
-; CHECK: %21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20
-; CHECK: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1
-; CHECK: %24 = OpConvertPtrToU %ulong %22
-; CHECK: %61 = OpFunctionCall %bool %inst_buff_addr_search_and_test %24 %uint_4
-; CHECK: OpSelectionMerge %62 None
-; CHECK: OpBranchConditional %61 %63 %64
-; CHECK: %63 = OpLabel
+;CHECK-NOT: %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
+;CHECK-NOT: %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
+;CHECK-NOT: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
+;CHECK: %20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
+;CHECK: %21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20
+;CHECK: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1
+;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %22
+;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} {{%\w+}} %uint_4
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpStore %22 %int_3239 Aligned 16
-; CHECK: OpStore %22 %int_3239 Aligned 16
-; CHECK: OpBranch %62
-; CHECK: %64 = OpLabel
-; CHECK: %65 = OpUConvert %uint %24
-; CHECK: %67 = OpShiftRightLogical %ulong %24 %uint_32
-; CHECK: %68 = OpUConvert %uint %67
-; CHECK: %124 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_48 %uint_2 %65 %68
-; CHECK: OpBranch %62
-; CHECK: %62 = OpLabel
+;CHECK: OpStore %22 %int_3239 Aligned 16
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string output_funcs = kSearchAndTest + kStreamWrite4Compute;
-
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBuffAddrCheckPass>(
-      defs + decorates + globals + main_func + output_funcs, true, 7u, 23u);
+      defs + decorates + globals + kImportStub + main_func, true, 23u);
 }
 
 TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferLoadAndStore) {
@@ -346,7 +187,7 @@
   const std::string defs = R"(
 OpCapability Shader
 OpCapability PhysicalStorageBufferAddresses
-; CHECK: OpCapability Int64
+;CHECK: OpCapability Int64
 OpExtension "SPV_EXT_physical_storage_buffer"
 OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
@@ -356,7 +197,7 @@
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_buffer_reference"
 OpName %main "main"
-; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
+;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
 OpName %blockType "blockType"
 OpMemberName %blockType 0 "x"
 OpMemberName %blockType 1 "next"
@@ -374,13 +215,9 @@
 OpDecorate %rootBlock Block
 OpDecorate %r DescriptorSet 0
 OpDecorate %r Binding 0
-; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8
-)" + kInputDecorations + R"(
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
 )";
-  // clang-format on
 
   const std::string globals = R"(
 %void = OpTypeVoid
@@ -398,7 +235,7 @@
 %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
 %int_531 = OpConstant %int 531
 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
-)" + kInputGlobals + kOutputGlobals;
+)";
 
   const std::string main_func = R"(
 %main = OpFunction %void None %3
@@ -409,48 +246,49 @@
 %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
 %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
 OpStore %26 %int_531 Aligned 16
-; CHECK-NOT: %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
-; CHECK-NOT: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
-; CHECK: %30 = OpConvertPtrToU %ulong %21
-; CHECK: %67 = OpFunctionCall %bool %inst_buff_addr_search_and_test %30 %uint_8
-; CHECK: OpSelectionMerge %68 None
-; CHECK: OpBranchConditional %67 %69 %70
-; CHECK: %69 = OpLabel
-; CHECK: %71 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
-; CHECK: OpBranch %68
-; CHECK: %70 = OpLabel
-; CHECK: %72 = OpUConvert %uint %30
-; CHECK: %74 = OpShiftRightLogical %ulong %30 %uint_32
-; CHECK: %75 = OpUConvert %uint %74
-; CHECK: %131 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_44 %uint_2 %72 %75
-; CHECK: %133 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %132
-; CHECK: OpBranch %68
-; CHECK: %68 = OpLabel
-; CHECK: %134 = OpPhi %_ptr_PhysicalStorageBuffer_blockType %71 %69 %133 %70
-; CHECK: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %134 %int_0
-; CHECK: %135 = OpConvertPtrToU %ulong %26
-; CHECK: %136 = OpFunctionCall %bool %inst_buff_addr_search_and_test %135 %uint_4
-; CHECK: OpSelectionMerge %137 None
-; CHECK: OpBranchConditional %136 %138 %139
-; CHECK: %138 = OpLabel
-; CHECK: OpStore %26 %int_531 Aligned 16
-; CHECK: OpBranch %137
-; CHECK: %139 = OpLabel
-; CHECK: %140 = OpUConvert %uint %135
-; CHECK: %141 = OpShiftRightLogical %ulong %135 %uint_32
-; CHECK: %142 = OpUConvert %uint %141
-; CHECK: %144 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_46 %uint_2 %140 %142
-; CHECK: OpBranch %137
-; CHECK: %137 = OpLabel
+;CHECK-NOT: %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
+;CHECK-NOT: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
+;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %21
+;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_45 {{%\w+}} {{%\w+}} %uint_8
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %52
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %_ptr_PhysicalStorageBuffer_blockType {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int {{%\w+}} %int_0
+;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %26
+;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_47 {{%\w+}} {{%\w+}} %uint_4
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %26 %int_531 Aligned 16
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
-
-  const std::string output_funcs = kSearchAndTest + kStreamWrite4Compute;
+  // clang-format on
 
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBuffAddrCheckPass>(
-      defs + decorates + globals + main_func + output_funcs, true, 7u, 23u);
+      defs + decorates + globals + kImportStub + main_func, true, 23u);
 }
 
 TEST_F(InstBuffAddrTest, StructLoad) {
@@ -477,11 +315,11 @@
 OpCapability Shader
 OpCapability Int64
 OpCapability PhysicalStorageBufferAddresses
-; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
+;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel PhysicalStorageBuffer64 GLSL450
 OpEntryPoint Fragment %main "main"
-; CHECK: OpEntryPoint Fragment %main "main" %inst_buff_addr_input_buffer %inst_buff_addr_output_buffer %gl_FragCoord
+;CHECK: OpEntryPoint Fragment %main "main" %gl_FragCoord
 OpExecutionMode %main OriginUpperLeft
 OpSource GLSL 450
 OpSourceExtension "GL_ARB_gpu_shader_int64"
@@ -500,11 +338,8 @@
 OpMemberDecorate %Test_0 0 Offset 0
 OpMemberDecorate %TestBuffer 0 Offset 0
 OpDecorate %TestBuffer Block
-; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8
-)" + kInputDecorations + R"(
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 )";
 
   const std::string globals = R"(
@@ -521,50 +356,176 @@
 %int_0 = OpConstant %int 0
 %_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0
 %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704
-; CHECK: %47 = OpTypeFunction %bool %ulong %uint
-)" + kInputGlobals + R"(
-; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint
-)" + kOutputGlobals + R"(
-; CHECK: %143 = OpConstantNull %Test_0
+;CHECK: {{%\w+}} = OpConstantNull %Test_0
 )";
-  // clang-format on
 
-  const std::string main_func =
-      R"(
+  const std::string main_func = R"(
 %main = OpFunction %void None %3
 %5 = OpLabel
 %37 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %ulong_18446744073172680704
 %38 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %37 %int_0
 %39 = OpLoad %Test_0 %38 Aligned 16
-; CHECK-NOT: %39 = OpLoad %Test_0 %38 Aligned 16
-; CHECK: %43 = OpConvertPtrToU %ulong %38
-; CHECK: %80 = OpFunctionCall %bool %inst_buff_addr_search_and_test %43 %uint_4
-; CHECK: OpSelectionMerge %81 None
-; CHECK: OpBranchConditional %80 %82 %83
-; CHECK: %82 = OpLabel
-; CHECK: %84 = OpLoad %Test_0 %38 Aligned 16
-; CHECK: OpBranch %81
-; CHECK: %83 = OpLabel
-; CHECK: %85 = OpUConvert %uint %43
-; CHECK: %87 = OpShiftRightLogical %ulong %43 %uint_32
-; CHECK: %88 = OpUConvert %uint %87
-; CHECK: %142 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_37 %uint_2 %85 %88
-; CHECK: OpBranch %81
-; CHECK: %81 = OpLabel
-; CHECK: %144 = OpPhi %Test_0 %84 %82 %143 %83
+;CHECK-NOT: %39 = OpLoad %Test_0 %38 Aligned 16
+;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %38
+;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
+;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_38 {{%\w+}} {{%\w+}} %uint_4
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %Test_0 %38 Aligned 16
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
 %40 = OpCopyLogical %Test %39
-; CHECK-NOT: %40 = OpCopyLogical %Test %39
-; CHECK: %40 = OpCopyLogical %Test %144
+;CHECK-NOT: %40 = OpCopyLogical %Test %39
+;CHECK: %40 = OpCopyLogical %Test [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
+  // clang-format on
 
-  const std::string output_funcs = kSearchAndTest + kStreamWrite4Frag;
-
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBuffAddrCheckPass>(
-      defs + decorates + globals + main_func + output_funcs, true);
+      defs + decorates + globals + kImportStub + main_func, true);
+}
+
+TEST_F(InstBuffAddrTest, PaddedStructLoad) {
+  // #version 450
+  // #extension GL_EXT_buffer_reference : enable
+  // #extension GL_ARB_gpu_shader_int64 : enable
+  // struct Test {
+  //   uvec3 pad_1;  // Offset 0 Size 12
+  //   double pad_2; // Offset 16 Size 8 (alignment requirement)
+  //   float a;      // Offset 24 Size 4
+  // }; // Total Size 28
+  //
+  // layout(buffer_reference, std430, buffer_reference_align = 16) buffer
+  // TestBuffer { Test test; };
+  //
+  // Test GetTest(uint64_t ptr) {
+  //   return TestBuffer(ptr).test;
+  // }
+  //
+  // void main() {
+  //   GetTest(0xe0000000);
+  // }
+
+  const std::string defs =
+      R"(
+OpCapability Shader
+OpCapability Float64
+OpCapability Int64
+OpCapability PhysicalStorageBufferAddresses
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Vertex %main "main"
+OpSource GLSL 450
+OpSourceExtension "GL_ARB_gpu_shader_int64"
+OpSourceExtension "GL_EXT_buffer_reference"
+OpName %main "main"
+OpName %Test "Test"
+OpMemberName %Test 0 "pad_1"
+OpMemberName %Test 1 "pad_2"
+OpMemberName %Test 2 "a"
+OpName %GetTest_u641_ "GetTest(u641;"
+OpName %ptr "ptr"
+OpName %Test_0 "Test"
+OpMemberName %Test_0 0 "pad_1"
+OpMemberName %Test_0 1 "pad_2"
+OpMemberName %Test_0 2 "a"
+OpName %TestBuffer "TestBuffer"
+OpMemberName %TestBuffer 0 "test"
+OpName %param "param"
+)";
+
+  // clang-format off
+  const std::string decorates = R"(
+OpDecorate %TestBuffer Block
+OpMemberDecorate %Test_0 0 Offset 0
+OpMemberDecorate %Test_0 1 Offset 16
+OpMemberDecorate %Test_0 2 Offset 24
+OpMemberDecorate %TestBuffer 0 Offset 0
+)" + kImportDeco + R"(
+;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
+)";
+
+  const std::string globals = R"(
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%ulong = OpTypeInt 64 0
+%_ptr_Function_ulong = OpTypePointer Function %ulong
+%uint = OpTypeInt 32 0
+%v3uint = OpTypeVector %uint 3
+%double = OpTypeFloat 64
+%float = OpTypeFloat 32
+%Test = OpTypeStruct %v3uint %double %float
+%13 = OpTypeFunction %Test %_ptr_Function_ulong
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer
+%Test_0 = OpTypeStruct %v3uint %double %float
+%TestBuffer = OpTypeStruct %Test_0
+%_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0
+%_ptr_Function_Test = OpTypePointer Function %Test
+%ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704
+;CHECK: {{%\w+}} = OpConstantNull %Test_0
+)";
+
+  const std::string main_func = R"(
+%main = OpFunction %void None %3
+%5 = OpLabel
+%param = OpVariable %_ptr_Function_ulong Function
+OpStore %param %ulong_18446744073172680704
+%35 = OpFunctionCall %Test %GetTest_u641_ %param
+OpReturn
+OpFunctionEnd
+%GetTest_u641_ = OpFunction %Test None %13
+%ptr = OpFunctionParameter %_ptr_Function_ulong
+%16 = OpLabel
+%28 = OpVariable %_ptr_Function_Test Function
+%17 = OpLoad %ulong %ptr
+%21 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %17
+%25 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %21 %int_0
+%26 = OpLoad %Test_0 %25 Aligned 16
+%29 = OpCopyLogical %Test %26
+;CHECK-NOT: %30 = OpLoad %Test %28
+;CHECK-NOT: %26 = OpLoad %Test_0 %25 Aligned 16
+;CHECK-NOT: %29 = OpCopyLogical %Test %26
+;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %25
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_63 {{%\w+}} {{%\w+}} %uint_28
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %Test_0 %25 Aligned 16
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: %29 = OpCopyLogical %Test [[phi_result]]
+OpStore %28 %29
+%30 = OpLoad %Test %28
+OpReturnValue %30
+OpFunctionEnd
+)";
+  // clang-format on
+
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
+  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndMatch<InstBuffAddrCheckPass>(
+      defs + decorates + globals + kImportStub + main_func, true);
 }
 
 TEST_F(InstBuffAddrTest, DeviceBufferAddressOOB) {
@@ -591,7 +552,7 @@
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel PhysicalStorageBuffer64 GLSL450
 OpEntryPoint Vertex %main "main" %u_info
-;CHECK: OpEntryPoint Vertex %main "main" %u_info %inst_buff_addr_input_buffer %inst_buff_addr_output_buffer %gl_VertexIndex %gl_InstanceIndex
+;CHECK: OpEntryPoint Vertex %main "main" %u_info %gl_VertexIndex %gl_InstanceIndex
 OpSource GLSL 450
 OpSourceExtension "GL_EXT_buffer_reference"
 OpName %main "main"
@@ -609,7 +570,8 @@
 OpMemberDecorate %bufStruct 0 Offset 0
 OpDecorate %bufStruct Block
 OpDecorate %u_info DescriptorSet 0
-OpDecorate %u_info Binding 0)" + kInputDecorations + kOutputDecorations + R"(
+OpDecorate %u_info Binding 0
+)" + kImportDeco + R"(
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %int = OpTypeInt 32 1
@@ -629,7 +591,8 @@
 %bool = OpTypeBool
 %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
 %int_n559035791 = OpConstant %int -559035791
-%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int)" + kInputGlobals + kOutputGlobals + R"(
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
+)" + kImportStub + R"(
 %main = OpFunction %void None %3
 %5 = OpLabel
 %i = OpVariable %_ptr_Function_int Function
@@ -649,20 +612,20 @@
 %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
 %33 = OpLoad %int %i
 %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33
-;CHECK: %41 = OpConvertPtrToU %ulong %36
-;CHECK: %76 = OpFunctionCall %bool %inst_buff_addr_search_and_test %41 %uint_4
-;CHECK: OpSelectionMerge %77 None
-;CHECK: OpBranchConditional %76 %78 %79
-;CHECK: %78 = OpLabel
 OpStore %36 %int_n559035791 Aligned 16
-;CHECK: OpBranch %77
-;CHECK: 79 = OpLabel
-;CHECK: 80 = OpUConvert %uint %41
-;CHECK: 82 = OpShiftRightLogical %ulong %41 %uint_32
-;CHECK: 83 = OpUConvert %uint %82
-;CHECK: 134 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_62 %uint_2 %80 %83
-;CHECK: OpBranch %77
-;CHECK: 77 = OpLabel
+;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %36
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_63 {{%\w+}} {{%\w+}} %uint_4
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpStore %36 %int_n559035791 Aligned 16
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpBranch %13
 %13 = OpLabel
 %37 = OpLoad %int %i
@@ -671,12 +634,137 @@
 OpBranch %10
 %12 = OpLabel
 OpReturn
-OpFunctionEnd)" + kSearchAndTest + kStreamWrite4Vert;
+OpFunctionEnd)";
   // clang-format on
 
-  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndMatch<InstBuffAddrCheckPass>(text, true, 7, 23);
+  SinglePassRunAndMatch<InstBuffAddrCheckPass>(text, true, 23);
+}
+
+TEST_F(InstBuffAddrTest, UVec3ScalarAddressOOB) {
+  // clang-format off
+  // #version 450
+  //    #extension GL_EXT_buffer_reference : enable
+  //    #extension GL_EXT_scalar_block_layout : enable
+  //    layout(buffer_reference, std430, scalar) readonly buffer IndexBuffer
+  //    {
+  //        uvec3 indices[];
+  //    };
+  //    layout(set = 0, binding = 0) uniform ufoo {
+  //        IndexBuffer data;
+  //        int nReads;
+  //    } u_info;
+  //    void main() {
+  //        uvec3 readvec;
+  //        for (int i=0; i < u_info.nReads; ++i) {
+  //            readvec = u_info.data.indices[i];
+  //        }
+  //    }
+  const std::string text = R"(
+OpCapability Shader
+OpCapability PhysicalStorageBufferAddresses
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Vertex %main "main" %u_info
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_buffer_reference"
+OpSourceExtension "GL_EXT_scalar_block_layout"
+OpName %main "main"
+OpName %i "i"
+OpName %ufoo "ufoo"
+OpMemberName %ufoo 0 "data"
+OpMemberName %ufoo 1 "nReads"
+OpName %IndexBuffer "IndexBuffer"
+OpMemberName %IndexBuffer 0 "indices"
+OpName %u_info "u_info"
+OpName %readvec "readvec"
+OpMemberDecorate %ufoo 0 Offset 0
+OpMemberDecorate %ufoo 1 Offset 8
+OpDecorate %ufoo Block
+OpDecorate %_runtimearr_v3uint ArrayStride 12
+OpMemberDecorate %IndexBuffer 0 NonWritable
+OpMemberDecorate %IndexBuffer 0 Offset 0
+OpDecorate %IndexBuffer Block
+OpDecorate %u_info DescriptorSet 0
+OpDecorate %u_info Binding 0
+)" + kImportDeco + R"(
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+%int_0 = OpConstant %int 0
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_IndexBuffer PhysicalStorageBuffer
+%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_IndexBuffer %int
+%uint = OpTypeInt 32 0
+%v3uint = OpTypeVector %uint 3
+%_runtimearr_v3uint = OpTypeRuntimeArray %v3uint
+%IndexBuffer = OpTypeStruct %_runtimearr_v3uint
+%_ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer PhysicalStorageBuffer %IndexBuffer
+%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
+%u_info = OpVariable %_ptr_Uniform_ufoo Uniform
+%int_1 = OpConstant %int 1
+%_ptr_Uniform_int = OpTypePointer Uniform %int
+%bool = OpTypeBool
+)" + kImportStub + R"(
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+%_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_IndexBuffer
+%_ptr_PhysicalStorageBuffer_v3uint = OpTypePointer PhysicalStorageBuffer %v3uint
+%main = OpFunction %void None %3
+%5 = OpLabel
+%i = OpVariable %_ptr_Function_int Function
+%readvec = OpVariable %_ptr_Function_v3uint Function
+OpStore %i %int_0
+OpBranch %10
+%10 = OpLabel
+OpLoopMerge %12 %13 None
+OpBranch %14
+%14 = OpLabel
+%15 = OpLoad %int %i
+%26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1
+%27 = OpLoad %int %26
+%29 = OpSLessThan %bool %15 %27
+OpBranchConditional %29 %11 %12
+%11 = OpLabel
+%33 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer %u_info %int_0
+%34 = OpLoad %_ptr_PhysicalStorageBuffer_IndexBuffer %33
+%35 = OpLoad %int %i
+%37 = OpAccessChain %_ptr_PhysicalStorageBuffer_v3uint %34 %int_0 %35
+%38 = OpLoad %v3uint %37 Aligned 4
+OpStore %readvec %38
+;CHECK-NOT: %38 = OpLoad %v3uint %37 Aligned 4
+;CHECK-NOT: OpStore %readvec %38
+;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %37
+;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
+;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
+;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
+;CHECK: [[test_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_67 {{%\w+}} {{%\w+}} %uint_12
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional [[test_result]] {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %v3uint %37 Aligned 4
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %v3uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: OpStore %readvec [[phi_result]]
+OpBranch %13
+%13 = OpLabel
+%39 = OpLoad %int %i
+%40 = OpIAdd %int %39 %int_1
+OpStore %i %40
+OpBranch %10
+%12 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+  // clang-format on
+
+  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
+  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  ValidatorOptions()->scalar_block_layout = true;
+  SinglePassRunAndMatch<InstBuffAddrCheckPass>(text, true, 23);
 }
 
 }  // namespace
diff --git a/third_party/SPIRV-Tools/test/opt/inst_debug_printf_test.cpp b/third_party/SPIRV-Tools/test/opt/inst_debug_printf_test.cpp
index 7dd10d8..24c0bc6 100644
--- a/third_party/SPIRV-Tools/test/opt/inst_debug_printf_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/inst_debug_printf_test.cpp
@@ -74,7 +74,7 @@
 ; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %2 "MainPs" %3 %4
-; CHECK: OpEntryPoint Fragment %2 "MainPs" %3 %4 %gl_FragCoord
+; CHECK: OpEntryPoint Fragment %2 "MainPs" %3 %4
 OpExecutionMode %2 OriginUpperLeft
 %5 = OpString "Color is %vn"
 )";
@@ -87,10 +87,7 @@
 OpDecorate %7 Binding 0
 OpDecorate %3 Location 0
 OpDecorate %4 Location 0
-; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kOutputDecorations + R"(
-; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
-)";
+)" + kOutputDecorations;
 
   const std::string globals =
       R"(%void = OpTypeVoid
@@ -110,14 +107,11 @@
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %4 = OpVariable %_ptr_Output_v4float Output
 ; CHECK: %uint = OpTypeInt 32 0
-; CHECK: [[func_type:%\w+]] = OpTypeFunction %void %uint %uint %uint %uint %uint %uint
+; CHECK: [[func_type:%\w+]] = OpTypeFunction %void %uint %uint %uint %uint %uint %uint %uint
 ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
 )" + kOutputGlobals + R"(
 ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
 ; CHECK: %bool = OpTypeBool
-; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
-; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-; CHECK: %v4uint = OpTypeVector %uint 4
 )";
   // clang-format on
 
@@ -131,76 +125,64 @@
 %25 = OpImageSampleImplicitLod %v4float %24 %21
 %26 = OpExtInst %void %1 1 %5 %25
 ; CHECK-NOT: %26 = OpExtInst %void %1 1 %5 %25
-; CHECK: %29 = OpCompositeExtract %float %25 0
-; CHECK: %30 = OpBitcast %uint %29
-; CHECK: %31 = OpCompositeExtract %float %25 1
-; CHECK: %32 = OpBitcast %uint %31
-; CHECK: %33 = OpCompositeExtract %float %25 2
-; CHECK: %34 = OpBitcast %uint %33
-; CHECK: %35 = OpCompositeExtract %float %25 3
-; CHECK: %36 = OpBitcast %uint %35
-; CHECK: %101 = OpFunctionCall %void %inst_printf_stream_write_6 %uint_36 %uint_5 %30 %32 %34 %36
-; CHECK: OpBranch %102
-; CHECK: %102 = OpLabel
+; CHECK: {{%\w+}} = OpCompositeExtract %float %25 0
+; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
+; CHECK: {{%\w+}} = OpCompositeExtract %float %25 1
+; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
+; CHECK: {{%\w+}} = OpCompositeExtract %float %25 2
+; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
+; CHECK: {{%\w+}} = OpCompositeExtract %float %25 3
+; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_printf_stream_write_5 %uint_23 %uint_36 %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 OpStore %4 %25
 OpReturn
 OpFunctionEnd
 )";
 
   const std::string output_func = R"(
-; CHECK: %inst_printf_stream_write_6 = OpFunction %void None [[func_type]]
-; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_6:%\w+]] = OpFunctionParameter %uint
+; CHECK: %inst_printf_stream_write_5 = OpFunction %void None {{%\w+}}
+; CHECK: [[sw_shader_id:%\w+]] = OpFunctionParameter %uint
+; CHECK: [[sw_inst_idx:%\w+]] = OpFunctionParameter %uint
+; CHECK: [[sw_param_1:%\w+]] = OpFunctionParameter %uint
+; CHECK: [[sw_param_2:%\w+]] = OpFunctionParameter %uint
+; CHECK: [[sw_param_3:%\w+]] = OpFunctionParameter %uint
+; CHECK: [[sw_param_4:%\w+]] = OpFunctionParameter %uint
+; CHECK: [[sw_param_5:%\w+]] = OpFunctionParameter %uint
 ; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1
-; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_12
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12
-; CHECK: {{%\w+}} = OpArrayLength %uint %inst_printf_output_buffer 2
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1
+; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_8
+; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
+; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2
 ; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
 ; CHECK: OpSelectionMerge {{%\w+}} None
 ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
 ; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_12
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
+; CHECK: OpStore {{%\w+}} %uint_8
 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_23
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
+; CHECK: OpStore {{%\w+}} [[sw_shader_id]]
 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_1]]
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
+; CHECK: OpStore {{%\w+}} [[sw_inst_idx]]
 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
-; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
+; CHECK: OpStore {{%\w+}} [[sw_param_1]]
 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
-; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
+; CHECK: OpStore {{%\w+}} [[sw_param_2]]
 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
+; CHECK: OpStore {{%\w+}} [[sw_param_3]]
+; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
+; CHECK: OpStore {{%\w+}} [[sw_param_4]]
 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_2]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_3]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_4]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_5]]
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
-; CHECK: OpStore {{%\w+}} [[param_6]]
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
+; CHECK: OpStore {{%\w+}} [[sw_param_5]]
 ; CHECK: OpBranch {{%\w+}}
 ; CHECK: {{%\w+}} = OpLabel
 ; CHECK: OpReturn
diff --git a/third_party/SPIRV-Tools/test/opt/invocation_interlock_placement_test.cpp b/third_party/SPIRV-Tools/test/opt/invocation_interlock_placement_test.cpp
new file mode 100644
index 0000000..2c4ff65
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/opt/invocation_interlock_placement_test.cpp
@@ -0,0 +1,613 @@
+// Copyright (c) 2023 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "spirv-tools/optimizer.hpp"
+#include "test/opt/pass_fixture.h"
+#include "test/opt/pass_utils.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+using InterlockInvocationPlacementTest = PassTest<::testing::Test>;
+
+TEST_F(InterlockInvocationPlacementTest, CheckUnchangedIfNotFragment) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main"
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+          %2 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+	             OpEndInvocationInterlockEXT
+	             OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(
+      Pass::Status::SuccessWithoutChange,
+      std::get<1>(SinglePassRunAndDisassemble<InvocationInterlockPlacementPass>(
+          kTest, /* skip_nop= */ false, /* do_validation= */ false)));
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckUnchangedWithoutCapability) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+          %2 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+	             OpEndInvocationInterlockEXT
+	             OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(
+      Pass::Status::SuccessWithoutChange,
+      std::get<1>(SinglePassRunAndDisassemble<InvocationInterlockPlacementPass>(
+          kTest, /* skip_nop= */ false, /* do_validation= */ false)));
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckSingleBasicBlock) {
+  // We're using OpNoLine as a generic standin for any other instruction, to
+  // test that begin and end aren't moved.
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+; CHECK: OpLabel
+          %2 = OpLabel
+; CHECK-NEXT: OpNoLine
+               OpNoLine
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+	             OpEndInvocationInterlockEXT
+	             OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpNoLine
+               OpNoLine
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpNoLine
+               OpNoLine
+; CHECK-NEXT: OpReturn
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionBegin) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %foo = OpFunction %void None %1
+; CHECK: OpLabel
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+          %2 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+               OpReturn
+; CHECK: OpFunctionEnd
+               OpFunctionEnd
+       %main = OpFunction %void None %1
+; CHECK: OpLabel
+          %3 = OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpFunctionCall
+          %4 = OpFunctionCall %void %foo
+; CHECK-NEXT: OpReturn
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionEnd) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %foo = OpFunction %void None %1
+; CHECK: OpLabel
+; CHECK-NOT: OpEndInvocationInterlockEXT
+          %2 = OpLabel
+               OpEndInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+; CHECK: OpFunctionEnd
+               OpFunctionEnd
+       %main = OpFunction %void None %1
+; CHECK: OpLabel
+          %3 = OpLabel
+; CHECK-NEXT: OpFunctionCall
+          %4 = OpFunctionCall %void %foo
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpReturn
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest,
+       CheckFunctionCallExtractionRepeatedCall) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %foo = OpFunction %void None %1
+; CHECK: OpLabel
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+          %2 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+; CHECK: OpFunctionEnd
+               OpFunctionEnd
+       %main = OpFunction %void None %1
+; CHECK: OpLabel
+          %3 = OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpFunctionCall
+          %4 = OpFunctionCall %void %foo
+; CHECK-NEXT: OpFunctionCall
+          %5 = OpFunctionCall %void %foo
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpReturn
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest,
+       CheckFunctionCallExtractionNestedCall) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %foo = OpFunction %void None %1
+; CHECK: OpLabel
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+          %2 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+; CHECK: OpFunctionEnd
+               OpFunctionEnd
+        %bar = OpFunction %void None %1
+; CHECK: OpLabel
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+          %3 = OpLabel
+          %4 = OpFunctionCall %void %foo
+               OpReturn
+; CHECK: OpFunctionEnd
+               OpFunctionEnd
+       %main = OpFunction %void None %1
+; CHECK: OpLabel
+          %5 = OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpFunctionCall
+          %6 = OpFunctionCall %void %bar
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpReturn
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckLoopExtraction) {
+  // Tests that any begin or end instructions in a loop are moved outside of the
+  // loop.
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+       %void = OpTypeVoid
+       %bool = OpTypeBool
+       %true = OpConstantTrue %bool
+           %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+
+          %2 = OpLabel
+; CHECK: OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+               OpBranch %3
+
+          %3 = OpLabel
+               OpLoopMerge %3 %4 None
+; CHECK: OpBranchConditional
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+               OpBranchConditional %true %4 %5
+
+          %4 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+; CHECK: OpBranch
+               OpBranch %3
+
+; CHECK-NEXT: OpLabel
+          %5 = OpLabel
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckAddBeginToElse) {
+  // Test that if there is a begin in a single branch of a conditional, begin
+  // will be added to the other branch.
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+	             OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+       %bool = OpTypeBool
+       %true = OpConstantTrue %bool
+           %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+
+          %2 = OpLabel
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+               OpSelectionMerge %5 None
+; CHECK: OpBranchConditional
+               OpBranchConditional %true %3 %4
+
+; CHECK-NEXT: OpLabel
+          %3 = OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpBranch
+               OpBranch %5
+
+          %4 = OpLabel
+; CHECK: OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpBranch
+               OpBranch %5
+
+; CHECK-NEXT: OpLabel
+          %5 = OpLabel
+               OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckAddEndToElse) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+	             OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+       %bool = OpTypeBool
+       %true = OpConstantTrue %bool
+           %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+
+          %2 = OpLabel
+; CHECK: OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpSelectionMerge %5 None
+; CHECK: OpBranchConditional
+               OpBranchConditional %true %3 %4
+
+; CHECK-NEXT: OpLabel
+          %3 = OpLabel
+               OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpBranch
+               OpBranch %5
+
+          %4 = OpLabel
+; CHECK: OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpBranch
+               OpBranch %5
+
+; CHECK-NEXT: OpLabel
+          %5 = OpLabel
+; CHECK-NOT: OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseBegin) {
+  // Test that if there is a begin in the then branch of a conditional, and no
+  // else branch, an else branch with a begin will created.
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+	             OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+       %bool = OpTypeBool
+       %true = OpConstantTrue %bool
+           %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+
+          %2 = OpLabel
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+               OpSelectionMerge %5 None
+; CHECK: OpBranchConditional
+               OpBranchConditional %true %3 %5
+
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpBranch
+
+; CHECK-NEXT: OpLabel
+          %3 = OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpBranch %5
+
+; CHECK: OpLabel
+          %5 = OpLabel
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseEnd) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+	             OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+       %bool = OpTypeBool
+       %true = OpConstantTrue %bool
+           %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+
+          %2 = OpLabel
+
+; CHECK: OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]]
+               OpSelectionMerge %5 None
+; CHECK-NEXT: OpBranchConditional %true [[then:%\d+]] [[else:%\d+]]
+               OpBranchConditional %true %3 %5
+
+; CHECK-NEXT: [[else]] = OpLabel
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpBranch [[merge]]
+
+; CHECK-NEXT: [[then]] = OpLabel
+          %3 = OpLabel
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpBranch [[merge]]
+               OpBranch %5
+
+; CHECK-NEXT: [[merge]] = OpLabel
+          %5 = OpLabel
+; CHECK-NEXT: OpReturn
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(InterlockInvocationPlacementTest, CheckSplitSwitch) {
+  // Test that if there is a begin or end in a single branch of a switch, begin
+  // or end will be added to all the other branches.
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderSampleInterlockEXT
+	             OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main SampleInterlockOrderedEXT
+               OpName %main "main"
+       %void = OpTypeVoid
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+           %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+
+; CHECK: OpLabel
+          %2 = OpLabel
+; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]]
+               OpSelectionMerge %8 None
+; CHECK-NEXT: OpSwitch %uint_1 [[default:%\d+]] 0 [[case_0:%\d+]] 1 [[case_1:%\d+]] 2 [[case_2:%\d+]]
+               OpSwitch %uint_1 %8 0 %4 1 %5 2 %8
+
+; CHECK-NEXT: [[case_2]] = OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpBranch [[merge]]
+
+; CHECK-NEXT: [[default]] = OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpBranch [[merge]]
+
+; CHECK-NEXT: [[case_0]] = OpLabel
+          %4 = OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpNoLine
+               OpNoLine
+; CHECK-NEXT: OpBranch [[merge]]
+               OpBranch %8
+
+; CHECK-NEXT: [[case_1]] = OpLabel
+          %5 = OpLabel
+; CHECK-NEXT: OpBeginInvocationInterlockEXT
+; CHECK-NOT: OpEndInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+; CHECK-NEXT: OpNoLine
+               OpNoLine
+; CHECK-NEXT: OpNoLine
+               OpNoLine
+; CHECK-NEXT: OpBranch [[merge]]
+               OpBranch %8
+
+; CHECK-NEXT: [[merge]] = OpLabel
+          %8 = OpLabel
+; CHECK-NOT: OpBeginInvocationInterlockEXT
+               OpBeginInvocationInterlockEXT
+; CHECK-NEXT: OpEndInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
+      kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+}  // namespace
+}  // namespace opt
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/ir_context_test.cpp b/third_party/SPIRV-Tools/test/opt/ir_context_test.cpp
index 1acbefe..621fe8c 100644
--- a/third_party/SPIRV-Tools/test/opt/ir_context_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/ir_context_test.cpp
@@ -1173,6 +1173,254 @@
   }
 }
 
+TEST_F(IRContextTest, ReturnsTrueWhenExtensionIsRemoved) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpExtension "SPV_KHR_shader_clock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+          %1 = OpFunction %void None %6
+          %9 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  std::unique_ptr<IRContext> ctx =
+      BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            1);
+
+  EXPECT_TRUE(ctx->RemoveExtension(kSPV_KHR_shader_clock));
+
+  EXPECT_FALSE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            0);
+}
+
+TEST_F(IRContextTest, ReturnsFalseWhenExtensionIsNotRemoved) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpExtension "SPV_KHR_device_group"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+          %1 = OpFunction %void None %6
+          %9 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  std::unique_ptr<IRContext> ctx =
+      BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            1);
+
+  EXPECT_FALSE(ctx->RemoveExtension(kSPV_KHR_shader_clock));
+
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            1);
+}
+
+TEST_F(IRContextTest, RemovesExtensionIfLast) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpExtension "SPV_KHR_device_group"
+               OpExtension "SPV_KHR_shader_clock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+          %1 = OpFunction %void None %6
+          %9 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  std::unique_ptr<IRContext> ctx =
+      BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group));
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            2);
+
+  EXPECT_TRUE(ctx->RemoveExtension(kSPV_KHR_shader_clock));
+
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group));
+  EXPECT_FALSE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            1);
+}
+
+TEST_F(IRContextTest, RemovesExtensionIfFirst) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpExtension "SPV_KHR_shader_clock"
+               OpExtension "SPV_KHR_device_group"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+          %1 = OpFunction %void None %6
+          %9 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+  std::unique_ptr<IRContext> ctx =
+      BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group));
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            2);
+
+  EXPECT_TRUE(ctx->RemoveExtension(kSPV_KHR_shader_clock));
+
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group));
+  EXPECT_FALSE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            1);
+}
+
+TEST_F(IRContextTest, RemovesMultipleExtensions) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpExtension "SPV_KHR_shader_clock"
+               OpExtension "SPV_KHR_shader_clock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+          %1 = OpFunction %void None %6
+          %9 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  std::unique_ptr<IRContext> ctx =
+      BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            2);
+
+  EXPECT_TRUE(ctx->RemoveExtension(kSPV_KHR_shader_clock));
+
+  EXPECT_FALSE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock));
+  EXPECT_EQ(std::distance(ctx->module()->extension_begin(),
+                          ctx->module()->extension_end()),
+            0);
+}
+
+TEST_F(IRContextTest, ReturnsTrueWhenCapabilityIsRemoved) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability ShaderClockKHR
+               OpExtension "SPV_KHR_shader_clock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+          %1 = OpFunction %void None %6
+          %9 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  std::unique_ptr<IRContext> ctx =
+      BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  EXPECT_TRUE(
+      ctx->get_feature_mgr()->HasCapability(spv::Capability::ShaderClockKHR));
+  EXPECT_EQ(std::distance(ctx->module()->capability_begin(),
+                          ctx->module()->capability_end()),
+            2);
+
+  EXPECT_TRUE(ctx->RemoveCapability(spv::Capability::ShaderClockKHR));
+
+  EXPECT_FALSE(
+      ctx->get_feature_mgr()->HasCapability(spv::Capability::ShaderClockKHR));
+  EXPECT_EQ(std::distance(ctx->module()->capability_begin(),
+                          ctx->module()->capability_end()),
+            1);
+}
+
+TEST_F(IRContextTest, ReturnsFalseWhenCapabilityIsNotRemoved) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability DeviceGroup
+               OpExtension "SPV_KHR_device_group"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+          %1 = OpFunction %void None %6
+          %9 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  std::unique_ptr<IRContext> ctx =
+      BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  EXPECT_TRUE(
+      ctx->get_feature_mgr()->HasCapability(spv::Capability::DeviceGroup));
+  EXPECT_EQ(std::distance(ctx->module()->capability_begin(),
+                          ctx->module()->capability_end()),
+            2);
+
+  EXPECT_FALSE(ctx->RemoveCapability(spv::Capability::ShaderClockKHR));
+
+  EXPECT_TRUE(
+      ctx->get_feature_mgr()->HasCapability(spv::Capability::DeviceGroup));
+  EXPECT_EQ(std::distance(ctx->module()->capability_begin(),
+                          ctx->module()->capability_end()),
+            2);
+}
+
+TEST_F(IRContextTest, RemovesMultipleCapabilities) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability DeviceGroup
+               OpCapability DeviceGroup
+               OpExtension "SPV_KHR_device_group"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+          %1 = OpFunction %void None %6
+          %9 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  std::unique_ptr<IRContext> ctx =
+      BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  EXPECT_TRUE(
+      ctx->get_feature_mgr()->HasCapability(spv::Capability::DeviceGroup));
+  EXPECT_EQ(std::distance(ctx->module()->capability_begin(),
+                          ctx->module()->capability_end()),
+            3);
+
+  EXPECT_TRUE(ctx->RemoveCapability(spv::Capability::DeviceGroup));
+
+  EXPECT_FALSE(
+      ctx->get_feature_mgr()->HasCapability(spv::Capability::DeviceGroup));
+  EXPECT_EQ(std::distance(ctx->module()->capability_begin(),
+                          ctx->module()->capability_end()),
+            1);
+}
+
 INSTANTIATE_TEST_SUITE_P(
     TestCase, TargetEnvCompareTest,
     ::testing::Values(
diff --git a/third_party/SPIRV-Tools/test/opt/modify_maximal_reconvergence_test.cpp b/third_party/SPIRV-Tools/test/opt/modify_maximal_reconvergence_test.cpp
new file mode 100644
index 0000000..bef9237
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/opt/modify_maximal_reconvergence_test.cpp
@@ -0,0 +1,312 @@
+// Copyright (c) 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "assembly_builder.h"
+#include "pass_fixture.h"
+#include "pass_utils.h"
+
+namespace {
+
+using namespace spvtools;
+
+using ModifyMaximalReconvergenceTest = opt::PassTest<::testing::Test>;
+
+TEST_F(ModifyMaximalReconvergenceTest, AddNoEntryPoint) {
+  const std::string text = R"(
+; CHECK-NOT: OpExtension
+OpCapability Kernel
+OpCapability Linkage
+OpMemoryModel Logical OpenCL
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, true);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, AddSingleEntryPoint) {
+  const std::string text = R"(
+; CHECK: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %main MaximallyReconvergesKHR
+
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpName %main "main"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, true);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, AddExtensionExists) {
+  const std::string text = R"(
+; CHECK: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %main MaximallyReconvergesKHR
+
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpName %main "main"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, true);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, AddExecutionModeExists) {
+  const std::string text = R"(
+; CHECK: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %main LocalSize 1 1 1
+; CHECK-NEXT: OpExecutionMode %main MaximallyReconvergesKHR
+; CHECK-NOT: OpExecutionMode %main MaximallyReconvergesKHR
+
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+OpName %main "main"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, true);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, AddTwoEntryPoints) {
+  const std::string text = R"(
+; CHECK: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %comp MaximallyReconvergesKHR
+; CHECK: OpExecutionMode %frag MaximallyReconvergesKHR
+
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %comp "main"
+OpEntryPoint Fragment %frag "main"
+OpExecutionMode %comp LocalSize 1 1 1
+OpExecutionMode %frag OriginUpperLeft
+OpName %comp "comp"
+OpName %frag "frag"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%comp = OpFunction %void None %void_fn
+%entry1 = OpLabel
+OpReturn
+OpFunctionEnd
+%frag = OpFunction %void None %void_fn
+%entry2 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, true);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, AddTwoEntryPointsOneFunc) {
+  const std::string text = R"(
+; CHECK: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %comp MaximallyReconvergesKHR
+; CHECK-NOT: OpExecutionMode %comp MaximallyReconvergesKHR
+
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %comp "main1"
+OpEntryPoint GLCompute %comp "main2"
+OpExecutionMode %comp LocalSize 1 1 1
+OpName %comp "comp"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%comp = OpFunction %void None %void_fn
+%entry1 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, true);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, AddTwoEntryPointsOneExecutionMode) {
+  const std::string text = R"(
+; CHECK: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %comp MaximallyReconvergesKHR
+; CHECK-NOT: OpExecutionMode %comp MaximallyReconvergesKHR
+; CHECK: OpExecutionMode %frag MaximallyReconvergesKHR
+; CHECK-NOT: OpExecutionMode %comp MaximallyReconvergesKHR
+
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %comp "main"
+OpEntryPoint Fragment %frag "main"
+OpExecutionMode %comp LocalSize 1 1 1
+OpExecutionMode %frag OriginUpperLeft
+OpExecutionMode %comp MaximallyReconvergesKHR
+OpName %comp "comp"
+OpName %frag "frag"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%comp = OpFunction %void None %void_fn
+%entry1 = OpLabel
+OpReturn
+OpFunctionEnd
+%frag = OpFunction %void None %void_fn
+%entry2 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, true);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, RemoveNoEntryPoint) {
+  const std::string text = R"(OpCapability Kernel
+OpCapability Linkage
+OpMemoryModel Logical OpenCL
+)";
+
+  SinglePassRunAndCheck<opt::ModifyMaximalReconvergence>(text, text, false,
+                                                         true, false);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, RemoveOnlyExtension) {
+  const std::string text = R"(
+; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %main LocalSize 1 1 1
+
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpName %main "main"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, false);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, RemoveSingleEntryPoint) {
+  const std::string text = R"(
+; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %main LocalSize 1 1 1
+; CHECK-NOT: OpExecutionMode %main MaximallyReconvergesKHR
+
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+OpName %main "main"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, false);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, RemoveTwoEntryPointsOneExecutionMode) {
+  const std::string text = R"(
+; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %comp LocalSize 1 1 1
+; CHECK-NEXT: OpExecutionMode %frag OriginUpperLeft
+; CHECK-NOT: OpExecutionMode %comp MaximallyReconvergesKHR
+
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %comp "main"
+OpEntryPoint Fragment %frag "main"
+OpExecutionMode %comp LocalSize 1 1 1
+OpExecutionMode %comp MaximallyReconvergesKHR
+OpExecutionMode %frag OriginUpperLeft
+OpName %comp "comp"
+OpName %frag "frag"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%comp = OpFunction %void None %void_fn
+%entry1 = OpLabel
+OpReturn
+OpFunctionEnd
+%frag = OpFunction %void None %void_fn
+%entry2 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, false);
+}
+
+TEST_F(ModifyMaximalReconvergenceTest, RemoveTwoEntryPoints) {
+  const std::string text = R"(
+; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence"
+; CHECK: OpExecutionMode %comp LocalSize 1 1 1
+; CHECK-NEXT: OpExecutionMode %frag OriginUpperLeft
+; CHECK-NOT: OpExecutionMode {{%\w}} MaximallyReconvergesKHR
+
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %comp "main"
+OpEntryPoint Fragment %frag "main"
+OpExecutionMode %comp LocalSize 1 1 1
+OpExecutionMode %comp MaximallyReconvergesKHR
+OpExecutionMode %frag OriginUpperLeft
+OpExecutionMode %frag MaximallyReconvergesKHR
+OpName %comp "comp"
+OpName %frag "frag"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%comp = OpFunction %void None %void_fn
+%entry1 = OpLabel
+OpReturn
+OpFunctionEnd
+%frag = OpFunction %void None %void_fn
+%entry2 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::ModifyMaximalReconvergence>(text, true, false);
+}
+
+}  // namespace
diff --git a/third_party/SPIRV-Tools/test/opt/switch_descriptorset_test.cpp b/third_party/SPIRV-Tools/test/opt/switch_descriptorset_test.cpp
new file mode 100644
index 0000000..f26178f
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/opt/switch_descriptorset_test.cpp
@@ -0,0 +1,193 @@
+// Copyright (c) 2023 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Bindless Check Instrumentation Tests.
+// Tests ending with V2 use version 2 record format.
+
+#include <string>
+#include <vector>
+
+#include "test/opt/pass_fixture.h"
+#include "test/opt/pass_utils.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+using SwitchDescriptorSetTest = PassTest<::testing::Test>;
+
+TEST_F(SwitchDescriptorSetTest, Basic) {
+  // #version 450
+  // #extension GL_EXT_buffer_reference : enable
+  //
+  // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct;
+  //
+  // layout(set = 7, binding = 7) uniform ufoo {
+  //     bufStruct data;
+  //     uint offset;
+  // } u_info;
+  //
+  // layout(buffer_reference, std140) buffer bufStruct {
+  //     layout(offset = 0) int a[2];
+  //     layout(offset = 32) int b;
+  // };
+  //
+  // void main() {
+  //     u_info.data.b = 0xca7;
+  // }
+
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability PhysicalStorageBufferAddresses
+OpExtension "SPV_EXT_physical_storage_buffer"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_buffer_reference"
+OpName %main "main"
+OpName %ufoo "ufoo"
+OpMemberName %ufoo 0 "data"
+OpMemberName %ufoo 1 "offset"
+OpName %bufStruct "bufStruct"
+OpMemberName %bufStruct 0 "a"
+OpMemberName %bufStruct 1 "b"
+OpName %u_info "u_info"
+OpMemberDecorate %ufoo 0 Offset 0
+OpMemberDecorate %ufoo 1 Offset 8
+OpDecorate %ufoo Block
+OpDecorate %_arr_int_uint_2 ArrayStride 16
+OpMemberDecorate %bufStruct 0 Offset 0
+OpMemberDecorate %bufStruct 1 Offset 32
+OpDecorate %bufStruct Block
+OpDecorate %u_info DescriptorSet 7
+;CHECK: OpDecorate %u_info DescriptorSet 31
+OpDecorate %u_info Binding 7
+;CHECK: OpDecorate %u_info Binding 7
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
+%uint = OpTypeInt 32 0
+%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint
+%int = OpTypeInt 32 1
+%uint_2 = OpConstant %uint 2
+%_arr_int_uint_2 = OpTypeArray %int %uint_2
+%bufStruct = OpTypeStruct %_arr_int_uint_2 %int
+%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
+%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
+%u_info = OpVariable %_ptr_Uniform_ufoo Uniform
+%int_0 = OpConstant %int 0
+%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
+%int_1 = OpConstant %int 1
+%int_3239 = OpConstant %int 3239
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
+%main = OpFunction %void None %3
+%5 = OpLabel
+%17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
+%18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
+%22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
+OpReturn
+OpFunctionEnd
+)";
+  // clang-format off
+
+  SinglePassRunAndMatch<SwitchDescriptorSetPass>(spirv, true, 7, 31);
+}
+
+
+// Make sure DescriptorSet decorations that don't match the requested number
+// are left unchanged.
+TEST_F(SwitchDescriptorSetTest, Unchanged) {
+  // #version 450
+  // #extension GL_EXT_buffer_reference : enable
+  //
+  // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct;
+  //
+  // layout(set = 11, binding = 7) uniform ufoo {
+  //     bufStruct data;
+  //     uint offset;
+  // } u_info;
+  //
+  // layout(buffer_reference, std140) buffer bufStruct {
+  //     layout(offset = 0) int a[2];
+  //     layout(offset = 32) int b;
+  // };
+  //
+  // void main() {
+  //     u_info.data.b = 0xca7;
+  // }
+
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability PhysicalStorageBufferAddresses
+OpExtension "SPV_EXT_physical_storage_buffer"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_buffer_reference"
+OpName %main "main"
+OpName %ufoo "ufoo"
+OpMemberName %ufoo 0 "data"
+OpMemberName %ufoo 1 "offset"
+OpName %bufStruct "bufStruct"
+OpMemberName %bufStruct 0 "a"
+OpMemberName %bufStruct 1 "b"
+OpName %u_info "u_info"
+OpMemberDecorate %ufoo 0 Offset 0
+OpMemberDecorate %ufoo 1 Offset 8
+OpDecorate %ufoo Block
+OpDecorate %_arr_int_uint_2 ArrayStride 16
+OpMemberDecorate %bufStruct 0 Offset 0
+OpMemberDecorate %bufStruct 1 Offset 32
+OpDecorate %bufStruct Block
+OpDecorate %u_info DescriptorSet 11
+;CHECK: OpDecorate %u_info DescriptorSet 11
+OpDecorate %u_info Binding 7
+;CHECK: OpDecorate %u_info Binding 7
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
+%uint = OpTypeInt 32 0
+%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint
+%int = OpTypeInt 32 1
+%uint_2 = OpConstant %uint 2
+%_arr_int_uint_2 = OpTypeArray %int %uint_2
+%bufStruct = OpTypeStruct %_arr_int_uint_2 %int
+%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
+%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
+%u_info = OpVariable %_ptr_Uniform_ufoo Uniform
+%int_0 = OpConstant %int 0
+%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
+%int_1 = OpConstant %int 1
+%int_3239 = OpConstant %int 3239
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
+%main = OpFunction %void None %3
+%5 = OpLabel
+%17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
+%18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
+%22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
+OpReturn
+OpFunctionEnd
+)";
+  // clang-format off
+
+  SinglePassRunAndMatch<SwitchDescriptorSetPass>(spirv, true, 7, 31);
+}
+
+}  // namespace
+}  // namespace opt
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/trim_capabilities_pass_test.cpp b/third_party/SPIRV-Tools/test/opt/trim_capabilities_pass_test.cpp
new file mode 100644
index 0000000..d74ccdf
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/opt/trim_capabilities_pass_test.cpp
@@ -0,0 +1,2665 @@
+// Copyright (c) 2023 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "spirv-tools/optimizer.hpp"
+#include "test/opt/pass_fixture.h"
+#include "test/opt/pass_utils.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+using TrimCapabilitiesPassTest = PassTest<::testing::Test>;
+
+TEST_F(TrimCapabilitiesPassTest, CheckKnownAliasTransformations) {
+  // Those are expected changes caused by the test process:
+  //  - SPV is assembled. -> capability goes from text to number.
+  //  - SPV is optimized.
+  //  - SPV is disassembled -> capability goes from number to text.
+  //  - CHECK rule compares both text versions.
+  // Because some capabilities share the same number (aliases), the text
+  // compared with the CHECK rules depends on which alias is the first on the
+  // SPIRV-Headers enum. This could change, and we want to easily distinguish
+  // real failure from alias order change. This test is only here to list known
+  // alias transformations. If this test breaks, it's not a bug in the
+  // optimization pass, but just the SPIRV-Headers enum order that has changed.
+  // If that happens, tests needs to be updated to the correct alias is used in
+  // the CHECK rule.
+  const std::string kTest = R"(
+               OpCapability Linkage
+               OpCapability StorageUniform16
+               OpCapability StorageUniformBufferBlock16
+               OpCapability ShaderViewportIndexLayerNV
+               OpCapability FragmentBarycentricNV
+               OpCapability ShadingRateNV
+               OpCapability ShaderNonUniformEXT
+               OpCapability RuntimeDescriptorArrayEXT
+               OpCapability InputAttachmentArrayDynamicIndexingEXT
+               OpCapability UniformTexelBufferArrayDynamicIndexingEXT
+               OpCapability StorageTexelBufferArrayDynamicIndexingEXT
+               OpCapability UniformBufferArrayNonUniformIndexingEXT
+               OpCapability SampledImageArrayNonUniformIndexingEXT
+               OpCapability StorageBufferArrayNonUniformIndexingEXT
+               OpCapability StorageImageArrayNonUniformIndexingEXT
+               OpCapability InputAttachmentArrayNonUniformIndexingEXT
+               OpCapability UniformTexelBufferArrayNonUniformIndexingEXT
+               OpCapability StorageTexelBufferArrayNonUniformIndexingEXT
+               OpCapability VulkanMemoryModelKHR
+               OpCapability VulkanMemoryModelDeviceScopeKHR
+               OpCapability PhysicalStorageBufferAddressesEXT
+               OpCapability DemoteToHelperInvocationEXT
+               OpCapability DotProductInputAllKHR
+               OpCapability DotProductInput4x8BitKHR
+               OpCapability DotProductInput4x8BitPackedKHR
+               OpCapability DotProductKHR
+               OpCapability ComputeDerivativeGroupQuadsNV
+               OpCapability ComputeDerivativeGroupLinearNV
+; CHECK: OpCapability Linkage
+; CHECK-NOT: OpCapability StorageUniform16
+; CHECK-NOT: OpCapability StorageUniformBufferBlock16
+; CHECK-NOT: OpCapability ShaderViewportIndexLayerNV
+; CHECK-NOT: OpCapability FragmentBarycentricNV
+; CHECK-NOT: OpCapability ShadingRateNV
+; CHECK-NOT: OpCapability ShaderNonUniformEXT
+; CHECK-NOT: OpCapability RuntimeDescriptorArrayEXT
+; CHECK-NOT: OpCapability InputAttachmentArrayDynamicIndexingEXT
+; CHECK-NOT: OpCapability UniformTexelBufferArrayDynamicIndexingEXT
+; CHECK-NOT: OpCapability StorageTexelBufferArrayDynamicIndexingEXT
+; CHECK-NOT: OpCapability UniformBufferArrayNonUniformIndexingEXT
+; CHECK-NOT: OpCapability SampledImageArrayNonUniformIndexingEXT
+; CHECK-NOT: OpCapability StorageBufferArrayNonUniformIndexingEXT
+; CHECK-NOT: OpCapability StorageImageArrayNonUniformIndexingEXT
+; CHECK-NOT: OpCapability InputAttachmentArrayNonUniformIndexingEXT
+; CHECK-NOT: OpCapability UniformTexelBufferArrayNonUniformIndexingEXT
+; CHECK-NOT: OpCapability StorageTexelBufferArrayNonUniformIndexingEXT
+; CHECK-NOT: OpCapability VulkanMemoryModelKHR
+; CHECK-NOT: OpCapability VulkanMemoryModelDeviceScopeKHR
+; CHECK-NOT: OpCapability PhysicalStorageBufferAddressesEXT
+; CHECK-NOT: OpCapability DemoteToHelperInvocationEXT
+; CHECK-NOT: OpCapability DotProductInputAllKHR
+; CHECK-NOT: OpCapability DotProductInput4x8BitKHR
+; CHECK-NOT: OpCapability DotProductInput4x8BitPackedKHR
+; CHECK-NOT: OpCapability DotProductKHR
+; CHECK-NOT: OpCapability ComputeDerivativeGroupQuadsNV
+; CHECK-NOT: OpCapability ComputeDerivativeGroupLinearNV
+; CHECK: OpCapability UniformAndStorageBuffer16BitAccess
+; CHECK: OpCapability StorageBuffer16BitAccess
+; CHECK: OpCapability ShaderViewportIndexLayerEXT
+; CHECK: OpCapability FragmentBarycentricKHR
+; CHECK: OpCapability FragmentDensityEXT
+; CHECK: OpCapability ShaderNonUniform
+; CHECK: OpCapability RuntimeDescriptorArray
+; CHECK: OpCapability InputAttachmentArrayDynamicIndexing
+; CHECK: OpCapability UniformTexelBufferArrayDynamicIndexing
+; CHECK: OpCapability StorageTexelBufferArrayDynamicIndexing
+; CHECK: OpCapability UniformBufferArrayNonUniformIndexing
+; CHECK: OpCapability SampledImageArrayNonUniformIndexing
+; CHECK: OpCapability StorageBufferArrayNonUniformIndexing
+; CHECK: OpCapability StorageImageArrayNonUniformIndexing
+; CHECK: OpCapability InputAttachmentArrayNonUniformIndexing
+; CHECK: OpCapability UniformTexelBufferArrayNonUniformIndexing
+; CHECK: OpCapability StorageTexelBufferArrayNonUniformIndexing
+; CHECK: OpCapability VulkanMemoryModel
+; CHECK: OpCapability VulkanMemoryModelDeviceScope
+; CHECK: OpCapability PhysicalStorageBufferAddresses
+; CHECK: OpCapability DemoteToHelperInvocation
+; CHECK: OpCapability DotProductInputAll
+; CHECK: OpCapability DotProductInput4x8Bit
+; CHECK: OpCapability DotProductInput4x8BitPacked
+; CHECK: OpCapability DotProduct
+               OpMemoryModel Logical Vulkan
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result =
+      SinglePassRunAndMatch<EmptyPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, LinkagePreventsChanges) {
+  const std::string kTest = R"(
+               OpCapability Linkage
+               OpCapability ClipDistance
+               OpCapability CullDistance
+               OpCapability DemoteToHelperInvocation
+               OpCapability DeviceGroup
+               OpCapability DrawParameters
+               OpCapability Float16
+               OpCapability Float64
+               OpCapability FragmentBarycentricKHR
+               OpCapability FragmentFullyCoveredEXT
+               OpCapability FragmentShadingRateKHR
+               OpCapability GroupNonUniform
+               OpCapability GroupNonUniformArithmetic
+               OpCapability GroupNonUniformBallot
+               OpCapability GroupNonUniformQuad
+               OpCapability GroupNonUniformShuffle
+               OpCapability Image1D
+               OpCapability ImageBuffer
+               OpCapability ImageGatherExtended
+               OpCapability ImageMSArray
+               OpCapability ImageQuery
+               OpCapability InputAttachment
+               OpCapability InputAttachmentArrayNonUniformIndexing
+               OpCapability Int16
+               OpCapability Int64
+               OpCapability Int64Atomics
+               OpCapability Int64ImageEXT
+               OpCapability MeshShadingNV
+               OpCapability MinLod
+               OpCapability MultiView
+               OpCapability MultiViewport
+               OpCapability PhysicalStorageBufferAddresses
+               OpCapability RayQueryKHR
+               OpCapability RayTracingKHR
+               OpCapability RayTracingNV
+               OpCapability RayTraversalPrimitiveCullingKHR
+               OpCapability RuntimeDescriptorArray
+               OpCapability SampleMaskPostDepthCoverage
+               OpCapability SampleRateShading
+               OpCapability Sampled1D
+               OpCapability SampledBuffer
+               OpCapability SampledImageArrayNonUniformIndexing
+               OpCapability Shader
+               OpCapability ShaderClockKHR
+               OpCapability ShaderLayer
+               OpCapability ShaderNonUniform
+               OpCapability ShaderViewportIndex
+               OpCapability ShaderViewportIndexLayerEXT
+               OpCapability SparseResidency
+               OpCapability StencilExportEXT
+               OpCapability StorageImageArrayNonUniformIndexingEXT
+               OpCapability StorageImageExtendedFormats
+               OpCapability StorageImageReadWithoutFormat
+               OpCapability StorageImageWriteWithoutFormat
+               OpCapability StorageInputOutput16
+               OpCapability StoragePushConstant16
+               OpCapability StorageTexelBufferArrayNonUniformIndexing
+               OpCapability StorageUniform16
+               OpCapability StorageUniformBufferBlock16
+               OpCapability Tessellation
+               OpCapability UniformTexelBufferArrayNonUniformIndexing
+               OpCapability VulkanMemoryModel
+               OpExtension "SPV_EXT_fragment_fully_covered"
+               OpExtension "SPV_EXT_shader_image_int64"
+               OpExtension "SPV_EXT_shader_stencil_export"
+               OpExtension "SPV_EXT_shader_viewport_index_layer"
+               OpExtension "SPV_KHR_fragment_shader_barycentric"
+               OpExtension "SPV_KHR_fragment_shading_rate"
+               OpExtension "SPV_KHR_post_depth_coverage"
+               OpExtension "SPV_KHR_ray_query"
+               OpExtension "SPV_KHR_ray_tracing"
+               OpExtension "SPV_KHR_shader_clock"
+               OpExtension "SPV_NV_mesh_shader"
+               OpExtension "SPV_NV_ray_tracing"
+               OpExtension "SPV_NV_viewport_array2"
+; CHECK: OpCapability Linkage
+; CHECK: OpCapability ClipDistance
+; CHECK: OpCapability CullDistance
+; CHECK: OpCapability DemoteToHelperInvocation
+; CHECK: OpCapability DeviceGroup
+; CHECK: OpCapability DrawParameters
+; CHECK: OpCapability Float16
+; CHECK: OpCapability Float64
+; CHECK: OpCapability FragmentBarycentricKHR
+; CHECK: OpCapability FragmentFullyCoveredEXT
+; CHECK: OpCapability FragmentShadingRateKHR
+; CHECK: OpCapability GroupNonUniform
+; CHECK: OpCapability GroupNonUniformArithmetic
+; CHECK: OpCapability GroupNonUniformBallot
+; CHECK: OpCapability GroupNonUniformQuad
+; CHECK: OpCapability GroupNonUniformShuffle
+; CHECK: OpCapability Image1D
+; CHECK: OpCapability ImageBuffer
+; CHECK: OpCapability ImageGatherExtended
+; CHECK: OpCapability ImageMSArray
+; CHECK: OpCapability ImageQuery
+; CHECK: OpCapability InputAttachment
+; CHECK: OpCapability InputAttachmentArrayNonUniformIndexing
+; CHECK: OpCapability Int16
+; CHECK: OpCapability Int64
+; CHECK: OpCapability Int64Atomics
+; CHECK: OpCapability Int64ImageEXT
+; CHECK: OpCapability MeshShadingNV
+; CHECK: OpCapability MinLod
+; CHECK: OpCapability MultiView
+; CHECK: OpCapability MultiViewport
+; CHECK: OpCapability PhysicalStorageBufferAddresses
+; CHECK: OpCapability RayQueryKHR
+; CHECK: OpCapability RayTracingKHR
+; CHECK: OpCapability RayTracingNV
+; CHECK: OpCapability RayTraversalPrimitiveCullingKHR
+; CHECK: OpCapability RuntimeDescriptorArray
+; CHECK: OpCapability SampleMaskPostDepthCoverage
+; CHECK: OpCapability SampleRateShading
+; CHECK: OpCapability Sampled1D
+; CHECK: OpCapability SampledBuffer
+; CHECK: OpCapability SampledImageArrayNonUniformIndexing
+; CHECK: OpCapability Shader
+; CHECK: OpCapability ShaderClockKHR
+; CHECK: OpCapability ShaderLayer
+; CHECK: OpCapability ShaderNonUniform
+; CHECK: OpCapability ShaderViewportIndex
+; CHECK: OpCapability ShaderViewportIndexLayerEXT
+; CHECK: OpCapability SparseResidency
+; CHECK: OpCapability StencilExportEXT
+; CHECK: OpCapability StorageImageArrayNonUniformIndexing
+; CHECK: OpCapability StorageImageExtendedFormats
+; CHECK: OpCapability StorageImageReadWithoutFormat
+; CHECK: OpCapability StorageImageWriteWithoutFormat
+; CHECK: OpCapability StorageInputOutput16
+; CHECK: OpCapability StoragePushConstant16
+; CHECK: OpCapability StorageTexelBufferArrayNonUniformIndexing
+; CHECK: OpCapability Tessellation
+; CHECK: OpCapability UniformTexelBufferArrayNonUniformIndex
+; CHECK: OpCapability VulkanMemoryModel
+; CHECK: OpExtension "SPV_EXT_fragment_fully_covered"
+; CHECK: OpExtension "SPV_EXT_shader_image_int64"
+; CHECK: OpExtension "SPV_EXT_shader_stencil_export"
+; CHECK: OpExtension "SPV_EXT_shader_viewport_index_layer"
+; CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
+; CHECK: OpExtension "SPV_KHR_fragment_shading_rate"
+; CHECK: OpExtension "SPV_KHR_post_depth_coverage"
+; CHECK: OpExtension "SPV_KHR_ray_query"
+; CHECK: OpExtension "SPV_KHR_ray_tracing"
+; CHECK: OpExtension "SPV_KHR_shader_clock"
+; CHECK: OpExtension "SPV_NV_mesh_shader"
+; CHECK: OpExtension "SPV_NV_ray_tracing"
+; CHECK: OpExtension "SPV_NV_viewport_array2"
+               OpMemoryModel Logical Vulkan
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_3);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, KeepShader) {
+  const std::string kTest = R"(
+               OpCapability Shader
+; CHECK: OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, KeepShaderClockWhenInUse) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability Int64
+               OpCapability ShaderClockKHR
+               OpExtension "SPV_KHR_shader_clock"
+; CHECK: OpCapability ShaderClockKHR
+; CHECK: OpExtension "SPV_KHR_shader_clock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+       %uint = OpTypeInt 32 0
+      %ulong = OpTypeInt 64 0
+      %scope = OpConstant %uint 1
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+          %7 = OpReadClockKHR %ulong %scope
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, TrimShaderClockWhenUnused) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability Int64
+               OpCapability ShaderClockKHR
+               OpExtension "SPV_KHR_shader_clock"
+; CHECK-NOT: OpCapability ShaderClockKHR
+; CHECK-NOT: OpExtension "SPV_KHR_shader_clock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, AMDShaderBallotExtensionRemains) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability Groups
+               OpExtension "SPV_AMD_shader_ballot"
+; CHECK: OpCapability Groups
+; CHECK: OpExtension "SPV_AMD_shader_ballot"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+       %uint = OpTypeInt 32 0
+          %1 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+          %2 = OpFunction %void None %1
+          %3 = OpLabel
+          %4 = OpGroupIAddNonUniformAMD %uint %uint_0 ExclusiveScan %uint_0
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, AMDShaderBallotExtensionRemoved) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability Groups
+               OpExtension "SPV_AMD_shader_ballot"
+; CHECK-NOT: OpCapability Groups
+; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+          %2 = OpFunction %void None %1
+          %3 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, MinLod_RemovedIfNotUsed) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Sampled1D
+                      OpCapability MinLod
+; CHECK-NOT:          OpCapability MinLod
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %1 "main"
+              %void = OpTypeVoid
+             %float = OpTypeFloat 32
+           %v3float = OpTypeVector %float 3
+           %v4float = OpTypeVector %float 4
+        %type_image = OpTypeImage %float Cube 2 0 0 1 Rgba32f
+    %ptr_type_image = OpTypePointer UniformConstant %type_image
+      %type_sampler = OpTypeSampler
+  %ptr_type_sampler = OpTypePointer UniformConstant %type_sampler
+           %float_0 = OpConstant %float 0
+         %float_000 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+             %image = OpVariable %ptr_type_image UniformConstant
+           %sampler = OpVariable %ptr_type_sampler UniformConstant
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                %21 = OpLoad %type_image %image
+                %22 = OpLoad %type_sampler %sampler
+                %24 = OpSampledImage %type_sampled_image %21 %22
+                %25 = OpImageSampleImplicitLod %v4float %24 %float_000
+                      OpReturn
+                      OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, MinLod_RemainsWithOpImageSampleImplicitLod) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Sampled1D
+                      OpCapability MinLod
+; CHECK:              OpCapability MinLod
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %1 "main"
+              %void = OpTypeVoid
+             %float = OpTypeFloat 32
+           %v3float = OpTypeVector %float 3
+           %v4float = OpTypeVector %float 4
+        %type_image = OpTypeImage %float Cube 2 0 0 1 Rgba32f
+    %ptr_type_image = OpTypePointer UniformConstant %type_image
+      %type_sampler = OpTypeSampler
+  %ptr_type_sampler = OpTypePointer UniformConstant %type_sampler
+           %float_0 = OpConstant %float 0
+         %float_000 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+             %image = OpVariable %ptr_type_image UniformConstant
+           %sampler = OpVariable %ptr_type_sampler UniformConstant
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                %21 = OpLoad %type_image %image
+                %22 = OpLoad %type_sampler %sampler
+                %24 = OpSampledImage %type_sampled_image %21 %22
+                %25 = OpImageSampleImplicitLod %v4float %24 %float_000 MinLod %float_0
+                      OpReturn
+                      OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       MinLod_RemainsWithOpImageSparseSampleImplicitLod) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability SparseResidency
+                      OpCapability ImageGatherExtended
+                      OpCapability MinLod
+; CHECK:              OpCapability MinLod
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint Fragment %2 "main"
+                      OpExecutionMode %2 OriginUpperLeft
+              %void = OpTypeVoid
+              %uint = OpTypeInt 32 0
+             %float = OpTypeFloat 32
+           %v2float = OpTypeVector %float 2
+           %v3float = OpTypeVector %float 3
+           %v4float = OpTypeVector %float 4
+        %type_image = OpTypeImage %float 2D 2 0 0 1 Unknown
+    %ptr_type_image = OpTypePointer UniformConstant %type_image
+      %type_sampler = OpTypeSampler
+  %ptr_type_sampler = OpTypePointer UniformConstant %type_sampler
+%type_sampled_image = OpTypeSampledImage %type_image
+     %sparse_struct = OpTypeStruct %uint %v4float
+           %float_0 = OpConstant %float 0
+          %float_00 = OpConstantComposite %v2float %float_0 %float_0
+         %float_000 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+             %image = OpVariable %ptr_type_image UniformConstant
+           %sampler = OpVariable %ptr_type_sampler UniformConstant
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                %21 = OpLoad %type_image %image
+                %22 = OpLoad %type_sampler %sampler
+                %24 = OpSampledImage %type_sampled_image %21 %22
+                %25 = OpImageSparseSampleImplicitLod %sparse_struct %24 %float_00 MinLod %float_0
+                      OpReturn
+                      OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, MinLod_DetectsMinLodWithBitmaskImageOperand) {
+  const std::string kTest = R"(
+                            OpCapability MinLod
+; CHECK:                    OpCapability MinLod
+                            OpCapability Shader
+                            OpCapability SparseResidency
+                            OpCapability ImageGatherExtended
+                            OpMemoryModel Logical GLSL450
+                            OpEntryPoint Fragment %1 "main"
+                            OpExecutionMode %1 OriginUpperLeft
+            %type_sampler = OpTypeSampler
+                     %int = OpTypeInt 32 1
+                   %float = OpTypeFloat 32
+                   %v2int = OpTypeVector %int 2
+                 %v2float = OpTypeVector %float 2
+                 %v4float = OpTypeVector %float 4
+             %ptr_sampler = OpTypePointer UniformConstant %type_sampler
+              %type_image = OpTypeImage %float 2D 2 0 0 1 Unknown
+               %ptr_image = OpTypePointer UniformConstant %type_image
+                    %void = OpTypeVoid
+                    %uint = OpTypeInt 32 0
+      %type_sampled_image = OpTypeSampledImage %type_image
+             %type_struct = OpTypeStruct %uint %v4float
+
+                   %int_1 = OpConstant %int 1
+                 %float_0 = OpConstant %float 0
+                 %float_1 = OpConstant %float 1
+                       %8 = OpConstantComposite %v2float %float_0 %float_0
+                      %12 = OpConstantComposite %v2int %int_1 %int_1
+
+                       %2 = OpVariable %ptr_sampler UniformConstant
+                       %3 = OpVariable %ptr_image UniformConstant
+                      %27 = OpTypeFunction %void
+                       %1 = OpFunction %void None %27
+                      %28 = OpLabel
+                      %29 = OpLoad %type_image %3
+                      %30 = OpLoad %type_sampler %2
+                      %31 = OpSampledImage %type_sampled_image %29 %30
+                      %32 = OpImageSparseSampleImplicitLod %type_struct %31 %8 ConstOffset|MinLod %12 %float_0
+                            OpReturn
+                            OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointer_Vulkan1_0) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+               %ptr = OpTypePointer Input %half
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointer_Vulkan1_1) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+               %ptr = OpTypePointer Input %half
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerArray_Vulkan1_0) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+              %uint = OpTypeInt 32 0
+            %uint_1 = OpConstant %uint 1
+             %array = OpTypeArray %half %uint_1
+               %ptr = OpTypePointer Input %array
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerArray_Vulkan1_1) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+              %uint = OpTypeInt 32 0
+            %uint_1 = OpConstant %uint 1
+             %array = OpTypeArray %half %uint_1
+               %ptr = OpTypePointer Input %array
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerStruct_Vulkan1_0) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+               %ptr = OpTypePointer Input %struct
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerStruct_Vulkan1_1) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+               %ptr = OpTypePointer Input %struct
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerStructOfStruct_Vulkan1_0) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+             %float = OpTypeFloat 32
+            %struct = OpTypeStruct %float %half
+            %parent = OpTypeStruct %float %struct
+               %ptr = OpTypePointer Input %parent
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerStructOfStruct_Vulkan1_1) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+             %float = OpTypeFloat 32
+            %struct = OpTypeStruct %float %half
+            %parent = OpTypeStruct %float %struct
+               %ptr = OpTypePointer Input %parent
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerArrayOfStruct_Vulkan1_0) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+              %uint = OpTypeInt 32 0
+            %uint_1 = OpConstant %uint 1
+             %array = OpTypeArray %struct %uint_1
+               %ptr = OpTypePointer Input %array
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerArrayOfStruct_Vulkan1_1) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+              %uint = OpTypeInt 32 0
+            %uint_1 = OpConstant %uint 1
+             %array = OpTypeArray %struct %uint_1
+               %ptr = OpTypePointer Input %array
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerVector_Vulkan1_0) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %vector = OpTypeVector %half 4
+               %ptr = OpTypePointer Input %vector
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerVector_Vulkan1_1) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %vector = OpTypeVector %half 4
+               %ptr = OpTypePointer Input %vector
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerMatrix_Vulkan1_0) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %vector = OpTypeVector %half 4
+            %matrix = OpTypeMatrix %vector 4
+               %ptr = OpTypePointer Input %matrix
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithInputPointerMatrix_Vulkan1_1) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %vector = OpTypeVector %half 4
+            %matrix = OpTypeMatrix %vector 4
+               %ptr = OpTypePointer Input %matrix
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_IsRemovedWithoutInputPointer) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK-NOT:          OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithOutputPointer_Vulkan1_0) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+               %ptr = OpTypePointer Output %half
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemainsWithOutputPointer_Vulkan1_1) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+               %ptr = OpTypePointer Output %half
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageInputOutput16_RemovedWithoutOutputPointer) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageInputOutput16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK-NOT:          OpCapability StorageInputOutput16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StoragePushConstant16_RemainsSimplePointer_Vulkan1_0) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StoragePushConstant16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StoragePushConstant16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+               %ptr = OpTypePointer PushConstant %half
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StoragePushConstant16_RemainsSimplePointer_Vulkan1_1) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StoragePushConstant16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK:              OpCapability StoragePushConstant16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+               %ptr = OpTypePointer PushConstant %half
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, StoragePushConstant16_RemovedSimplePointer) {
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StoragePushConstant16
+                      OpExtension "SPV_KHR_16bit_storage"
+; CHECK-NOT:          OpCapability StoragePushConstant16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+               %ptr = OpTypePointer Function %half
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageUniformBufferBlock16_RemainsSimplePointer_Vulkan1_0) {
+  // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354
+  static_assert(spv::Capability::StorageUniformBufferBlock16 ==
+                spv::Capability::StorageBuffer16BitAccess);
+
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageBuffer16BitAccess
+                      OpExtension "SPV_KHR_16bit_storage"
+
+; CHECK:              OpCapability StorageBuffer16BitAccess
+;                                   `-> StorageUniformBufferBlock16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+                      OpDecorate %struct BufferBlock
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+               %ptr = OpTypePointer Uniform %struct
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageUniformBufferBlock16_RemainsSimplePointer_Vulkan1_1) {
+  // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354
+  static_assert(spv::Capability::StorageUniformBufferBlock16 ==
+                spv::Capability::StorageBuffer16BitAccess);
+
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageBuffer16BitAccess
+                      OpExtension "SPV_KHR_16bit_storage"
+
+; CHECK:              OpCapability StorageBuffer16BitAccess
+;                                   `-> StorageUniformBufferBlock16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+                      OpDecorate %struct BufferBlock
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+               %ptr = OpTypePointer Uniform %struct
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageUniformBufferBlock16_RemovedSimplePointer) {
+  // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354
+  static_assert(spv::Capability::StorageUniformBufferBlock16 ==
+                spv::Capability::StorageBuffer16BitAccess);
+
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageBuffer16BitAccess
+                      OpExtension "SPV_KHR_16bit_storage"
+
+; CHECK-NOT:          OpCapability StorageBuffer16BitAccess
+;                                   `-> StorageUniformBufferBlock16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+               %ptr = OpTypePointer Function %struct
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageUniform16_RemovedWithBufferBlockPointer_Vulkan1_0) {
+  // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354
+  static_assert(spv::Capability::StorageUniformBufferBlock16 ==
+                spv::Capability::StorageBuffer16BitAccess);
+  static_assert(spv::Capability::StorageUniform16 ==
+                spv::Capability::UniformAndStorageBuffer16BitAccess);
+
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageBuffer16BitAccess
+                      OpCapability UniformAndStorageBuffer16BitAccess
+                      OpExtension "SPV_KHR_16bit_storage"
+
+; CHECK:              OpCapability StorageBuffer16BitAccess
+;                                   `-> StorageUniformBufferBlock16
+; CHECK-NOT:          OpCapability UniformAndStorageBuffer16BitAccess
+;                                   `-> StorageUniform16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+                      OpDecorate %struct BufferBlock
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+               %ptr = OpTypePointer Uniform %struct
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageUniform16_RemovedWithBufferBlockPointer_Vulkan1_1) {
+  // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354
+  static_assert(spv::Capability::StorageUniformBufferBlock16 ==
+                spv::Capability::StorageBuffer16BitAccess);
+  static_assert(spv::Capability::StorageUniform16 ==
+                spv::Capability::UniformAndStorageBuffer16BitAccess);
+
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageBuffer16BitAccess
+                      OpCapability UniformAndStorageBuffer16BitAccess
+                      OpExtension "SPV_KHR_16bit_storage"
+
+; CHECK:              OpCapability StorageBuffer16BitAccess
+;                                   `-> StorageUniformBufferBlock16
+; CHECK-NOT:          OpCapability UniformAndStorageBuffer16BitAccess
+;                                   `-> StorageUniform16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+                      OpDecorate %struct BufferBlock
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+               %ptr = OpTypePointer Uniform %struct
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageUniform16_RemovedWithNonBlockUniformPointer_Vulkan1_0) {
+  // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354
+  static_assert(spv::Capability::StorageUniformBufferBlock16 ==
+                spv::Capability::StorageBuffer16BitAccess);
+  static_assert(spv::Capability::StorageUniform16 ==
+                spv::Capability::UniformAndStorageBuffer16BitAccess);
+
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageBuffer16BitAccess
+                      OpCapability UniformAndStorageBuffer16BitAccess
+                      OpExtension "SPV_KHR_16bit_storage"
+
+; CHECK-NOT:          OpCapability StorageBuffer16BitAccess
+;                                   `-> StorageUniformBufferBlock16
+; CHECK:              OpCapability UniformAndStorageBuffer16BitAccess
+;                                   `-> StorageUniform16
+; CHECK:              OpExtension "SPV_KHR_16bit_storage"
+
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+               %ptr = OpTypePointer Uniform %struct
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_0);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageUniform16_RemovedWithNonBlockUniformPointer_Vulkan1_1) {
+  // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354
+  static_assert(spv::Capability::StorageUniformBufferBlock16 ==
+                spv::Capability::StorageBuffer16BitAccess);
+  static_assert(spv::Capability::StorageUniform16 ==
+                spv::Capability::UniformAndStorageBuffer16BitAccess);
+
+  const std::string kTest = R"(
+                      OpCapability Shader
+                      OpCapability Float16
+                      OpCapability StorageBuffer16BitAccess
+                      OpCapability UniformAndStorageBuffer16BitAccess
+                      OpExtension "SPV_KHR_16bit_storage"
+
+; CHECK-NOT:          OpCapability StorageBuffer16BitAccess
+;                                   `-> StorageUniformBufferBlock16
+; CHECK:              OpCapability UniformAndStorageBuffer16BitAccess
+;                                   `-> StorageUniform16
+; CHECK-NOT:          OpExtension "SPV_KHR_16bit_storage"
+
+                      OpMemoryModel Logical GLSL450
+                      OpEntryPoint GLCompute %2 "main"
+              %void = OpTypeVoid
+              %half = OpTypeFloat 16
+            %struct = OpTypeStruct %half
+               %ptr = OpTypePointer Uniform %struct
+                 %1 = OpTypeFunction %void
+                 %2 = OpFunction %void None %1
+                 %3 = OpLabel
+                      OpReturn
+                      OpFunctionEnd
+  )";
+  SetTargetEnv(SPV_ENV_VULKAN_1_1);
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, FragmentShaderInterlock_RemovedIfNotUsed) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderPixelInterlockEXT
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpCapability FragmentShaderShadingRateInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+; CHECK-NOT:   OpCapability FragmentShaderPixelInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderSampleInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderShadingRateInterlockEXT
+; CHECK-NOT:   OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+          %2 = OpFunction %void None %1
+          %3 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       FragmentShaderPixelInterlock_RemainsWhenOrderedIsUsed) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderPixelInterlockEXT
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpCapability FragmentShaderShadingRateInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+; CHECK:       OpCapability FragmentShaderPixelInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderSampleInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderShadingRateInterlockEXT
+; CHECK:       OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %main PixelInterlockOrderedEXT
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+          %2 = OpFunction %void None %1
+          %3 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       FragmentShaderPixelInterlock_RemainsWhenUnorderedIsUsed) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderPixelInterlockEXT
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpCapability FragmentShaderShadingRateInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+; CHECK:       OpCapability FragmentShaderPixelInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderSampleInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderShadingRateInterlockEXT
+; CHECK:       OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %main PixelInterlockUnorderedEXT
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+          %2 = OpFunction %void None %1
+          %3 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       FragmentShaderSampleInterlock_RemainsWhenOrderedIsUsed) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderPixelInterlockEXT
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpCapability FragmentShaderShadingRateInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+; CHECK-NOT:   OpCapability FragmentShaderPixelInterlockEXT
+; CHECK:       OpCapability FragmentShaderSampleInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderShadingRateInterlockEXT
+; CHECK:       OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %main SampleInterlockOrderedEXT
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+          %2 = OpFunction %void None %1
+          %3 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       FragmentShaderSampleInterlock_RemainsWhenUnorderedIsUsed) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderPixelInterlockEXT
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpCapability FragmentShaderShadingRateInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+; CHECK-NOT:   OpCapability FragmentShaderPixelInterlockEXT
+; CHECK:       OpCapability FragmentShaderSampleInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderShadingRateInterlockEXT
+; CHECK:       OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %main SampleInterlockUnorderedEXT
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+          %2 = OpFunction %void None %1
+          %3 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       FragmentShaderShadingRateInterlock_RemainsWhenOrderedIsUsed) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderPixelInterlockEXT
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpCapability FragmentShaderShadingRateInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+; CHECK-NOT:   OpCapability FragmentShaderPixelInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderSampleInterlockEXT
+; CHECK:       OpCapability FragmentShaderShadingRateInterlockEXT
+; CHECK:       OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %main ShadingRateInterlockOrderedEXT
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+          %2 = OpFunction %void None %1
+          %3 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       FragmentShaderShadingRateInterlock_RemainsWhenUnorderedIsUsed) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability FragmentShaderPixelInterlockEXT
+               OpCapability FragmentShaderSampleInterlockEXT
+               OpCapability FragmentShaderShadingRateInterlockEXT
+               OpExtension "SPV_EXT_fragment_shader_interlock"
+; CHECK-NOT:   OpCapability FragmentShaderPixelInterlockEXT
+; CHECK-NOT:   OpCapability FragmentShaderSampleInterlockEXT
+; CHECK:       OpCapability FragmentShaderShadingRateInterlockEXT
+; CHECK:       OpExtension "SPV_EXT_fragment_shader_interlock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %main ShadingRateInterlockUnorderedEXT
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+          %2 = OpFunction %void None %1
+          %3 = OpLabel
+               OpBeginInvocationInterlockEXT
+               OpEndInvocationInterlockEXT
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, Int64_RemovedWhenUnused) {
+  const std::string kTest = R"(
+               OpCapability Int64
+; CHECK-NOT:   OpCapability Int64
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, Int64_RemainsWhenUsed) {
+  const std::string kTest = R"(
+               OpCapability Int64
+; CHECK:       OpCapability Int64
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+        %int = OpTypeInt 64 0
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, RayQueryKHR_RemovedWhenUnused) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpExtension "SPV_KHR_ray_query"
+; CHECK-NOT:   OpCapability RayQueryKHR
+; CHECK-NOT:   OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %out_var_TEXCOORD1
+               OpSource HLSL 660
+               OpName %out_var_TEXCOORD1 "out.var.TEXCOORD1"
+               OpName %main "main"
+               OpDecorate %out_var_TEXCOORD1 Flat
+               OpDecorate %out_var_TEXCOORD1 Location 0
+       %uint = OpTypeInt 32 0
+  %uint_1234 = OpConstant %uint 1234
+%_ptr_Output_uint = OpTypePointer Output %uint
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+%out_var_TEXCOORD1 = OpVariable %_ptr_Output_uint Output
+       %main = OpFunction %void None %7
+          %8 = OpLabel
+               OpStore %out_var_TEXCOORD1 %uint_1234
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       RayQueryKHR_RemainsWhenAccelerationStructureIsPresent) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpExtension "SPV_KHR_ray_query"
+; CHECK:       OpCapability RayQueryKHR
+; CHECK:       OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 2 4
+               OpDecorate %var_bvh DescriptorSet 0
+               OpDecorate %var_bvh Binding 0
+        %bvh = OpTypeAccelerationStructureKHR
+    %ptr_bvh = OpTypePointer UniformConstant %bvh
+       %void = OpTypeVoid
+         %20 = OpTypeFunction %void
+    %var_bvh = OpVariable %ptr_bvh UniformConstant
+       %main = OpFunction %void None %20
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, RayQueryKHR_RemainsWhenRayQueryTypeIsPresent) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpExtension "SPV_KHR_ray_query"
+; CHECK:       OpCapability RayQueryKHR
+; CHECK:       OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 2 4
+      %query = OpTypeRayQueryKHR
+       %void = OpTypeVoid
+         %20 = OpTypeFunction %void
+  %ptr_query = OpTypePointer Function %query
+       %main = OpFunction %void None %20
+         %30 = OpLabel
+  %var_query = OpVariable %ptr_query Function
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, RayQueryKHR_RemainsWhenUsed) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpExtension "SPV_KHR_ray_query"
+; CHECK:       OpCapability RayQueryKHR
+; CHECK:       OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 2 4
+               OpDecorate %bvh DescriptorSet 0
+               OpDecorate %bvh Binding 0
+               OpDecorate %output DescriptorSet 0
+               OpDecorate %output Binding 1
+               OpDecorate %_runtimearr_float ArrayStride 4
+               OpMemberDecorate %type_RWStructuredBuffer_float 0 Offset 0
+               OpDecorate %type_RWStructuredBuffer_float BufferBlock
+      %float = OpTypeFloat 32
+    %float_0 = OpConstant %float 0
+        %int = OpTypeInt 32 1
+    %v3float = OpTypeVector %float 3
+         %12 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+      %int_0 = OpConstant %int 0
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+     %uint_1 = OpConstant %uint 1
+%accelerationStructureKHR = OpTypeAccelerationStructureKHR
+%_ptr_UniformConstant_accelerationStructureKHR = OpTypePointer UniformConstant %accelerationStructureKHR
+%_runtimearr_float = OpTypeRuntimeArray %float
+%type_RWStructuredBuffer_float = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform_type_RWStructuredBuffer_float = OpTypePointer Uniform %type_RWStructuredBuffer_float
+       %void = OpTypeVoid
+         %20 = OpTypeFunction %void
+%rayQueryKHR = OpTypeRayQueryKHR
+%_ptr_Function_rayQueryKHR = OpTypePointer Function %rayQueryKHR
+       %bool = OpTypeBool
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+        %bvh = OpVariable %_ptr_UniformConstant_accelerationStructureKHR UniformConstant
+     %output = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_float Uniform
+       %main = OpFunction %void None %20
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_rayQueryKHR Function
+         %26 = OpLoad %accelerationStructureKHR %bvh
+               OpRayQueryInitializeKHR %25 %26 %uint_0 %uint_0 %12 %float_0 %12 %float_0
+         %27 = OpRayQueryProceedKHR %bool %25
+         %28 = OpRayQueryGetIntersectionTypeKHR %uint %25 %uint_1
+         %29 = OpIEqual %bool %28 %uint_1
+               OpSelectionMerge %30 None
+               OpBranchConditional %29 %31 %30
+         %31 = OpLabel
+         %32 = OpAccessChain %_ptr_Uniform_float %output %int_0 %uint_0
+               OpStore %32 %float_0
+               OpBranch %30
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       RayTracingKHR_RemainsWithIntersectionExecutionMode) {
+  const std::string kTest = R"(
+               OpCapability RayTracingKHR
+               OpExtension "SPV_KHR_ray_tracing"
+; CHECK:       OpCapability RayTracingKHR
+; CHECK:       OpExtension "SPV_KHR_ray_tracing"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint IntersectionKHR %main "main"
+               OpSource HLSL 660
+               OpName %main "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %main = OpFunction %void None %3
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       RayTracingKHR_RemainsWithClosestHitExecutionMode) {
+  const std::string kTest = R"(
+               OpCapability RayTracingKHR
+               OpExtension "SPV_KHR_ray_tracing"
+; CHECK:       OpCapability RayTracingKHR
+; CHECK:       OpExtension "SPV_KHR_ray_tracing"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint ClosestHitKHR %main "main" %a
+               OpSource HLSL 630
+               OpName %Payload "Payload"
+               OpMemberName %Payload 0 "color"
+               OpName %a "a"
+               OpName %main "main"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+    %Payload = OpTypeStruct %v4float
+%ptr_payload = OpTypePointer IncomingRayPayloadKHR %Payload
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+          %a = OpVariable %ptr_payload IncomingRayPayloadKHR
+       %main = OpFunction %void None %8
+          %9 = OpLabel
+         %10 = OpLoad %Payload %a
+               OpStore %a %10
+               OpReturn
+               OpFunctionEnd
+
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, RayTracingKHR_RemainsWithAnyHitExecutionMode) {
+  const std::string kTest = R"(
+               OpCapability RayTracingKHR
+               OpExtension "SPV_KHR_ray_tracing"
+; CHECK:       OpCapability RayTracingKHR
+; CHECK:       OpExtension "SPV_KHR_ray_tracing"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint AnyHitKHR %main "main" %a
+               OpSource HLSL 630
+               OpName %Payload "Payload"
+               OpMemberName %Payload 0 "color"
+               OpName %a "a"
+               OpName %main "main"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+    %Payload = OpTypeStruct %v4float
+%ptr_payload = OpTypePointer IncomingRayPayloadKHR %Payload
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+          %a = OpVariable %ptr_payload IncomingRayPayloadKHR
+       %main = OpFunction %void None %8
+          %9 = OpLabel
+         %10 = OpLoad %Payload %a
+               OpStore %a %10
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, RayTracingKHR_RemainsWithMissExecutionMode) {
+  const std::string kTest = R"(
+               OpCapability RayTracingKHR
+               OpExtension "SPV_KHR_ray_tracing"
+; CHECK:       OpCapability RayTracingKHR
+; CHECK:       OpExtension "SPV_KHR_ray_tracing"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint MissKHR %main "main" %a
+               OpSource HLSL 630
+               OpName %Payload "Payload"
+               OpMemberName %Payload 0 "color"
+               OpName %a "a"
+               OpName %main "main"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+    %Payload = OpTypeStruct %v4float
+%ptr_payload = OpTypePointer IncomingRayPayloadKHR %Payload
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+          %a = OpVariable %ptr_payload IncomingRayPayloadKHR
+       %main = OpFunction %void None %8
+          %9 = OpLabel
+         %10 = OpLoad %Payload %a
+               OpStore %a %10
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       RayTracingKHR_RemainsWithRayGenerationExecutionMode) {
+  const std::string kTest = R"(
+               OpCapability RayTracingKHR
+               OpExtension "SPV_KHR_ray_tracing"
+; CHECK:       OpCapability RayTracingKHR
+; CHECK:       OpExtension "SPV_KHR_ray_tracing"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint RayGenerationKHR %main "main"
+               OpSource HLSL 630
+               OpName %main "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %main = OpFunction %void None %3
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       RayTracingKHR_RemainsWithCallableExecutionMode) {
+  const std::string kTest = R"(
+; CHECK:       OpCapability RayTracingKHR
+; CHECK:       OpExtension "SPV_KHR_ray_tracing"
+               OpCapability RayTracingKHR
+               OpExtension "SPV_KHR_ray_tracing"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint CallableKHR %main "main" %a
+               OpSource HLSL 660
+               OpName %Payload "Payload"
+               OpMemberName %Payload 0 "data"
+               OpName %a "a"
+               OpName %main "main"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+    %Payload = OpTypeStruct %v4float
+%ptr_payload = OpTypePointer IncomingCallableDataKHR %Payload
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+          %a = OpVariable %ptr_payload IncomingCallableDataKHR
+       %main = OpFunction %void None %8
+          %9 = OpLabel
+         %10 = OpLoad %Payload %a
+               OpStore %a %10
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       ImageMSArray_RemainsIfSampledIs2AndArrayedIs1) {
+  const std::string kTest = R"(
+               OpCapability ImageMSArray
+ ; CHECK:      OpCapability ImageMSArray
+               OpCapability Shader
+               OpCapability StorageImageMultisample
+               OpCapability StorageImageReadWithoutFormat
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %var_image DescriptorSet 0
+               OpDecorate %var_image Binding 1
+       %void = OpTypeVoid
+       %func = OpTypeFunction %void
+        %f32 = OpTypeFloat 32
+        %u32 = OpTypeInt 32 0
+     %uint_2 = OpConstant %u32 2
+     %uint_1 = OpConstant %u32 1
+     %v2uint = OpTypeVector %u32 2
+    %v4float = OpTypeVector %f32 4
+    %image = OpTypeImage %f32 2D 2 1 1 2 Unknown
+%ptr_image = OpTypePointer UniformConstant %image
+       %10 = OpConstantComposite %v2uint %uint_1 %uint_2
+%var_image = OpVariable %ptr_image UniformConstant
+     %main = OpFunction %void None %func
+ %main_lab = OpLabel
+       %18 = OpLoad %image %var_image
+       %19 = OpImageRead %v4float %18 %10 Sample %uint_2
+             OpReturn
+             OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, ImageMSArray_RemovedIfNotUsed) {
+  const std::string kTest = R"(
+               OpCapability Shader
+               OpCapability ImageMSArray
+; CHECK-NOT:   OpCapability ImageMSArray
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %out_var_SV_Target
+               OpExecutionMode %main OriginUpperLeft
+               OpSource HLSL 660
+               OpName %out_var_SV_Target "out.var.SV_Target"
+               OpName %main "main"
+               OpDecorate %out_var_SV_Target Location 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
+       %main = OpFunction %void None %7
+          %8 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, ImageMSArray_RemovedIfArrayedIsNot1) {
+  const std::string kTest = R"(
+               OpCapability ImageMSArray
+ ; CHECK-NOT:  OpCapability ImageMSArray
+               OpCapability Shader
+               OpCapability StorageImageMultisample
+               OpCapability StorageImageReadWithoutFormat
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %var_image DescriptorSet 0
+               OpDecorate %var_image Binding 1
+       %void = OpTypeVoid
+       %func = OpTypeFunction %void
+        %f32 = OpTypeFloat 32
+        %u32 = OpTypeInt 32 0
+     %uint_2 = OpConstant %u32 2
+     %uint_1 = OpConstant %u32 1
+     %v2uint = OpTypeVector %u32 2
+    %v4float = OpTypeVector %f32 4
+    %image = OpTypeImage %f32 2D 2 0 1 2 Unknown
+%ptr_image = OpTypePointer UniformConstant %image
+       %10 = OpConstantComposite %v2uint %uint_1 %uint_2
+%var_image = OpVariable %ptr_image UniformConstant
+     %main = OpFunction %void None %func
+ %main_lab = OpLabel
+       %18 = OpLoad %image %var_image
+       %19 = OpImageRead %v4float %18 %10 Sample %uint_2
+             OpReturn
+             OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, ImageMSArray_RemovedIfSampledNot2) {
+  const std::string kTest = R"(
+               OpCapability ImageMSArray
+ ; CHECK-NOT:  OpCapability ImageMSArray
+               OpCapability Shader
+               OpCapability StorageImageReadWithoutFormat
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %var_image DescriptorSet 0
+               OpDecorate %var_image Binding 1
+       %void = OpTypeVoid
+       %func = OpTypeFunction %void
+        %f32 = OpTypeFloat 32
+        %u32 = OpTypeInt 32 0
+     %uint_3 = OpConstant %u32 3
+     %uint_2 = OpConstant %u32 2
+     %uint_1 = OpConstant %u32 1
+     %v3uint = OpTypeVector %u32 3
+    %v4float = OpTypeVector %f32 4
+    %image = OpTypeImage %f32 2D 2 1 0 2 Unknown
+%ptr_image = OpTypePointer UniformConstant %image
+       %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+%var_image = OpVariable %ptr_image UniformConstant
+     %main = OpFunction %void None %func
+ %main_lab = OpLabel
+       %18 = OpLoad %image %var_image
+       %19 = OpImageRead %v4float %18 %10
+             OpReturn
+             OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, Float64_RemovedWhenUnused) {
+  const std::string kTest = R"(
+               OpCapability Float64
+; CHECK-NOT:   OpCapability Float64
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, Float64_RemainsWhenUsed) {
+  const std::string kTest = R"(
+               OpCapability Float64
+; CHECK:       OpCapability Float64
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+      %float = OpTypeFloat 64
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       ComputeDerivativeGroupQuads_ReamainsWithExecMode) {
+  const std::string kTest = R"(
+               OpCapability ComputeDerivativeGroupQuadsNV
+               OpCapability ComputeDerivativeGroupLinearNV
+; CHECK-NOT:   OpCapability ComputeDerivativeGroupLinearNV
+; CHECK:       OpCapability ComputeDerivativeGroupQuadsNV
+; CHECK-NOT:   OpCapability ComputeDerivativeGroupLinearNV
+               OpCapability Shader
+; CHECK:       OpExtension "SPV_NV_compute_shader_derivatives"
+               OpExtension "SPV_NV_compute_shader_derivatives"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %1 DerivativeGroupQuadsNV
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       ComputeDerivativeGroupLinear_ReamainsWithExecMode) {
+  const std::string kTest = R"(
+               OpCapability ComputeDerivativeGroupLinearNV
+               OpCapability ComputeDerivativeGroupQuadsNV
+; CHECK-NOT:   OpCapability ComputeDerivativeGroupQuadsNV
+; CHECK:       OpCapability ComputeDerivativeGroupLinearNV
+; CHECK-NOT:   OpCapability ComputeDerivativeGroupQuadsNV
+               OpCapability Shader
+; CHECK:       OpExtension "SPV_NV_compute_shader_derivatives"
+               OpExtension "SPV_NV_compute_shader_derivatives"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %1 DerivativeGroupLinearNV
+       %void = OpTypeVoid
+      %float = OpTypeFloat 64
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageImageReadWithoutFormat_RemovedIfUnused) {
+  const std::string kTest = R"(
+               OpCapability StorageImageReadWithoutFormat
+; CHECK-NOT:   OpCapability StorageImageReadWithoutFormat
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %PSMain "PSMain" %out_var
+               OpExecutionMode %PSMain OriginUpperLeft
+               OpDecorate %out_var Location 0
+      %float = OpTypeFloat 32
+     %float4 = OpTypeVector %float 4
+    %float_0 = OpConstant %float 0
+%float4_0000 = OpConstantComposite %float4 %float_0 %float_0 %float_0 %float_0
+ %ptr_float4 = OpTypePointer Output %float4
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+    %out_var = OpVariable %ptr_float4 Output
+     %PSMain = OpFunction %void None %9
+         %10 = OpLabel
+               OpStore %out_var %float4_0000
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageImageReadWithoutFormat_RemovedIfUnusedOpImageFetch) {
+  const std::string kTest = R"(
+               OpCapability StorageImageReadWithoutFormat
+; CHECK-NOT:   OpCapability StorageImageReadWithoutFormat
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %PSMain "PSMain" %out_var
+               OpExecutionMode %PSMain OriginUpperLeft
+               OpDecorate %out_var Location 0
+               OpDecorate %texture DescriptorSet 0
+               OpDecorate %texture Binding 1
+      %float = OpTypeFloat 32
+     %float4 = OpTypeVector %float 4
+        %int = OpTypeInt 32 1
+       %int2 = OpTypeVector %int 2
+ %type_image = OpTypeImage %float 2D 2 0 0 1 Unknown
+  %ptr_image = OpTypePointer UniformConstant %type_image
+      %int_0 = OpConstant %int 0
+    %int2_00 = OpConstantComposite %int2 %int_0 %int_0
+ %ptr_float4 = OpTypePointer Output %float4
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+    %texture = OpVariable %ptr_image UniformConstant
+    %out_var = OpVariable %ptr_float4 Output
+     %PSMain = OpFunction %void None %9
+         %10 = OpLabel
+         %11 = OpLoad %type_image %texture
+         %12 = OpImageFetch %float4 %11 %int2_00 Lod %int_0
+               OpStore %out_var %12
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageImageReadWithoutFormat_RemainsWhenRequiredWithRead) {
+  const std::string kTest = R"(
+               OpCapability StorageImageReadWithoutFormat
+; CHECK:       OpCapability StorageImageReadWithoutFormat
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %PSMain "PSMain" %out_var
+               OpExecutionMode %PSMain OriginUpperLeft
+               OpDecorate %out_var Location 0
+               OpDecorate %texture DescriptorSet 0
+               OpDecorate %texture Binding 1
+      %float = OpTypeFloat 32
+     %float4 = OpTypeVector %float 4
+        %int = OpTypeInt 32 1
+       %int2 = OpTypeVector %int 2
+ %type_image = OpTypeImage %float 2D 2 0 0 1 Unknown
+  %ptr_image = OpTypePointer UniformConstant %type_image
+      %int_0 = OpConstant %int 0
+    %int2_00 = OpConstantComposite %int2 %int_0 %int_0
+ %ptr_float4 = OpTypePointer Output %float4
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+    %texture = OpVariable %ptr_image UniformConstant
+    %out_var = OpVariable %ptr_float4 Output
+     %PSMain = OpFunction %void None %9
+         %10 = OpLabel
+         %11 = OpLoad %type_image %texture
+         %12 = OpImageRead %float4 %11 %int2_00 Lod %int_0
+               OpStore %out_var %12
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageImageReadWithoutFormat_RemainsWhenRequiredWithSparseRead) {
+  const std::string kTest = R"(
+               OpCapability StorageImageReadWithoutFormat
+; CHECK:       OpCapability StorageImageReadWithoutFormat
+               OpCapability SparseResidency
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %PSMain "PSMain"
+               OpExecutionMode %PSMain OriginUpperLeft
+               OpDecorate %texture DescriptorSet 0
+               OpDecorate %texture Binding 1
+      %float = OpTypeFloat 32
+     %float4 = OpTypeVector %float 4
+        %int = OpTypeInt 32 1
+       %int2 = OpTypeVector %int 2
+ %type_image = OpTypeImage %float 2D 2 0 0 2 Unknown
+     %struct = OpTypeStruct %int %float4
+  %ptr_image = OpTypePointer UniformConstant %type_image
+      %int_0 = OpConstant %int 0
+    %int2_00 = OpConstantComposite %int2 %int_0 %int_0
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+    %texture = OpVariable %ptr_image UniformConstant
+     %PSMain = OpFunction %void None %9
+         %10 = OpLabel
+         %11 = OpLoad %type_image %texture
+         %12 = OpImageSparseRead %struct %11 %int2_00
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       StorageImageReadWithoutFormat_RemovedWithReadOnSubpassData) {
+  const std::string kTest = R"(
+               OpCapability StorageImageReadWithoutFormat
+; CHECK-NOT:   OpCapability StorageImageReadWithoutFormat
+               OpCapability InputAttachment
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %PSMain "PSMain" %out_var
+               OpExecutionMode %PSMain OriginUpperLeft
+               OpDecorate %out_var Location 0
+               OpDecorate %texture DescriptorSet 0
+               OpDecorate %texture Binding 1
+      %float = OpTypeFloat 32
+     %float4 = OpTypeVector %float 4
+        %int = OpTypeInt 32 1
+       %int2 = OpTypeVector %int 2
+ %type_image = OpTypeImage %float SubpassData 2 0 0 2 Unknown
+  %ptr_image = OpTypePointer UniformConstant %type_image
+      %int_0 = OpConstant %int 0
+    %int2_00 = OpConstantComposite %int2 %int_0 %int_0
+ %ptr_float4 = OpTypePointer Output %float4
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+    %texture = OpVariable %ptr_image UniformConstant
+    %out_var = OpVariable %ptr_float4 Output
+     %PSMain = OpFunction %void None %9
+         %10 = OpLabel
+         %11 = OpLoad %type_image %texture
+         %12 = OpImageRead %float4 %11 %int2_00
+               OpStore %out_var %12
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, PhysicalStorageBuffer_RemovedWhenUnused) {
+  const std::string kTest = R"(
+               OpCapability PhysicalStorageBufferAddresses
+; CHECK-NOT:   OpCapability PhysicalStorageBufferAddresses
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       PhysicalStorageBuffer_RemainsWithOpTypeForwardPointer) {
+  const std::string kTest = R"(
+               OpCapability PhysicalStorageBufferAddresses
+; CHECK:       OpCapability PhysicalStorageBufferAddresses
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 2 4
+       %void = OpTypeVoid
+        %int = OpTypeInt 32 0
+     %struct = OpTypeStruct %int
+               OpTypeForwardPointer %ptr PhysicalStorageBuffer
+        %ptr = OpTypePointer PhysicalStorageBuffer %struct
+          %3 = OpTypeFunction %void
+       %main = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       PhysicalStorageBuffer_RemainsWithPhysicalStorageBufferStorage) {
+  const std::string kTest = R"(
+               OpCapability PhysicalStorageBufferAddresses
+; CHECK:       OpCapability PhysicalStorageBufferAddresses
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 2 4
+       %void = OpTypeVoid
+        %int = OpTypeInt 32 0
+     %struct = OpTypeStruct %int
+        %ptr = OpTypePointer PhysicalStorageBuffer %struct
+          %3 = OpTypeFunction %void
+       %main = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       PhysicalStorageBuffer_RemainsWithRestrictDecoration) {
+  const std::string kTest = R"(
+               OpCapability PhysicalStorageBufferAddresses
+; CHECK:       OpCapability PhysicalStorageBufferAddresses
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 2 4
+               OpDecorate %var RestrictPointer
+       %void = OpTypeVoid
+        %int = OpTypeInt 32 0
+     %struct = OpTypeStruct %int
+        %ptr = OpTypePointer Function %struct
+          %3 = OpTypeFunction %void
+       %main = OpFunction %void None %3
+          %6 = OpLabel
+        %var = OpVariable %ptr Function
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       PhysicalStorageBuffer_RemainsWithAliasedDecoration) {
+  const std::string kTest = R"(
+               OpCapability PhysicalStorageBufferAddresses
+; CHECK:       OpCapability PhysicalStorageBufferAddresses
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 2 4
+               OpDecorate %var AliasedPointer
+       %void = OpTypeVoid
+        %int = OpTypeInt 32 0
+     %struct = OpTypeStruct %int
+        %ptr = OpTypePointer Function %struct
+          %3 = OpTypeFunction %void
+       %main = OpFunction %void None %3
+          %6 = OpLabel
+        %var = OpVariable %ptr Function
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, Float16_RemovedWhenUnused) {
+  const std::string kTest = R"(
+               OpCapability Float16
+; CHECK-NOT:   OpCapability Float16
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, Float16_RemainsWhenUsed) {
+  const std::string kTest = R"(
+               OpCapability Float16
+; CHECK:       OpCapability Float16
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+      %float = OpTypeFloat 16
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, Int16_RemovedWhenUnused) {
+  const std::string kTest = R"(
+               OpCapability Int16
+; CHECK-NOT:   OpCapability Int16
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, Int16_RemainsWhenUsed) {
+  const std::string kTest = R"(
+               OpCapability Int16
+; CHECK:       OpCapability Int16
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+        %int = OpTypeInt 16 1
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest, UInt16_RemainsWhenUsed) {
+  const std::string kTest = R"(
+               OpCapability Int16
+; CHECK:       OpCapability Int16
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+       %uint = OpTypeInt 16 0
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       VulkanMemoryModelDeviceScope_RemovedWhenUnused) {
+  const std::string kTest = R"(
+               OpCapability VulkanMemoryModelDeviceScope
+; CHECK-NOT:   OpCapability VulkanMemoryModelDeviceScope
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd;
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       VulkanMemoryModelDeviceScope_RemovedWhenUsedWithGLSL450) {
+  const std::string kTest = R"(
+               OpCapability VulkanMemoryModelDeviceScope
+; CHECK-NOT:   OpCapability VulkanMemoryModelDeviceScope
+               OpCapability Shader
+               OpCapability ShaderClockKHR
+               OpCapability Int64
+               OpExtension "SPV_KHR_shader_clock"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 2 4
+       %void = OpTypeVoid
+       %uint = OpTypeInt 32 0
+      %ulong = OpTypeInt 64 0
+     %uint_1 = OpConstant %uint 1
+          %3 = OpTypeFunction %void
+       %main = OpFunction %void None %3
+          %6 = OpLabel
+         %22 = OpReadClockKHR %ulong %uint_1 ; Device Scope
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       VulkanMemoryModelDeviceScope_RemainsWhenUsedWithVulkan) {
+  const std::string kTest = R"(
+               OpCapability VulkanMemoryModelDeviceScope
+; CHECK:       OpCapability VulkanMemoryModelDeviceScope
+               OpCapability Shader
+               OpCapability ShaderClockKHR
+               OpCapability Int64
+               OpExtension "SPV_KHR_shader_clock"
+               OpMemoryModel Logical Vulkan
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 2 4
+       %void = OpTypeVoid
+       %uint = OpTypeInt 32 0
+      %ulong = OpTypeInt 64 0
+     %uint_1 = OpConstant %uint 1
+          %3 = OpTypeFunction %void
+       %main = OpFunction %void None %3
+          %6 = OpLabel
+         %22 = OpReadClockKHR %ulong %uint_1 ; Device Scope
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
+}
+
+}  // namespace
+}  // namespace opt
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/type_manager_test.cpp b/third_party/SPIRV-Tools/test/opt/type_manager_test.cpp
index 563eb74..d4d0fef 100644
--- a/third_party/SPIRV-Tools/test/opt/type_manager_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/type_manager_test.cpp
@@ -171,6 +171,7 @@
   types.emplace_back(new NamedBarrier());
   types.emplace_back(new AccelerationStructureNV());
   types.emplace_back(new CooperativeMatrixNV(f32, 24, 24, 24));
+  types.emplace_back(new CooperativeMatrixKHR(f32, 8, 8, 8, 1002));
   types.emplace_back(new RayQueryKHR());
   types.emplace_back(new HitObjectNV());
 
@@ -237,6 +238,8 @@
     %arr_long_constant = OpTypeArray %s32 %long_constant
     %arr_spec_const_op = OpTypeArray %s32 %spec_const_op
     %cm   = OpTypeCooperativeMatrixNV %f64 %id4 %id4 %id4
+    %id2    = OpConstant %u32 2
+    %cmkhr  = OpTypeCooperativeMatrixKHR %f64 %id4 %id4 %id4 %id2
   )";
 
   std::vector<std::pair<uint32_t, std::string>> type_id_strs = {
@@ -275,6 +278,7 @@
       {37, "[sint32, id(33), words(0,705032704,1)]"},
       {38, "[sint32, id(34), words(2,34)]"},
       {39, "<float64, 6, 6, 6>"},
+      {41, "<float64, 6, 6, 6, 40>"},
   };
 
   std::unique_ptr<IRContext> context =
@@ -938,10 +942,11 @@
   EXPECT_NE(context, nullptr);
 
   std::vector<std::unique_ptr<Type>> types = GenerateAllTypes();
-  uint32_t id = 1u;
+  uint32_t id = 0u;
   for (auto& t : types) {
-    context->get_type_mgr()->RegisterType(id, *t);
+    context->get_type_mgr()->RegisterType(++id, *t);
     EXPECT_EQ(*t, *context->get_type_mgr()->GetType(id));
+    EXPECT_EQ(id, context->get_type_mgr()->GetId(t.get()));
   }
   types.clear();
 
@@ -1030,6 +1035,8 @@
 ; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
 ; CHECK: [[input_ptr:%\w+]] = OpTypePointer Input [[uint]]
 ; CHECK: [[uniform_ptr:%\w+]] = OpTypePointer Uniform [[uint]]
+; CHECK: [[uint2:%\w+]] = OpConstant [[uint]] 2
+; CHECK: [[uint8:%\w+]] = OpConstant [[uint]] 8
 ; CHECK: [[uint24:%\w+]] = OpConstant [[uint]] 24
 ; CHECK: [[uint42:%\w+]] = OpConstant [[uint]] 42
 ; CHECK: [[uint100:%\w+]] = OpConstant [[uint]] 100
@@ -1085,6 +1092,7 @@
 ; CHECK: OpTypeNamedBarrier
 ; CHECK: OpTypeAccelerationStructureKHR
 ; CHECK: OpTypeCooperativeMatrixNV [[f32]] [[uint24]] [[uint24]] [[uint24]]
+; CHECK: OpTypeCooperativeMatrixKHR [[f32]] [[uint8]] [[uint8]] [[uint8]] [[uint2]]
 ; CHECK: OpTypeRayQueryKHR
 ; CHECK: OpTypeHitObjectNV
 OpCapability Shader
@@ -1094,6 +1102,8 @@
 %uint = OpTypeInt 32 0
 %1 = OpTypePointer Input %uint
 %2 = OpTypePointer Uniform %uint
+%1002 = OpConstant %uint 2
+%8 = OpConstant %uint 8
 %24 = OpConstant %uint 24
 %42 = OpConstant %uint 42
 %100 = OpConstant %uint 100
@@ -1190,6 +1200,39 @@
   Match(text, context.get());
 }
 
+// Structures containing circular type references
+// (from https://github.com/KhronosGroup/SPIRV-Tools/issues/5623).
+TEST(TypeManager, CircularPointerToStruct) {
+  const std::string text = R"(
+               OpCapability VariablePointers
+               OpCapability PhysicalStorageBufferAddresses
+               OpCapability Int64
+               OpCapability Shader
+               OpExtension "SPV_KHR_variable_pointers"
+               OpExtension "SPV_KHR_physical_storage_buffer"
+               OpMemoryModel PhysicalStorageBuffer64 GLSL450
+               OpEntryPoint Fragment %1 "main"
+               OpExecutionMode %1 OriginUpperLeft
+               OpExecutionMode %1 DepthReplacing
+               OpDecorate %1200 ArrayStride 24
+               OpMemberDecorate %600 0 Offset 0
+               OpMemberDecorate %800 0 Offset 0
+               OpMemberDecorate %120 0 Offset 16
+               OpTypeForwardPointer %1200 PhysicalStorageBuffer
+                 %600 = OpTypeStruct %1200
+                 %800 = OpTypeStruct %1200
+                 %120 = OpTypeStruct %800
+                %1200 = OpTypePointer PhysicalStorageBuffer %120
+  )";
+
+  std::unique_ptr<IRContext> context =
+      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
+                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  TypeManager manager(nullptr, context.get());
+  uint32_t id = manager.FindPointerToType(600, spv::StorageClass::Function);
+  EXPECT_EQ(id, 1201);
+}
+
 }  // namespace
 }  // namespace analysis
 }  // namespace opt
diff --git a/third_party/SPIRV-Tools/test/scripts/test_compact_ids.py b/third_party/SPIRV-Tools/test/scripts/test_compact_ids.py
index 6ca6e67..b1d5387 100644
--- a/third_party/SPIRV-Tools/test/scripts/test_compact_ids.py
+++ b/third_party/SPIRV-Tools/test/scripts/test_compact_ids.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright (c) 2017 Google Inc.
 
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,7 +47,7 @@
   template= \
 """{script} tests correctness of opt pass tools/opt --compact-ids
 
-USAGE: python {script} [<spirv_files>]
+USAGE: python3 {script} [<spirv_files>]
 
 Requires tools/spirv-dis, tools/spirv-as and tools/spirv-opt to be in path
 (call the script from the SPIRV-Tools build output directory).
diff --git a/third_party/SPIRV-Tools/test/text_to_binary.extension_test.cpp b/third_party/SPIRV-Tools/test/text_to_binary.extension_test.cpp
index 55f8466..8e78312 100644
--- a/third_party/SPIRV-Tools/test/text_to_binary.extension_test.cpp
+++ b/third_party/SPIRV-Tools/test/text_to_binary.extension_test.cpp
@@ -1247,5 +1247,58 @@
              MakeInstruction(spv::Op::OpStencilAttachmentReadEXT, {1, 2, 3})},
         })));
 
+// SPV_KHR_maximal_reconvergence
+
+INSTANTIATE_TEST_SUITE_P(
+    SPV_KHR_maximal_reconvergence, ExtensionRoundTripTest,
+    Combine(
+        Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0,
+               SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3),
+        ValuesIn(std::vector<AssemblyCase>{
+            {"OpExtension \"SPV_KHR_maximal_reconvergence\"\n",
+             MakeInstruction(spv::Op::OpExtension,
+                             MakeVector("SPV_KHR_maximal_reconvergence"))},
+            {"OpExecutionMode %1 MaximallyReconvergesKHR\n",
+             MakeInstruction(
+                 spv::Op::OpExecutionMode,
+                 {1, (uint32_t)spv::ExecutionMode::MaximallyReconvergesKHR})},
+        })));
+
+// SPV_KHR_float_controls2
+
+INSTANTIATE_TEST_SUITE_P(
+    SPV_KHR_float_controls2, ExtensionRoundTripTest,
+    Combine(
+        Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0,
+               SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3),
+        ValuesIn(std::vector<AssemblyCase>{
+            {"OpExtension \"SPV_KHR_float_controls2\"\n",
+             MakeInstruction(spv::Op::OpExtension,
+                             MakeVector("SPV_KHR_float_controls2"))},
+            {"OpCapability FloatControls2\n",
+             MakeInstruction(spv::Op::OpCapability,
+                             {(uint32_t)spv::Capability::FloatControls2})},
+            {"OpExecutionMode %1 FPFastMathDefault %2 %3\n",
+             // The operands are: target type, flags constant
+             MakeInstruction(
+                 spv::Op::OpExecutionMode,
+                 {1, (uint32_t)spv::ExecutionMode::FPFastMathDefault, 2, 3})},
+            {"OpDecorate %1 FPFastMathMode AllowContract\n",
+             MakeInstruction(
+                 spv::Op::OpDecorate,
+                 {1, (uint32_t)spv::Decoration::FPFastMathMode,
+                  (uint32_t)spv::FPFastMathModeMask::AllowContract})},
+            {"OpDecorate %1 FPFastMathMode AllowReassoc\n",
+             MakeInstruction(
+                 spv::Op::OpDecorate,
+                 {1, (uint32_t)spv::Decoration::FPFastMathMode,
+                  (uint32_t)spv::FPFastMathModeMask::AllowReassoc})},
+            {"OpDecorate %1 FPFastMathMode AllowTransform\n",
+             MakeInstruction(
+                 spv::Op::OpDecorate,
+                 {1, (uint32_t)spv::Decoration::FPFastMathMode,
+                  (uint32_t)spv::FPFastMathModeMask::AllowTransform})},
+        })));
+
 }  // namespace
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/text_to_binary.pipe_storage_test.cpp b/third_party/SPIRV-Tools/test/text_to_binary.pipe_storage_test.cpp
index 2a41d42..ef899a2 100644
--- a/third_party/SPIRV-Tools/test/text_to_binary.pipe_storage_test.cpp
+++ b/third_party/SPIRV-Tools/test/text_to_binary.pipe_storage_test.cpp
@@ -41,7 +41,7 @@
       Eq(MakeInstruction(spv::Op::OpTypePipeStorage, {1})));
   EXPECT_THAT(CompileFailure("%res = OpTypePipeStorage %1 %2 %3 %4 %5",
                              SPV_ENV_UNIVERSAL_1_1),
-              Eq("'=' expected after result id."));
+              Eq("'=' expected after result id but found '%2'."));
 }
 
 using OpConstantPipeStorageTest = spvtest::TextToBinaryTest;
@@ -72,7 +72,7 @@
       Eq(MakeInstruction(spv::Op::OpConstantPipeStorage, {1, 2, 3, 4, 5})));
   EXPECT_THAT(CompileFailure("%1 = OpConstantPipeStorage %2 3 4 5 %6 %7",
                              SPV_ENV_UNIVERSAL_1_1),
-              Eq("'=' expected after result id."));
+              Eq("'=' expected after result id but found '%7'."));
 }
 
 TEST_F(OpConstantPipeStorageTest, ArgumentTypes) {
@@ -118,7 +118,7 @@
       Eq(MakeInstruction(spv::Op::OpCreatePipeFromPipeStorage, {1, 2, 3})));
   EXPECT_THAT(CompileFailure("%1 = OpCreatePipeFromPipeStorage %2 %3 %4 %5",
                              SPV_ENV_UNIVERSAL_1_1),
-              Eq("'=' expected after result id."));
+              Eq("'=' expected after result id but found '%5'."));
 }
 
 TEST_F(OpCreatePipeFromPipeStorageTest, ArgumentTypes) {
diff --git a/third_party/SPIRV-Tools/test/tools/CMakeLists.txt b/third_party/SPIRV-Tools/test/tools/CMakeLists.txt
index 4c8989f..37fe2b9 100644
--- a/third_party/SPIRV-Tools/test/tools/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/test/tools/CMakeLists.txt
@@ -13,10 +13,10 @@
 # limitations under the License.
 
 add_test(NAME spirv-tools_expect_unittests
-         COMMAND ${PYTHON_EXECUTABLE} -m unittest expect_unittest.py
+         COMMAND Python3::Interpreter -m unittest expect_unittest.py
          WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 add_test(NAME spirv-tools_spirv_test_framework_unittests
-         COMMAND ${PYTHON_EXECUTABLE} -m unittest spirv_test_framework_unittest.py
+         COMMAND Python3::Interpreter -m unittest spirv_test_framework_unittest.py
          WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 
 add_spvtools_unittest(
diff --git a/third_party/SPIRV-Tools/test/tools/opt/CMakeLists.txt b/third_party/SPIRV-Tools/test/tools/opt/CMakeLists.txt
index 21aa247..966ffbb 100644
--- a/third_party/SPIRV-Tools/test/tools/opt/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/test/tools/opt/CMakeLists.txt
@@ -13,9 +13,9 @@
 # limitations under the License.
 
 if(NOT ${SPIRV_SKIP_TESTS})
-  if(${PYTHONINTERP_FOUND})
+  if(${Python3_Interpreter_FOUND})
     add_test(NAME spirv_opt_cli_tools_tests
-      COMMAND ${PYTHON_EXECUTABLE}
+      COMMAND Python3::Interpreter
       ${CMAKE_CURRENT_SOURCE_DIR}/../spirv_test_framework.py
       $<TARGET_FILE:spirv-opt> $<TARGET_FILE:spirv-as> $<TARGET_FILE:spirv-dis>
       --test-dir ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/third_party/SPIRV-Tools/test/unit_spirv.h b/third_party/SPIRV-Tools/test/unit_spirv.h
index bc9857e..9e7074c 100644
--- a/third_party/SPIRV-Tools/test/unit_spirv.h
+++ b/third_party/SPIRV-Tools/test/unit_spirv.h
@@ -202,9 +202,8 @@
 // Returns the capabilities in a CapabilitySet as an ordered vector.
 inline std::vector<spv::Capability> ElementsIn(
     const spvtools::CapabilitySet& capabilities) {
-  std::vector<spv::Capability> result;
-  capabilities.ForEach([&result](spv::Capability c) { result.push_back(c); });
-  return result;
+  return std::vector<spv::Capability>(capabilities.cbegin(),
+                                      capabilities.cend());
 }
 
 }  // namespace spvtest
diff --git a/third_party/SPIRV-Tools/test/val/CMakeLists.txt b/third_party/SPIRV-Tools/test/val/CMakeLists.txt
index 62d93bd..9d6f6ea 100644
--- a/third_party/SPIRV-Tools/test/val/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/test/val/CMakeLists.txt
@@ -46,6 +46,7 @@
        val_extension_spv_khr_bit_instructions_test.cpp
        val_extension_spv_khr_terminate_invocation_test.cpp
        val_extension_spv_khr_subgroup_rotate_test.cpp
+       val_extension_spv_nv_raw_access_chains.cpp
        val_ext_inst_test.cpp
        val_ext_inst_debug_test.cpp
        ${VAL_TEST_COMMON_SRCS}
diff --git a/third_party/SPIRV-Tools/test/val/val_annotation_test.cpp b/third_party/SPIRV-Tools/test/val/val_annotation_test.cpp
index 9f85a30..97dde2d 100644
--- a/third_party/SPIRV-Tools/test/val/val_annotation_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_annotation_test.cpp
@@ -65,6 +65,171 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
+TEST_F(DecorationTest, FPFastMathModeInvalidMask) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add FPFastMathMode !524288
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%undef = OpUndef %float
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%add = OpFAdd %float %undef %undef
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Invalid floating-point fast math mode operand"));
+}
+
+TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingAllowContract) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add FPFastMathMode AllowTransform|AllowReassoc
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%undef = OpUndef %float
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%add = OpFAdd %float %undef %undef
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AllowReassoc and AllowContract must be specified when "
+                        "AllowTransform is specified"));
+}
+
+TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingAllowReassoc) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add FPFastMathMode AllowTransform|AllowContract
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%undef = OpUndef %float
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%add = OpFAdd %float %undef %undef
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AllowReassoc and AllowContract must be specified when "
+                        "AllowTransform is specified"));
+}
+
+TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingContractAndReassoc) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add FPFastMathMode AllowTransform
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%undef = OpUndef %float
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%add = OpFAdd %float %undef %undef
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AllowReassoc and AllowContract must be specified when "
+                        "AllowTransform is specified"));
+}
+
+TEST_F(DecorationTest, FPFastMathModeAndNoContraction) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add FPFastMathMode None
+OpDecorate %add NoContraction
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%undef = OpUndef %float
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%add = OpFAdd %float %undef %undef
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "FPFastMathMode and NoContraction cannot decorate the same target"));
+}
+
+TEST_F(DecorationTest, FPFastMathModeAndNoContraction2) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add NoContraction
+OpDecorate %add FPFastMathMode None
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%undef = OpUndef %float
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%add = OpFAdd %float %undef %undef
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "FPFastMathMode and NoContraction cannot decorate the same target"));
+}
+
 using MemberOnlyDecorations = spvtest::ValidateBase<std::string>;
 
 TEST_P(MemberOnlyDecorations, MemberDecoration) {
diff --git a/third_party/SPIRV-Tools/test/val/val_arithmetics_test.cpp b/third_party/SPIRV-Tools/test/val/val_arithmetics_test.cpp
index 631375e..58ac442 100644
--- a/third_party/SPIRV-Tools/test/val/val_arithmetics_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_arithmetics_test.cpp
@@ -1318,7 +1318,7 @@
   CompileSuccessfully(GenerateCoopMatCode(types, "").c_str());
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
   EXPECT_THAT(getDiagnosticString(),
-              HasSubstr("OpTypeCooperativeMatrixNV Component Type <id> "
+              HasSubstr("OpTypeCooperativeMatrix Component Type <id> "
                         "'4[%bool]' is not a scalar numerical type."));
 }
 
@@ -1331,7 +1331,7 @@
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
   EXPECT_THAT(
       getDiagnosticString(),
-      HasSubstr("OpTypeCooperativeMatrixNV Scope <id> '17[%float_1]' is not a "
+      HasSubstr("OpTypeCooperativeMatrix Scope <id> '17[%float_1]' is not a "
                 "constant instruction with scalar integer type."));
 }
 
@@ -1344,7 +1344,7 @@
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
   EXPECT_THAT(
       getDiagnosticString(),
-      HasSubstr("OpTypeCooperativeMatrixNV Rows <id> '17[%float_1]' is not a "
+      HasSubstr("OpTypeCooperativeMatrix Rows <id> '17[%float_1]' is not a "
                 "constant instruction with scalar integer type."));
 }
 
@@ -1357,7 +1357,7 @@
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
   EXPECT_THAT(
       getDiagnosticString(),
-      HasSubstr("OpTypeCooperativeMatrixNV Cols <id> '17[%float_1]' is not a "
+      HasSubstr("OpTypeCooperativeMatrix Cols <id> '17[%float_1]' is not a "
                 "constant instruction with scalar integer type."));
 }
 
@@ -1469,6 +1469,149 @@
                 "SMulExtended"));
 }
 
+std::string GenerateCoopMatKHRCode(const std::string& extra_types,
+                                   const std::string& main_body) {
+  const std::string prefix = R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%bool = OpTypeBool
+%f16 = OpTypeFloat 16
+%f32 = OpTypeFloat 32
+%u32 = OpTypeInt 32 0
+%s32 = OpTypeInt 32 1
+
+%u32_16 = OpConstant %u32 16
+%u32_4 = OpConstant %u32 4
+%subgroup = OpConstant %u32 3
+%useA = OpConstant %u32 0
+%useB = OpConstant %u32 1
+%useC = OpConstant %u32 2
+
+%f16matA = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useA
+%u32matA = OpTypeCooperativeMatrixKHR %u32 %subgroup %u32_16 %u32_16 %useA
+%s32matA = OpTypeCooperativeMatrixKHR %s32 %subgroup %u32_16 %u32_16 %useA
+
+%f16matB = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useB
+%u32matB = OpTypeCooperativeMatrixKHR %u32 %subgroup %u32_16 %u32_16 %useB
+%s32matB = OpTypeCooperativeMatrixKHR %s32 %subgroup %u32_16 %u32_16 %useB
+
+%f16matC = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useC
+%f32matC = OpTypeCooperativeMatrixKHR %f32 %subgroup %u32_16 %u32_16 %useC
+%u32matC = OpTypeCooperativeMatrixKHR %u32 %subgroup %u32_16 %u32_16 %useC
+%s32matC = OpTypeCooperativeMatrixKHR %s32 %subgroup %u32_16 %u32_16 %useC
+
+%f16_1 = OpConstant %f16 1
+%f32_1 = OpConstant %f32 1
+%u32_1 = OpConstant %u32 1
+%s32_1 = OpConstant %s32 1
+
+%f16mat_A_1 = OpConstantComposite %f16matA %f16_1
+%u32mat_A_1 = OpConstantComposite %u32matA %u32_1
+%s32mat_A_1 = OpConstantComposite %s32matA %s32_1
+
+%f16mat_B_1 = OpConstantComposite %f16matB %f16_1
+%u32mat_B_1 = OpConstantComposite %u32matB %u32_1
+%s32mat_B_1 = OpConstantComposite %s32matB %s32_1
+
+%f16mat_C_1 = OpConstantComposite %f16matC %f16_1
+%u32mat_C_1 = OpConstantComposite %u32matC %u32_1
+%s32mat_C_1 = OpConstantComposite %s32matC %s32_1
+
+)";
+
+  const std::string func_begin = R"(
+%main = OpFunction %void None %func
+%main_entry = OpLabel)";
+
+  const std::string suffix = R"(
+OpReturn
+OpFunctionEnd)";
+
+  return prefix + extra_types + func_begin + main_body + suffix;
+}
+
+TEST_F(ValidateArithmetics, CoopMatKHRSuccess) {
+  const std::string body = R"(
+%val1 = OpFAdd %f16matA %f16mat_A_1 %f16mat_A_1
+%val2 = OpFSub %f16matA %f16mat_A_1 %f16mat_A_1
+%val3 = OpFMul %f16matA %f16mat_A_1 %f16mat_A_1
+%val4 = OpFDiv %f16matA %f16mat_A_1 %f16mat_A_1
+%val5 = OpFNegate %f16matA %f16mat_A_1
+%val6 = OpIAdd %u32matA %u32mat_A_1 %u32mat_A_1
+%val7 = OpISub %u32matA %u32mat_A_1 %u32mat_A_1
+%val8 = OpUDiv %u32matA %u32mat_A_1 %u32mat_A_1
+%val9 = OpIAdd %s32matA %s32mat_A_1 %s32mat_A_1
+%val10 = OpISub %s32matA %s32mat_A_1 %s32mat_A_1
+%val11 = OpSDiv %s32matA %s32mat_A_1 %s32mat_A_1
+%val12 = OpSNegate %s32matA %s32mat_A_1
+%val13 = OpMatrixTimesScalar %f16matA %f16mat_A_1 %f16_1
+%val14 = OpMatrixTimesScalar %u32matA %u32mat_A_1 %u32_1
+%val15 = OpMatrixTimesScalar %s32matA %s32mat_A_1 %s32_1
+%val16 = OpCooperativeMatrixMulAddKHR %f32matC %f16mat_A_1 %f16mat_B_1 %f16mat_C_1
+%val17 = OpCooperativeMatrixMulAddKHR %s32matC %s32mat_A_1 %s32mat_B_1 %s32mat_C_1
+  MatrixASignedComponentsKHR|MatrixBSignedComponentsKHR|MatrixCSignedComponentsKHR|MatrixResultSignedComponentsKHR
+%val18 = OpCooperativeMatrixMulAddKHR %u32matC %u32mat_A_1 %u32mat_B_1 %u32mat_C_1
+)";
+
+  CompileSuccessfully(GenerateCoopMatKHRCode("", body).c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateArithmetics, CoopMatMatrixKHRTimesScalarMismatchFail) {
+  const std::string body = R"(
+%val1 = OpMatrixTimesScalar %f16matA %f16mat_A_1 %f32_1
+)";
+
+  CompileSuccessfully(GenerateCoopMatKHRCode("", body).c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Expected scalar operand type to be equal to the component "
+                "type of the matrix operand: MatrixTimesScalar"));
+}
+
+TEST_F(ValidateArithmetics, CoopMatKHRScopeFail) {
+  const std::string types = R"(
+%workgroup = OpConstant %u32 2
+%mat16x16_wg = OpTypeCooperativeMatrixKHR %f16 %workgroup %u32_16 %u32_16 %useC
+%f16matwg_16x16_1 = OpConstantComposite %mat16x16_wg %f16_1
+)";
+
+  const std::string body = R"(
+%val1 = OpFAdd %f16matA %f16matwg_16x16_1 %f16mat_A_1
+)";
+
+  CompileSuccessfully(GenerateCoopMatKHRCode(types, body).c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Expected scopes of Matrix and Result Type to be identical"));
+}
+
+TEST_F(ValidateArithmetics, CoopMatKHRDimFail) {
+  const std::string types = R"(
+%mat16x4 = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_4 %useC
+%mat16x4_C_1 = OpConstantComposite %mat16x4 %f16_1
+)";
+
+  const std::string body = R"(
+%val1 = OpCooperativeMatrixMulAddKHR %mat16x4 %f16mat_A_1 %f16mat_B_1 %mat16x4_C_1
+)";
+
+  CompileSuccessfully(GenerateCoopMatKHRCode(types, body).c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Cooperative matrix 'N' mismatch: CooperativeMatrixMulAddKHR"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_atomics_test.cpp b/third_party/SPIRV-Tools/test/val/val_atomics_test.cpp
index b266ad6..0f65634 100644
--- a/third_party/SPIRV-Tools/test/val/val_atomics_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_atomics_test.cpp
@@ -318,7 +318,8 @@
   EXPECT_THAT(
       getDiagnosticString(),
       HasSubstr("Opcode AtomicFAddEXT requires one of these capabilities: "
-                "AtomicFloat32AddEXT AtomicFloat64AddEXT AtomicFloat16AddEXT"));
+                "AtomicFloat16VectorNV AtomicFloat32AddEXT AtomicFloat64AddEXT "
+                "AtomicFloat16AddEXT"));
 }
 
 TEST_F(ValidateAtomics, AtomicMinFloatVulkan) {
@@ -331,7 +332,8 @@
   EXPECT_THAT(
       getDiagnosticString(),
       HasSubstr("Opcode AtomicFMinEXT requires one of these capabilities: "
-                "AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT"));
+                "AtomicFloat16VectorNV AtomicFloat32MinMaxEXT "
+                "AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT"));
 }
 
 TEST_F(ValidateAtomics, AtomicMaxFloatVulkan) {
@@ -343,8 +345,10 @@
   ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
   EXPECT_THAT(
       getDiagnosticString(),
-      HasSubstr("Opcode AtomicFMaxEXT requires one of these capabilities: "
-                "AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT"));
+      HasSubstr(
+          "Opcode AtomicFMaxEXT requires one of these capabilities: "
+          "AtomicFloat16VectorNV AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT "
+          "AtomicFloat16MinMaxEXT"));
 }
 
 TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType1) {
@@ -2713,6 +2717,136 @@
                         "value of type Result Type"));
 }
 
+TEST_F(ValidateAtomics, AtomicFloat16VectorSuccess) {
+  const std::string definitions = R"(
+%f16 = OpTypeFloat 16
+%f16vec2 = OpTypeVector %f16 2
+%f16vec4 = OpTypeVector %f16 4
+
+%f16_1 = OpConstant %f16 1
+%f16vec2_1 = OpConstantComposite %f16vec2 %f16_1 %f16_1
+%f16vec4_1 = OpConstantComposite %f16vec4 %f16_1 %f16_1 %f16_1 %f16_1
+
+%f16vec2_ptr = OpTypePointer Workgroup %f16vec2
+%f16vec4_ptr = OpTypePointer Workgroup %f16vec4
+%f16vec2_var = OpVariable %f16vec2_ptr Workgroup
+%f16vec4_var = OpVariable %f16vec4_ptr Workgroup
+)";
+
+  const std::string body = R"(
+%val3 = OpAtomicFMinEXT %f16vec2 %f16vec2_var %device %relaxed %f16vec2_1
+%val4 = OpAtomicFMaxEXT %f16vec2 %f16vec2_var %device %relaxed %f16vec2_1
+%val8 = OpAtomicFAddEXT %f16vec2 %f16vec2_var %device %relaxed %f16vec2_1
+%val9 = OpAtomicExchange %f16vec2 %f16vec2_var %device %relaxed %f16vec2_1
+
+%val11 = OpAtomicFMinEXT %f16vec4 %f16vec4_var %device %relaxed %f16vec4_1
+%val12 = OpAtomicFMaxEXT %f16vec4 %f16vec4_var %device %relaxed %f16vec4_1
+%val18 = OpAtomicFAddEXT %f16vec4 %f16vec4_var %device %relaxed %f16vec4_1
+%val19 = OpAtomicExchange %f16vec4 %f16vec4_var %device %relaxed %f16vec4_1
+
+)";
+
+  CompileSuccessfully(GenerateShaderComputeCode(
+                          body,
+                          "OpCapability Float16\n"
+                          "OpCapability AtomicFloat16VectorNV\n"
+                          "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n",
+                          definitions),
+                      SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
+static constexpr char Float16Vector3Defs[] = R"(
+%f16 = OpTypeFloat 16
+%f16vec3 = OpTypeVector %f16 3
+
+%f16_1 = OpConstant %f16 1
+%f16vec3_1 = OpConstantComposite %f16vec3 %f16_1 %f16_1 %f16_1
+
+%f16vec3_ptr = OpTypePointer Workgroup %f16vec3
+%f16vec3_var = OpVariable %f16vec3_ptr Workgroup
+)";
+
+TEST_F(ValidateAtomics, AtomicFloat16Vector3MinFail) {
+  const std::string definitions = Float16Vector3Defs;
+
+  const std::string body = R"(
+%val11 = OpAtomicFMinEXT %f16vec3 %f16vec3_var %device %relaxed %f16vec3_1
+)";
+
+  CompileSuccessfully(GenerateShaderComputeCode(
+                          body,
+                          "OpCapability Float16\n"
+                          "OpCapability AtomicFloat16VectorNV\n"
+                          "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n",
+                          definitions),
+                      SPV_ENV_VULKAN_1_0);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("AtomicFMinEXT: expected Result Type to be float scalar type"));
+}
+
+TEST_F(ValidateAtomics, AtomicFloat16Vector3MaxFail) {
+  const std::string definitions = Float16Vector3Defs;
+
+  const std::string body = R"(
+%val12 = OpAtomicFMaxEXT %f16vec3 %f16vec3_var %device %relaxed %f16vec3_1
+)";
+
+  CompileSuccessfully(GenerateShaderComputeCode(
+                          body,
+                          "OpCapability Float16\n"
+                          "OpCapability AtomicFloat16VectorNV\n"
+                          "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n",
+                          definitions),
+                      SPV_ENV_VULKAN_1_0);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("AtomicFMaxEXT: expected Result Type to be float scalar type"));
+}
+
+TEST_F(ValidateAtomics, AtomicFloat16Vector3AddFail) {
+  const std::string definitions = Float16Vector3Defs;
+
+  const std::string body = R"(
+%val18 = OpAtomicFAddEXT %f16vec3 %f16vec3_var %device %relaxed %f16vec3_1
+)";
+
+  CompileSuccessfully(GenerateShaderComputeCode(
+                          body,
+                          "OpCapability Float16\n"
+                          "OpCapability AtomicFloat16VectorNV\n"
+                          "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n",
+                          definitions),
+                      SPV_ENV_VULKAN_1_0);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("AtomicFAddEXT: expected Result Type to be float scalar type"));
+}
+
+TEST_F(ValidateAtomics, AtomicFloat16Vector3ExchangeFail) {
+  const std::string definitions = Float16Vector3Defs;
+
+  const std::string body = R"(
+%val19 = OpAtomicExchange %f16vec3 %f16vec3_var %device %relaxed %f16vec3_1
+)";
+
+  CompileSuccessfully(GenerateShaderComputeCode(
+                          body,
+                          "OpCapability Float16\n"
+                          "OpCapability AtomicFloat16VectorNV\n"
+                          "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n",
+                          definitions),
+                      SPV_ENV_VULKAN_1_0);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AtomicExchange: expected Result Type to be integer or "
+                        "float scalar type"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_barriers_test.cpp b/third_party/SPIRV-Tools/test/val/val_barriers_test.cpp
index f160904..ba8ac7d 100644
--- a/third_party/SPIRV-Tools/test/val/val_barriers_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_barriers_test.cpp
@@ -410,7 +410,7 @@
 TEST_F(ValidateBarriers,
        OpControlBarrierVulkan1p1WorkgroupNonComputeMemoryFailure) {
   const std::string body = R"(
-OpControlBarrier %subgroup %workgroup %acquire
+OpControlBarrier %subgroup %workgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1);
@@ -427,7 +427,7 @@
 TEST_F(ValidateBarriers,
        OpControlBarrierVulkan1p1WorkgroupNonComputeExecutionFailure) {
   const std::string body = R"(
-OpControlBarrier %workgroup %subgroup %acquire
+OpControlBarrier %workgroup %subgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1);
@@ -442,7 +442,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupComputeSuccess) {
   const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire
+OpControlBarrier %workgroup %workgroup %acquire_uniform_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
@@ -451,7 +451,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeSuccess) {
   const std::string body = R"(
-OpControlBarrier %subgroup %subgroup %acquire
+OpControlBarrier %subgroup %subgroup %acquire_uniform_workgroup
 )";
 
   CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1);
@@ -495,15 +495,15 @@
                         "AcquireRelease or SequentiallyConsistent"));
 }
 
-// TODO(atgoo@github.com): the corresponding check fails Vulkan CTS,
-// reenable once fixed.
-TEST_F(ValidateBarriers, DISABLED_OpControlBarrierVulkanSubgroupStorageClass) {
+TEST_F(ValidateBarriers, OpControlBarrierVulkanSubgroupStorageClass) {
   const std::string body = R"(
 OpControlBarrier %workgroup %device %acquire_release_subgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpControlBarrier-04650"));
   EXPECT_THAT(
       getDiagnosticString(),
       HasSubstr(
@@ -513,7 +513,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionFragment1p1) {
   const std::string body = R"(
-OpControlBarrier %subgroup %subgroup %acquire_release_subgroup
+OpControlBarrier %subgroup %subgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
@@ -523,7 +523,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionFragment1p1) {
   const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_release
+OpControlBarrier %workgroup %workgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
@@ -541,7 +541,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionFragment1p0) {
   const std::string body = R"(
-OpControlBarrier %subgroup %workgroup %acquire_release
+OpControlBarrier %subgroup %workgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
@@ -556,7 +556,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionVertex1p1) {
   const std::string body = R"(
-OpControlBarrier %subgroup %subgroup %acquire_release_subgroup
+OpControlBarrier %subgroup %subgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body, "", "Vertex"),
@@ -566,7 +566,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionVertex1p1) {
   const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_release
+OpControlBarrier %workgroup %workgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body, "", "Vertex"),
@@ -584,7 +584,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionVertex1p0) {
   const std::string body = R"(
-OpControlBarrier %subgroup %workgroup %acquire_release
+OpControlBarrier %subgroup %workgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body, "", "Vertex"),
@@ -599,7 +599,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionGeometry1p1) {
   const std::string body = R"(
-OpControlBarrier %subgroup %subgroup %acquire_release_subgroup
+OpControlBarrier %subgroup %subgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(
@@ -610,7 +610,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionGeometry1p1) {
   const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_release
+OpControlBarrier %workgroup %workgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(
@@ -629,7 +629,7 @@
 
 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionGeometry1p0) {
   const std::string body = R"(
-OpControlBarrier %subgroup %workgroup %acquire_release
+OpControlBarrier %subgroup %workgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(
@@ -646,7 +646,7 @@
 TEST_F(ValidateBarriers,
        OpControlBarrierSubgroupExecutionTessellationEvaluation1p1) {
   const std::string body = R"(
-OpControlBarrier %subgroup %subgroup %acquire_release_subgroup
+OpControlBarrier %subgroup %subgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n",
@@ -658,7 +658,7 @@
 TEST_F(ValidateBarriers,
        OpControlBarrierWorkgroupExecutionTessellationEvaluation1p1) {
   const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_release
+OpControlBarrier %workgroup %workgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n",
@@ -678,7 +678,7 @@
 TEST_F(ValidateBarriers,
        OpControlBarrierSubgroupExecutionTessellationEvaluation1p0) {
   const std::string body = R"(
-OpControlBarrier %subgroup %workgroup %acquire_release
+OpControlBarrier %subgroup %workgroup %acquire_release_workgroup
 )";
 
   CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n",
diff --git a/third_party/SPIRV-Tools/test/val/val_builtins_test.cpp b/third_party/SPIRV-Tools/test/val/val_builtins_test.cpp
index 4f9fc97..0104969 100644
--- a/third_party/SPIRV-Tools/test/val/val_builtins_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_builtins_test.cpp
@@ -4261,6 +4261,260 @@
         Values(TestResult(SPV_ERROR_INVALID_DATA,
                           "needs to be a 3-component 32-bit float vector"))));
 
+std::string GenerateMeshShadingCode(const std::string& built_in,
+                                    const std::string& execution_mode,
+                                    const std::string& body,
+                                    const std::string& declarations = "") {
+  std::ostringstream ss;
+  ss << R"(
+OpCapability MeshShadingEXT
+OpExtension "SPV_EXT_mesh_shader"
+OpMemoryModel Logical GLSL450
+OpEntryPoint MeshEXT %main "main" %var
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main OutputVertices 1
+OpExecutionMode %main OutputPrimitivesEXT 16
+)";
+  ss << "OpExecutionMode %main " << execution_mode << "\n";
+  ss << "OpDecorate %var BuiltIn " << built_in << "\n";
+
+  ss << R"(
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%bool = OpTypeBool
+%int = OpTypeInt 32 1
+%uint = OpTypeInt 32 0
+%v2uint = OpTypeVector %uint 2
+%v3uint = OpTypeVector %uint 3
+
+%int_0 = OpConstant %int 0
+%uint_16 = OpConstant %uint 16
+)";
+
+  ss << declarations;
+
+  ss << R"(
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+)";
+
+  ss << body;
+
+  ss << R"(
+OpReturn
+OpFunctionEnd)";
+  return ss.str();
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTSuccess) {
+  const std::string declarations = R"(
+%array = OpTypeArray %v3uint %uint_16
+%array_ptr = OpTypePointer Output %array
+%var = OpVariable %array_ptr Output
+%ptr = OpTypePointer Output %v3uint
+)";
+  const std::string body = R"(
+%access = OpAccessChain %ptr %var %int_0
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT",
+                              "OutputTrianglesEXT", body, declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTStorageClass) {
+  const std::string declarations = R"(
+%array = OpTypeArray %v3uint %uint_16
+%array_ptr = OpTypePointer Input %array
+%var = OpVariable %array_ptr Input
+%ptr = OpTypePointer Input %v3uint
+)";
+  const std::string body = R"(
+%access = OpAccessChain %ptr %var %int_0
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT",
+                              "OutputTrianglesEXT", body, declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-PrimitiveTriangleIndicesEXT-"
+                      "PrimitiveTriangleIndicesEXT-07055"));
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTVectorSize) {
+  const std::string declarations = R"(
+%array = OpTypeArray %v2uint %uint_16
+%array_ptr = OpTypePointer Output %array
+%var = OpVariable %array_ptr Output
+%ptr = OpTypePointer Output %v2uint
+)";
+  const std::string body = R"(
+%access = OpAccessChain %ptr %var %int_0
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT",
+                              "OutputTrianglesEXT", body, declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-PrimitiveTriangleIndicesEXT-"
+                      "PrimitiveTriangleIndicesEXT-07056"));
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTNonArray) {
+  const std::string declarations = R"(
+%ptr = OpTypePointer Output %v3uint
+%var = OpVariable %ptr Output
+)";
+  const std::string body = R"(
+%load = OpLoad %v3uint %var
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT",
+                              "OutputTrianglesEXT", body, declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-PrimitiveTriangleIndicesEXT-"
+                      "PrimitiveTriangleIndicesEXT-07056"));
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTSuccess) {
+  const std::string declarations = R"(
+%array = OpTypeArray %v2uint %uint_16
+%array_ptr = OpTypePointer Output %array
+%var = OpVariable %array_ptr Output
+%ptr = OpTypePointer Output %v2uint
+)";
+  const std::string body = R"(
+%access = OpAccessChain %ptr %var %int_0
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body,
+                              declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTStorageClass) {
+  const std::string declarations = R"(
+%array = OpTypeArray %v2uint %uint_16
+%array_ptr = OpTypePointer Input %array
+%var = OpVariable %array_ptr Input
+%ptr = OpTypePointer Input %v2uint
+)";
+  const std::string body = R"(
+%access = OpAccessChain %ptr %var %int_0
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body,
+                              declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049"));
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTType) {
+  const std::string declarations = R"(
+%array = OpTypeArray %v3uint %uint_16
+%array_ptr = OpTypePointer Input %array
+%var = OpVariable %array_ptr Input
+%ptr = OpTypePointer Input %v3uint
+)";
+  const std::string body = R"(
+%access = OpAccessChain %ptr %var %int_0
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body,
+                              declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050"));
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTSuccess) {
+  const std::string declarations = R"(
+%array = OpTypeArray %uint %uint_16
+%array_ptr = OpTypePointer Output %array
+%var = OpVariable %array_ptr Output
+%ptr = OpTypePointer Output %uint
+)";
+  const std::string body = R"(
+%access = OpAccessChain %ptr %var %int_0
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body,
+                              declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTStorageClass) {
+  const std::string declarations = R"(
+%array = OpTypeArray %uint %uint_16
+%array_ptr = OpTypePointer Input %array
+%var = OpVariable %array_ptr Input
+%ptr = OpTypePointer Input %uint
+)";
+  const std::string body = R"(
+%access = OpAccessChain %ptr %var %int_0
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body,
+                              declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043"));
+}
+
+TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTType) {
+  const std::string declarations = R"(
+%array = OpTypeArray %v3uint %uint_16
+%array_ptr = OpTypePointer Output %array
+%var = OpVariable %array_ptr Output
+%ptr = OpTypePointer Output %v3uint
+)";
+  const std::string body = R"(
+%access = OpAccessChain %ptr %var %int_0
+)";
+
+  CompileSuccessfully(
+      GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body,
+                              declarations)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_cfg_test.cpp b/third_party/SPIRV-Tools/test/val/val_cfg_test.cpp
index 3953057..233aee6 100644
--- a/third_party/SPIRV-Tools/test/val/val_cfg_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_cfg_test.cpp
@@ -4803,6 +4803,321 @@
                         "via a structured exit"));
 }
 
+TEST_F(ValidateCFG,
+       MaximalReconvergenceBranchConditionalSameTargetNotInCallTree) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+OpBranchConditional %cond %func_exit %func_exit
+%func_exit = OpLabel
+OpReturn
+OpFunctionEnd
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+}
+
+TEST_F(ValidateCFG, MaximalReconvergenceBranchConditionalSameTargetInCallTree) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+OpBranchConditional %cond %func_exit %func_exit
+%func_exit = OpLabel
+OpReturn
+OpFunctionEnd
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+%call = OpFunctionCall %void %func
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("In entry points using the MaximallyReconvergesKHR "
+                        "execution mode, True "
+                        "Label and False Label must be different labels"));
+}
+
+TEST_F(ValidateCFG, MaximalReconvergenceEarlyReconvergenceNotInCallTree) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+OpSelectionMerge %func_exit None
+OpBranchConditional %cond %then %else
+%then = OpLabel
+OpBranch %merge
+%else = OpLabel
+OpBranch %merge
+%merge = OpLabel
+OpBranch %func_exit
+%func_exit = OpLabel
+OpReturn
+OpFunctionEnd
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MaximalReconvergenceEarlyReconvergenceInCallTree) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+OpSelectionMerge %func_exit None
+OpBranchConditional %cond %then %else
+%then = OpLabel
+OpBranch %merge
+%else = OpLabel
+OpBranch %merge
+%merge = OpLabel
+OpBranch %func_exit
+%func_exit = OpLabel
+OpReturn
+OpFunctionEnd
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+%call = OpFunctionCall %void %func
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "In entry points using the MaximallyReconvergesKHR execution mode, "
+          "this basic block must not have multiple unique predecessors"));
+}
+
+TEST_F(ValidateCFG, MaximalReconvergenceLoopMultiplePredsOk) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+OpBranch %loop
+%loop = OpLabel
+OpLoopMerge %merge %loop None
+OpBranchConditional %cond %loop %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MaximalReconvergenceLoopMultiplePredsOk2) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+OpBranch %loop
+%loop = OpLabel
+OpLoopMerge %merge %cont None
+OpBranch %body
+%body = OpLabel
+OpBranch %cont
+%cont = OpLabel
+OpBranchConditional %cond %loop %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MaximalReconvergenceSelectionMergeMultiplePredsOk) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+OpSelectionMerge %merge None
+OpBranchConditional %cond %then %else
+%then = OpLabel
+OpBranch %merge
+%else = OpLabel
+OpBranch %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MaximalReconvergenceSelectionMergeMultiplePredsOk2) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+OpName %merge "merge"
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+OpSelectionMerge %merge None
+OpBranchConditional %cond %then %else
+%then = OpLabel
+OpBranch %merge
+%else = OpLabel
+OpBranch %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MaximalReconvergenceLoopMergeMultiplePredsOk) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+OpBranch %loop
+%loop = OpLabel
+OpLoopMerge %merge %continue None
+OpBranchConditional %cond %merge %continue
+%continue = OpLabel
+OpBranchConditional %cond %loop %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MaximalReconvergenceCaseFallthroughMultiplePredsOk) {
+  const std::string text = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_maximal_reconvergence"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%bool = OpTypeBool
+%cond = OpUndef %bool
+%int = OpTypeInt 32 0
+%val = OpUndef %int
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%main_entry = OpLabel
+OpSelectionMerge %merge None
+OpSwitch %val %merge 0 %case1 1 %case2
+%case1 = OpLabel
+OpBranch %case2
+%case2 = OpLabel
+OpBranch %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_composites_test.cpp b/third_party/SPIRV-Tools/test/val/val_composites_test.cpp
index 0fd1ed6..6e0d7c0 100644
--- a/third_party/SPIRV-Tools/test/val/val_composites_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_composites_test.cpp
@@ -1486,8 +1486,7 @@
 }
 
 TEST_F(ValidateComposites, CoopMatConstantCompositeMismatchFail) {
-  const std::string body =
-      R"(
+  const std::string body = R"(
 OpCapability Shader
 OpCapability Float16
 OpCapability CooperativeMatrixNV
@@ -1525,8 +1524,7 @@
 }
 
 TEST_F(ValidateComposites, CoopMatCompositeConstructMismatchFail) {
-  const std::string body =
-      R"(
+  const std::string body = R"(
 OpCapability Shader
 OpCapability Float16
 OpCapability CooperativeMatrixNV
@@ -1562,6 +1560,86 @@
       HasSubstr("Expected Constituent type to be equal to the component type"));
 }
 
+TEST_F(ValidateComposites, CoopMatKHRConstantCompositeMismatchFail) {
+  const std::string body = R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%bool = OpTypeBool
+%f16 = OpTypeFloat 16
+%f32 = OpTypeFloat 32
+%u32 = OpTypeInt 32 0
+
+%u32_16 = OpConstant %u32 16
+%useA = OpConstant %u32 0
+%subgroup = OpConstant %u32 3
+
+%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useA
+
+%f32_1 = OpConstant %f32 1
+
+%f16mat_1 = OpConstantComposite %f16mat %f32_1
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+
+OpReturn
+OpFunctionEnd)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpConstantComposite Constituent <id> '12[%float_1]' type "
+          "does not match the Result Type <id> '11[%11]'s component type."));
+}
+
+TEST_F(ValidateComposites, CoopMatKHRCompositeConstructMismatchFail) {
+  const std::string body = R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%bool = OpTypeBool
+%f16 = OpTypeFloat 16
+%f32 = OpTypeFloat 32
+%u32 = OpTypeInt 32 0
+
+%u32_16 = OpConstant %u32 16
+%useA = OpConstant %u32 0
+%subgroup = OpConstant %u32 3
+
+%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useA
+
+%f32_1 = OpConstant %f32 1
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+
+%f16mat_1 = OpCompositeConstruct %f16mat %f32_1
+
+OpReturn
+OpFunctionEnd)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Expected Constituent type to be equal to the component type"));
+}
+
 TEST_F(ValidateComposites, ExtractDynamicLabelIndex) {
   const std::string spirv = R"(
 OpCapability Shader
diff --git a/third_party/SPIRV-Tools/test/val/val_conversion_test.cpp b/third_party/SPIRV-Tools/test/val/val_conversion_test.cpp
index 1f8c426..0128aa1 100644
--- a/third_party/SPIRV-Tools/test/val/val_conversion_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_conversion_test.cpp
@@ -1149,8 +1149,7 @@
 }
 
 TEST_F(ValidateConversion, CoopMatConversionShapesMismatchPass) {
-  const std::string body =
-      R"(
+  const std::string body = R"(
 OpCapability Shader
 OpCapability Float16
 OpCapability Int16
@@ -1191,6 +1190,179 @@
   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
+TEST_F(ValidateConversion, CoopMatKHRConversionSuccess) {
+  const std::string body = R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability Int16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%bool = OpTypeBool
+%f16 = OpTypeFloat 16
+%f32 = OpTypeFloat 32
+%u16 = OpTypeInt 16 0
+%u32 = OpTypeInt 32 0
+%s16 = OpTypeInt 16 1
+%s32 = OpTypeInt 32 1
+
+%u32_8 = OpConstant %u32 8
+%use_A = OpConstant %u32 0
+%subgroup = OpConstant %u32 3
+
+%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A
+%f32mat = OpTypeCooperativeMatrixKHR %f32 %subgroup %u32_8 %u32_8 %use_A
+%u16mat = OpTypeCooperativeMatrixKHR %u16 %subgroup %u32_8 %u32_8 %use_A
+%u32mat = OpTypeCooperativeMatrixKHR %u32 %subgroup %u32_8 %u32_8 %use_A
+%s16mat = OpTypeCooperativeMatrixKHR %s16 %subgroup %u32_8 %u32_8 %use_A
+%s32mat = OpTypeCooperativeMatrixKHR %s32 %subgroup %u32_8 %u32_8 %use_A
+
+%f16_1 = OpConstant %f16 1
+%f32_1 = OpConstant %f32 1
+%u16_1 = OpConstant %u16 1
+%u32_1 = OpConstant %u32 1
+%s16_1 = OpConstant %s16 1
+%s32_1 = OpConstant %s32 1
+
+%f16mat_1 = OpConstantComposite %f16mat %f16_1
+%f32mat_1 = OpConstantComposite %f32mat %f32_1
+%u16mat_1 = OpConstantComposite %u16mat %u16_1
+%u32mat_1 = OpConstantComposite %u32mat %u32_1
+%s16mat_1 = OpConstantComposite %s16mat %s16_1
+%s32mat_1 = OpConstantComposite %s32mat %s32_1
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+
+%val11 = OpConvertFToU %u16mat %f16mat_1
+%val12 = OpConvertFToU %u32mat %f16mat_1
+%val13 = OpConvertFToS %s16mat %f16mat_1
+%val14 = OpConvertFToS %s32mat %f16mat_1
+%val15 = OpFConvert %f32mat %f16mat_1
+
+%val21 = OpConvertFToU %u16mat %f32mat_1
+%val22 = OpConvertFToU %u32mat %f32mat_1
+%val23 = OpConvertFToS %s16mat %f32mat_1
+%val24 = OpConvertFToS %s32mat %f32mat_1
+%val25 = OpFConvert %f16mat %f32mat_1
+
+%val31 = OpConvertUToF %f16mat %u16mat_1
+%val32 = OpConvertUToF %f32mat %u16mat_1
+%val33 = OpUConvert %u32mat %u16mat_1
+%val34 = OpSConvert %s32mat %u16mat_1
+
+%val41 = OpConvertSToF %f16mat %s16mat_1
+%val42 = OpConvertSToF %f32mat %s16mat_1
+%val43 = OpUConvert %u32mat %s16mat_1
+%val44 = OpSConvert %s32mat %s16mat_1
+
+OpReturn
+OpFunctionEnd)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateConversion, CoopMatKHRConversionUseMismatchFail) {
+  const std::string body = R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability Int16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%bool = OpTypeBool
+%f16 = OpTypeFloat 16
+%f32 = OpTypeFloat 32
+%u16 = OpTypeInt 16 0
+%u32 = OpTypeInt 32 0
+%s16 = OpTypeInt 16 1
+%s32 = OpTypeInt 32 1
+
+%u32_8 = OpConstant %u32 8
+%u32_4 = OpConstant %u32 4
+%subgroup = OpConstant %u32 3
+%use_A = OpConstant %u32 0
+%use_B = OpConstant %u32 1
+
+%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A
+%f32mat = OpTypeCooperativeMatrixKHR %f32 %subgroup %u32_8 %u32_8 %use_B
+
+%f16_1 = OpConstant %f16 1
+
+%f16mat_1 = OpConstantComposite %f16mat %f16_1
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+
+%val1 = OpFConvert %f32mat %f16mat_1
+
+OpReturn
+OpFunctionEnd)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Expected Use of Matrix type and Result Type to be identical"));
+}
+
+TEST_F(ValidateConversion, CoopMatKHRConversionScopeMismatchFail) {
+  const std::string body = R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability Int16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%bool = OpTypeBool
+%f16 = OpTypeFloat 16
+%f32 = OpTypeFloat 32
+%u16 = OpTypeInt 16 0
+%u32 = OpTypeInt 32 0
+%s16 = OpTypeInt 16 1
+%s32 = OpTypeInt 32 1
+
+%u32_8 = OpConstant %u32 8
+%u32_4 = OpConstant %u32 4
+%subgroup = OpConstant %u32 3
+%workgroup = OpConstant %u32 2
+%use_A = OpConstant %u32 0
+
+%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A
+%f32mat = OpTypeCooperativeMatrixKHR %f32 %workgroup %u32_8 %u32_8 %use_A
+
+%f16_1 = OpConstant %f16 1
+
+%f16mat_1 = OpConstantComposite %f16mat %f16_1
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+
+%val1 = OpFConvert %f32mat %f16mat_1
+
+OpReturn
+OpFunctionEnd)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Expected scopes of Matrix and Result Type to be identical"));
+}
+
 TEST_F(ValidateConversion, BitcastSuccess) {
   const std::string body = R"(
 %ptr = OpVariable %f32ptr_func Function
diff --git a/third_party/SPIRV-Tools/test/val/val_decoration_test.cpp b/third_party/SPIRV-Tools/test/val/val_decoration_test.cpp
index be16aba..ba0e959 100644
--- a/third_party/SPIRV-Tools/test/val/val_decoration_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_decoration_test.cpp
@@ -3209,6 +3209,48 @@
           "statically used per shader entry point."));
 }
 
+TEST_F(ValidateDecorations,
+       VulkanMultiplePushConstantsSingleEntryPointInterfaceBad) {
+  std::string spirv = R"(
+            OpCapability Shader
+            OpMemoryModel Logical GLSL450
+            OpEntryPoint Vertex %func1 "func1" %pc1 %pc2
+            OpDecorate %struct Block
+            OpMemberDecorate %struct 0 Offset 0
+    %void = OpTypeVoid
+  %voidfn = OpTypeFunction %void
+   %float = OpTypeFloat 32
+     %int = OpTypeInt 32 0
+   %int_0 = OpConstant %int 0
+  %struct = OpTypeStruct %float
+     %ptr = OpTypePointer PushConstant %struct
+%ptr_float = OpTypePointer PushConstant %float
+     %pc1 = OpVariable %ptr PushConstant
+     %pc2 = OpVariable %ptr PushConstant
+   %func1 = OpFunction %void None %voidfn
+  %label1 = OpLabel
+ %access1 = OpAccessChain %ptr_float %pc1 %int_0
+   %load1 = OpLoad %float %access1
+            OpReturn
+            OpFunctionEnd
+   %func2 = OpFunction %void None %voidfn
+  %label2 = OpLabel
+ %access2 = OpAccessChain %ptr_float %pc2 %int_0
+   %load2 = OpLoad %float %access2
+            OpReturn
+            OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpVariable-06673"));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Entry-point has more than one variable with the "
+                        "PushConstant storage class in the interface"));
+}
+
 TEST_F(ValidateDecorations, VulkanUniformMissingDescriptorSetBad) {
   std::string spirv = R"(
             OpCapability Shader
@@ -8003,6 +8045,7 @@
                OpCapability Shader
                OpCapability Float16
                OpCapability Int16
+               OpCapability WorkgroupMemoryExplicitLayoutKHR
                OpCapability WorkgroupMemoryExplicitLayout16BitAccessKHR
                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
                OpMemoryModel Logical GLSL450
@@ -8265,6 +8308,37 @@
                 "member 0 at offset 1 is not aligned to 4"));
 }
 
+TEST_F(ValidateDecorations, WorkgroupBlockNoCapability) {
+  std::string spirv = R"(
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main" %_
+               OpExecutionMode %main LocalSize 1 1 1
+               OpMemberDecorate %struct 0 Offset 0
+               OpMemberDecorate %struct 1 Offset 4
+               OpDecorate %struct Block
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+     %struct = OpTypeStruct %int %int
+%ptr_workgroup = OpTypePointer Workgroup %struct
+          %_ = OpVariable %ptr_workgroup Workgroup
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+            ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1_SPIRV_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "Workgroup Storage Class variables can't be decorated with Block "
+          "unless declaring the WorkgroupMemoryExplicitLayoutKHR capability"));
+}
+
 TEST_F(ValidateDecorations, BadMatrixStrideUniform) {
   const std::string spirv = R"(
 OpCapability Shader
@@ -9252,6 +9326,124 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
 }
 
+TEST_F(ValidateDecorations, PhysicalStorageBufferWithOffset) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability Int64
+OpCapability PhysicalStorageBufferAddresses
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint GLCompute %main "main" %pc
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %pc_block Block
+OpMemberDecorate %pc_block 0 Offset 0
+OpMemberDecorate %pssbo_struct 0 Offset 0
+%void = OpTypeVoid
+%long = OpTypeInt 64 0
+%float = OpTypeFloat 32
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%pc_block = OpTypeStruct %long
+%pc_block_ptr = OpTypePointer PushConstant %pc_block
+%pc_long_ptr = OpTypePointer PushConstant %long
+%pc = OpVariable %pc_block_ptr PushConstant
+%pssbo_struct = OpTypeStruct %float
+%pssbo_ptr = OpTypePointer PhysicalStorageBuffer %pssbo_struct
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%pc_gep = OpAccessChain %pc_long_ptr %pc %int_0
+%addr = OpLoad %long %pc_gep
+%ptr = OpConvertUToPtr %pssbo_ptr %addr
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
+TEST_F(ValidateDecorations, PhysicalStorageBufferMissingOffset) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability Int64
+OpCapability PhysicalStorageBufferAddresses
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint GLCompute %main "main" %pc
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %pc_block Block
+OpMemberDecorate %pc_block 0 Offset 0
+%void = OpTypeVoid
+%long = OpTypeInt 64 0
+%float = OpTypeFloat 32
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%pc_block = OpTypeStruct %long
+%pc_block_ptr = OpTypePointer PushConstant %pc_block
+%pc_long_ptr = OpTypePointer PushConstant %long
+%pc = OpVariable %pc_block_ptr PushConstant
+%pssbo_struct = OpTypeStruct %float
+%pssbo_ptr = OpTypePointer PhysicalStorageBuffer %pssbo_struct
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%pc_gep = OpAccessChain %pc_long_ptr %pc %int_0
+%addr = OpLoad %long %pc_gep
+%ptr = OpConvertUToPtr %pssbo_ptr %addr
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("decorated as Block for variable in PhysicalStorageBuffer "
+                "storage class must follow relaxed storage buffer layout "
+                "rules: member 0 is missing an Offset decoration"));
+}
+
+TEST_F(ValidateDecorations, PhysicalStorageBufferMissingArrayStride) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability Int64
+OpCapability PhysicalStorageBufferAddresses
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint GLCompute %main "main" %pc
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %pc_block Block
+OpMemberDecorate %pc_block 0 Offset 0
+%void = OpTypeVoid
+%long = OpTypeInt 64 0
+%float = OpTypeFloat 32
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_4 = OpConstant %int 4
+%pc_block = OpTypeStruct %long
+%pc_block_ptr = OpTypePointer PushConstant %pc_block
+%pc_long_ptr = OpTypePointer PushConstant %long
+%pc = OpVariable %pc_block_ptr PushConstant
+%pssbo_array = OpTypeArray %float %int_4
+%pssbo_ptr = OpTypePointer PhysicalStorageBuffer %pssbo_array
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%pc_gep = OpAccessChain %pc_long_ptr %pc %int_0
+%addr = OpLoad %long %pc_gep
+%ptr = OpConvertUToPtr %pssbo_ptr %addr
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "decorated as Block for variable in PhysicalStorageBuffer storage "
+          "class must follow relaxed storage buffer layout rules: member 0 "
+          "contains an array with stride 0, but with an element size of 4"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_ext_inst_debug_test.cpp b/third_party/SPIRV-Tools/test/val/val_ext_inst_debug_test.cpp
index 554e78b..8f0da42 100644
--- a/third_party/SPIRV-Tools/test/val/val_ext_inst_debug_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_ext_inst_debug_test.cpp
@@ -1012,9 +1012,9 @@
   CompileSuccessfully(GenerateShaderCodeForDebugInfo(
       src, size_const, dbg_inst_header, "", extension, "Vertex"));
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
-  EXPECT_THAT(getDiagnosticString(),
-              HasSubstr("expected operand Base Type must be a result id of "
-                        "DebugTypeBasic"));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("expected operand Base Type is not a valid debug type"));
 }
 
 TEST_F(ValidateOpenCL100DebugInfo, DebugTypeQualifier) {
@@ -1077,9 +1077,9 @@
   CompileSuccessfully(GenerateShaderCodeForDebugInfo(
       src, size_const, dbg_inst_header, "", extension, "Vertex"));
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
-  EXPECT_THAT(getDiagnosticString(),
-              HasSubstr("expected operand Base Type must be a result id of "
-                        "DebugTypeBasic"));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("expected operand Base Type is not a valid debug type"));
 }
 TEST_F(ValidateVulkan100DebugInfo, DebugTypeQualifier) {
   const std::string src = R"(
@@ -1147,9 +1147,9 @@
   CompileSuccessfully(GenerateShaderCodeForDebugInfo(
       src, constants, dbg_inst_header, "", extension, "Vertex"));
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
-  EXPECT_THAT(getDiagnosticString(),
-              HasSubstr("expected operand Base Type must be a result id of "
-                        "DebugTypeBasic"));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("expected operand Base Type is not a valid debug type"));
 }
 
 TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArray) {
diff --git a/third_party/SPIRV-Tools/test/val/val_extension_spv_nv_raw_access_chains.cpp b/third_party/SPIRV-Tools/test/val/val_extension_spv_nv_raw_access_chains.cpp
new file mode 100644
index 0000000..f06d7cd
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/val/val_extension_spv_nv_raw_access_chains.cpp
@@ -0,0 +1,510 @@
+// Copyright (c) 2024 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "source/spirv_target_env.h"
+#include "test/unit_spirv.h"
+#include "test/val/val_fixtures.h"
+
+namespace spvtools {
+namespace val {
+namespace {
+
+using ::testing::HasSubstr;
+
+using ValidateSpvNVRawAccessChains = spvtest::ValidateBase<bool>;
+
+TEST_F(ValidateSpvNVRawAccessChains, Valid) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %intPtr = OpTypePointer StorageBuffer %int
+
+    %int_0 = OpConstant %int 0
+    %int_16 = OpConstant %int 16
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, NoCapability) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %intPtr = OpTypePointer StorageBuffer %int
+
+    %int_0 = OpConstant %int 0
+    %int_16 = OpConstant %int 16
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("requires one of these capabilities: RawAccessChainsNV"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, NoExtension) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %intPtr = OpTypePointer StorageBuffer %int
+
+    %int_0 = OpConstant %int 0
+    %int_16 = OpConstant %int 16
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("requires one of these extensions: SPV_NV_raw_access_chains"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, ReturnTypeNotPointer) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+
+    %int_0 = OpConstant %int 0
+    %int_16 = OpConstant %int 16
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %int %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("must be OpTypePointer. Found OpTypeInt"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, Workgroup) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+
+    %int = OpTypeInt 32 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer Workgroup %intStruct
+    %ssbo = OpVariable %intStructPtr Workgroup
+    %intPtr = OpTypePointer Workgroup %int
+
+    %int_0 = OpConstant %int 0
+    %int_16 = OpConstant %int 16
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("must point to a storage class of"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, ReturnTypeArray) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %int_1 = OpConstant %int 1
+    %intArray = OpTypeArray %int %int_1
+    %intArrayPtr = OpTypePointer StorageBuffer %intArray
+
+    %int_0 = OpConstant %int 0
+    %int_16 = OpConstant %int 16
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intArrayPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("must not point to"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, VariableStride) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %intPtr = OpTypePointer StorageBuffer %int
+
+    %int_0 = OpConstant %int 0
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %stride = OpIAdd %int %int_0 %int_0
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %stride %int_0 %int_0 RobustnessPerComponentNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("must be OpConstant"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, RobustnessPerElementZeroStride) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %intPtr = OpTypePointer StorageBuffer %int
+
+    %int_0 = OpConstant %int 0
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_0 %int_0 %int_0 RobustnessPerElementNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Stride must not be zero when per-element robustness is used"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, BothRobustness) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %intPtr = OpTypePointer StorageBuffer %int
+
+    %int_0 = OpConstant %int 0
+    %int_16 = OpConstant %int 16
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerElementNV|RobustnessPerComponentNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Per-component robustness and per-element robustness "
+                        "are mutually exclusive"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, StrideFloat) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %float = OpTypeFloat 32
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %intPtr = OpTypePointer StorageBuffer %int
+
+    %int_0 = OpConstant %int 0
+    %float_16 = OpConstant %float 16
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %float_16 %int_0 %int_0 RobustnessPerComponentNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("must be OpTypeInt"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, IndexType) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpCapability Int64
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %long = OpTypeInt 64 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %intPtr = OpTypePointer StorageBuffer %int
+
+    %int_0 = OpConstant %int 0
+    %int_16 = OpConstant %int 16
+    %long_0 = OpConstant %long 0
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %long_0 %int_0 RobustnessPerComponentNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("The integer width of Index"));
+}
+
+TEST_F(ValidateSpvNVRawAccessChains, OffsetType) {
+  const std::string str = R"(
+    OpCapability Shader
+    OpCapability RawAccessChainsNV
+    OpCapability Int64
+    OpExtension "SPV_KHR_storage_buffer_storage_class"
+    OpExtension "SPV_NV_raw_access_chains"
+    OpMemoryModel Logical GLSL450
+
+    OpEntryPoint GLCompute %main "main"
+    OpExecutionMode %main LocalSize 1 1 1
+
+    OpDecorate %intStruct Block
+    OpMemberDecorate %intStruct 0 Offset 0
+    OpDecorate %ssbo DescriptorSet 0
+    OpDecorate %ssbo Binding 0
+
+    %int = OpTypeInt 32 1
+    %long = OpTypeInt 64 1
+    %void = OpTypeVoid
+    %mainFunctionType = OpTypeFunction %void
+    %intStruct = OpTypeStruct %int
+    %intStructPtr = OpTypePointer StorageBuffer %intStruct
+    %ssbo = OpVariable %intStructPtr StorageBuffer
+    %intPtr = OpTypePointer StorageBuffer %int
+
+    %int_0 = OpConstant %int 0
+    %int_16 = OpConstant %int 16
+    %long_0 = OpConstant %long 0
+
+    %main = OpFunction %void None %mainFunctionType
+    %label = OpLabel
+    %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %long_0 RobustnessPerComponentNV
+    %unused = OpLoad %int %rawChain
+    OpReturn
+    OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("The integer width of Offset"));
+}
+
+}  // namespace
+}  // namespace val
+}  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_extensions_test.cpp b/third_party/SPIRV-Tools/test/val/val_extensions_test.cpp
index 0ab8c6e..932bbee 100644
--- a/third_party/SPIRV-Tools/test/val/val_extensions_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_extensions_test.cpp
@@ -131,6 +131,214 @@
   EXPECT_THAT(getDiagnosticString(), HasSubstr("SPV_KHR_device_group"));
 }
 
+TEST_F(ValidateExtensionCapabilities,
+       DeclCapabilityFailureBlockMatchWIndowSAD) {
+  const std::string str = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %v_texcoord %fragColor %target_samp %ref_samp
+               OpExecutionMode %main OriginUpperLeft
+               OpSource GLSL 450
+               OpSourceExtension "GL_QCOM_image_processing"
+               OpSourceExtension "GL_QCOM_image_processing2"
+               OpName %main "main"
+               OpName %tgt_coords "tgt_coords"
+               OpName %v_texcoord "v_texcoord"
+               OpName %ref_coords "ref_coords"
+               OpName %blockSize "blockSize"
+               OpName %fragColor "fragColor"
+               OpName %target_samp "target_samp"
+               OpName %ref_samp "ref_samp"
+               OpDecorate %v_texcoord Location 0
+               OpDecorate %fragColor Location 0
+               OpDecorate %target_samp DescriptorSet 0
+               OpDecorate %target_samp Binding 4
+               OpDecorate %ref_samp DescriptorSet 0
+               OpDecorate %ref_samp Binding 5
+               OpDecorate %target_samp BlockMatchTextureQCOM
+               OpDecorate %target_samp BlockMatchSamplerQCOM
+               OpDecorate %ref_samp BlockMatchTextureQCOM
+               OpDecorate %ref_samp BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %v_texcoord = OpVariable %_ptr_Input_v4float Input
+     %uint_0 = OpConstant %uint 0
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+     %uint_4 = OpConstant %uint 4
+         %39 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %fragColor = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %43 = OpTypeSampledImage %42
+%_ptr_UniformConstant_43 = OpTypePointer UniformConstant %43
+%target_samp = OpVariable %_ptr_UniformConstant_43 UniformConstant
+   %ref_samp = OpVariable %_ptr_UniformConstant_43 UniformConstant
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+ %tgt_coords = OpVariable %_ptr_Function_v2uint Function
+ %ref_coords = OpVariable %_ptr_Function_v2uint Function
+  %blockSize = OpVariable %_ptr_Function_v2uint Function
+         %16 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_0
+         %17 = OpLoad %float %16
+         %18 = OpConvertFToU %uint %17
+         %20 = OpAccessChain %_ptr_Function_uint %tgt_coords %uint_0
+               OpStore %20 %18
+         %22 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_1
+         %23 = OpLoad %float %22
+         %24 = OpConvertFToU %uint %23
+         %25 = OpAccessChain %_ptr_Function_uint %tgt_coords %uint_0
+               OpStore %25 %24
+         %28 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_2
+         %29 = OpLoad %float %28
+         %30 = OpConvertFToU %uint %29
+         %31 = OpAccessChain %_ptr_Function_uint %ref_coords %uint_0
+               OpStore %31 %30
+         %33 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_3
+         %34 = OpLoad %float %33
+         %35 = OpConvertFToU %uint %34
+         %36 = OpAccessChain %_ptr_Function_uint %ref_coords %uint_1
+               OpStore %36 %35
+               OpStore %blockSize %39
+         %46 = OpLoad %43 %target_samp
+         %47 = OpLoad %v2uint %tgt_coords
+         %49 = OpLoad %43 %ref_samp
+         %50 = OpLoad %v2uint %ref_coords
+         %51 = OpLoad %v2uint %blockSize
+         %52 = OpImageBlockMatchWindowSADQCOM %v4float %46 %47 %49 %50 %51
+               OpStore %fragColor %52
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("2nd operand of Decorate"));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("requires one of these extensions"));
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("SPV_QCOM_image_processing"));
+}
+
+TEST_F(ValidateExtensionCapabilities,
+       DeclCapabilityFailureBlockMatchWIndowSSD) {
+  const std::string str = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %v_texcoord %fragColor %tex2D_src1 %samp %tex2D_src2
+               OpExecutionMode %main OriginUpperLeft
+               OpSource GLSL 450
+               OpSourceExtension "GL_QCOM_image_processing"
+               OpSourceExtension "GL_QCOM_image_processing2"
+               OpName %main "main"
+               OpName %tgt_coords "tgt_coords"
+               OpName %v_texcoord "v_texcoord"
+               OpName %ref_coords "ref_coords"
+               OpName %blockSize "blockSize"
+               OpName %fragColor "fragColor"
+               OpName %tex2D_src1 "tex2D_src1"
+               OpName %samp "samp"
+               OpName %tex2D_src2 "tex2D_src2"
+               OpDecorate %v_texcoord Location 0
+               OpDecorate %fragColor Location 0
+               OpDecorate %tex2D_src1 DescriptorSet 0
+               OpDecorate %tex2D_src1 Binding 1
+               OpDecorate %samp DescriptorSet 0
+               OpDecorate %samp Binding 3
+               OpDecorate %tex2D_src2 DescriptorSet 0
+               OpDecorate %tex2D_src2 Binding 2
+               OpDecorate %tex2D_src1 BlockMatchTextureQCOM
+               OpDecorate %samp BlockMatchSamplerQCOM
+               OpDecorate %tex2D_src2 BlockMatchTextureQCOM
+               OpDecorate %samp BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %v_texcoord = OpVariable %_ptr_Input_v4float Input
+     %uint_0 = OpConstant %uint 0
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+     %uint_4 = OpConstant %uint 4
+         %39 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %fragColor = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %tex2D_src1 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %samp = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %tex2D_src2 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+ %tgt_coords = OpVariable %_ptr_Function_v2uint Function
+ %ref_coords = OpVariable %_ptr_Function_v2uint Function
+  %blockSize = OpVariable %_ptr_Function_v2uint Function
+         %16 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_0
+         %17 = OpLoad %float %16
+         %18 = OpConvertFToU %uint %17
+         %20 = OpAccessChain %_ptr_Function_uint %tgt_coords %uint_0
+               OpStore %20 %18
+         %22 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_1
+         %23 = OpLoad %float %22
+         %24 = OpConvertFToU %uint %23
+         %25 = OpAccessChain %_ptr_Function_uint %tgt_coords %uint_0
+               OpStore %25 %24
+         %28 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_2
+         %29 = OpLoad %float %28
+         %30 = OpConvertFToU %uint %29
+         %31 = OpAccessChain %_ptr_Function_uint %ref_coords %uint_0
+               OpStore %31 %30
+         %33 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_3
+         %34 = OpLoad %float %33
+         %35 = OpConvertFToU %uint %34
+         %36 = OpAccessChain %_ptr_Function_uint %ref_coords %uint_1
+               OpStore %36 %35
+               OpStore %blockSize %39
+         %45 = OpLoad %42 %tex2D_src1
+         %49 = OpLoad %46 %samp
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %tgt_coords
+         %54 = OpLoad %42 %tex2D_src2
+         %55 = OpLoad %46 %samp
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %ref_coords
+         %58 = OpLoad %v2uint %blockSize
+         %59 = OpImageBlockMatchWindowSSDQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %fragColor %59
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("2nd operand of Decorate"));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("requires one of these extensions"));
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("SPV_QCOM_image_processing"));
+}
+
 using ValidateAMDShaderBallotCapabilities = spvtest::ValidateBase<std::string>;
 
 // Returns a vector of strings for the prefix of a SPIR-V assembly shader
diff --git a/third_party/SPIRV-Tools/test/val/val_id_test.cpp b/third_party/SPIRV-Tools/test/val/val_id_test.cpp
index 3666f38..cc29736 100644
--- a/third_party/SPIRV-Tools/test/val/val_id_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_id_test.cpp
@@ -1056,7 +1056,7 @@
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
   EXPECT_THAT(getDiagnosticString(),
               HasSubstr(make_message("OpTypeArray Length <id> '2[%2]' default "
-                                     "value must be at least 1.")));
+                                     "value must be at least 1: found 0")));
 }
 
 TEST_P(ValidateIdWithMessage, OpTypeArrayLengthSpecConst) {
@@ -2317,7 +2317,7 @@
           "be used with non-externally visible shader Storage Classes: "
           "Workgroup, CrossWorkgroup, Private, Function, Input, Output, "
           "RayPayloadKHR, IncomingRayPayloadKHR, HitAttributeKHR, "
-          "CallableDataKHR, or IncomingCallableDataKHR")));
+          "CallableDataKHR, IncomingCallableDataKHR, or UniformConstant")));
 }
 
 TEST_P(ValidateIdWithMessage, OpVariableContainsBoolPrivateGood) {
@@ -2339,6 +2339,25 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
+TEST_P(ValidateIdWithMessage, OpVariableContainsBoolUniformConstantGood) {
+  std::string spirv = kGLSL450MemoryModel + R"(
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%block = OpTypeStruct %bool %int
+%_ptr_UniformConstant_block = OpTypePointer UniformConstant %block
+%var = OpVariable %_ptr_UniformConstant_block UniformConstant
+%void = OpTypeVoid
+%fnty = OpTypeFunction %void
+%main = OpFunction %void None %fnty
+%entry = OpLabel
+%load = OpLoad %block %var
+OpReturn
+OpFunctionEnd
+)";
+  CompileSuccessfully(spirv.c_str());
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
 TEST_P(ValidateIdWithMessage, OpVariableContainsBoolPointerGood) {
   std::string spirv = kGLSL450MemoryModel + R"(
 %bool = OpTypeBool
@@ -4206,7 +4225,7 @@
 OpFunctionEnd
   )";
   const std::string expected_err = "Index is out of bounds: " + instr +
-                                   " can not find index 3 into the structure "
+                                   " cannot find index 3 into the structure "
                                    "<id> '25[%_struct_25]'. This structure "
                                    "has 3 members. Largest valid index is 2.";
   CompileSuccessfully(spirv);
diff --git a/third_party/SPIRV-Tools/test/val/val_image_test.cpp b/third_party/SPIRV-Tools/test/val/val_image_test.cpp
index aa335c8..77b042f 100644
--- a/third_party/SPIRV-Tools/test/val/val_image_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_image_test.cpp
@@ -786,6 +786,21 @@
               HasSubstr("Dim SubpassData requires Arrayed to be 0"));
 }
 
+TEST_F(ValidateImage, TypeImageDimRectVulkan) {
+  const std::string code = GetShaderHeader("OpCapability InputAttachment\n") +
+                           R"(
+%img_type = OpTypeImage %f32 Rect 0 1 0 2 Unknown
+)" + TrivialMain();
+
+  CompileSuccessfully(code.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
+            ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  // Can't actually hit VUID-StandaloneSpirv-OpTypeImage-09638
+  EXPECT_THAT(
+      getDiagnosticString(),
+      AnyVUID("TypeImage requires one of these capabilities: SampledRect"));
+}
+
 TEST_F(ValidateImage, TypeImageWrongSampledTypeForTileImageDataEXT) {
   const std::string code = GetShaderHeader(
                                "OpCapability TileImageColorReadAccessEXT\n"
@@ -2177,8 +2192,6 @@
   CompileSuccessfully(
       GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_VULKAN_1_0).c_str());
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
-  EXPECT_THAT(getDiagnosticString(),
-              AnyVUID("VUID-StandaloneSpirv-Offset-04662"));
   EXPECT_THAT(
       getDiagnosticString(),
       HasSubstr("Image Operands Offset, ConstOffset, ConstOffsets, Offsets "
@@ -5854,10 +5867,12 @@
 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 SignExtend
 )";
 
-  EXPECT_THAT(CompileFailure(GenerateShaderCode(body, "", "Fragment", "",
-                                                SPV_ENV_UNIVERSAL_1_3),
-                             SPV_ENV_UNIVERSAL_1_3, SPV_ERROR_WRONG_VERSION),
-              HasSubstr("Invalid image operand 'SignExtend'"));
+  CompileSuccessfully(
+      GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_UNIVERSAL_1_3));
+  ASSERT_EQ(SPV_ERROR_WRONG_VERSION, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("SignExtend(4096) requires SPIR-V version 1.4 or later"));
 }
 
 TEST_F(ValidateImage, ZeroExtendV13Bad) {
@@ -5866,10 +5881,12 @@
 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 ZeroExtend
 )";
 
-  EXPECT_THAT(CompileFailure(GenerateShaderCode(body, "", "Fragment", "",
-                                                SPV_ENV_UNIVERSAL_1_3),
-                             SPV_ENV_UNIVERSAL_1_3, SPV_ERROR_WRONG_VERSION),
-              HasSubstr("Invalid image operand 'ZeroExtend'"));
+  CompileSuccessfully(
+      GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_UNIVERSAL_1_3));
+  ASSERT_EQ(SPV_ERROR_WRONG_VERSION, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("ZeroExtend(8192) requires SPIR-V version 1.4 or later"));
 }
 
 TEST_F(ValidateImage, SignExtendScalarUIntTexelV14Good) {
@@ -6675,6 +6692,3961 @@
       HasSubstr("OpSamplerImageAddressingModeNV bitwidth should be 64 or 32"));
 }
 
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationA) {
+  std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpExtension "SPV_QCOM_image_processing"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchSADQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationB) {
+  std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpExtension "SPV_QCOM_image_processing"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %5 BlockMatchTextureQCOM
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchSADQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationC) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchSADQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationD) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchSADQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationA) {
+  std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpExtension "SPV_QCOM_image_processing"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchSSDQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationB) {
+  std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpExtension "SPV_QCOM_image_processing"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %5 BlockMatchTextureQCOM
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchSSDQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationC) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchSSDQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationD) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchSSDQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedNoDecorationA) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureSampleWeightedQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 %7
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 1
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 3
+               OpDecorate %6 Location 0
+               OpDecorate %7 DescriptorSet 0
+               OpDecorate %7 Binding 0
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %13 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+          %4 = OpVariable %_ptr_UniformConstant_13 UniformConstant
+         %15 = OpTypeSampler
+%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
+          %5 = OpVariable %_ptr_UniformConstant_15 UniformConstant
+         %17 = OpTypeSampledImage %13
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %6 = OpVariable %_ptr_Input_v4float Input
+    %v2float = OpTypeVector %float 2
+         %20 = OpTypeImage %float 2D 0 1 0 1 Unknown
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %7 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+         %22 = OpTypeSampledImage %20
+%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17
+          %2 = OpFunction %void None %9
+         %24 = OpLabel
+         %25 = OpLoad %13 %4
+         %26 = OpLoad %15 %5
+         %27 = OpSampledImage %17 %25 %26
+         %28 = OpLoad %v4float %6
+         %29 = OpVectorShuffle %v2float %28 %28 0 1
+         %30 = OpLoad %20 %7
+         %31 = OpLoad %15 %5
+         %32 = OpSampledImage %22 %30 %31
+         %33 = OpImageSampleWeightedQCOM %v4float %27 %29 %32
+               OpStore %3 %33
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration WeightTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedNoDecorationB) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureSampleWeightedQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %12 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
+         %14 = OpTypeSampler
+%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
+         %16 = OpTypeSampledImage %12
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %4 = OpVariable %_ptr_Input_v4float Input
+    %v2float = OpTypeVector %float 2
+         %19 = OpTypeImage %float 2D 0 1 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+         %21 = OpTypeSampledImage %19
+%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16
+          %5 = OpVariable %_ptr_UniformConstant_16 UniformConstant
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+          %6 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpLoad %16 %5
+         %26 = OpLoad %v4float %4
+         %27 = OpVectorShuffle %v2float %26 %26 0 1
+         %28 = OpLoad %21 %6
+         %29 = OpImageSampleWeightedQCOM %v4float %25 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration WeightTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchWindowSADInvalidUseA) {
+  std::string text = R"(
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 11
+; Bound: 79
+; Schema: 0
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchSADQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %102
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADInvalidUseB) {
+  std::string text = R"(
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 11
+; Bound: 79
+; Schema: 0
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchSADQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %104
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADInvalidUseC) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchSADQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %5
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADInvalidUseD) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchSADQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %6
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDInvalidUseA) {
+  std::string text = R"(
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 11
+; Bound: 79
+; Schema: 0
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchSSDQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %102
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDInvalidUseB) {
+  std::string text = R"(
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 11
+; Bound: 79
+; Schema: 0
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchSSDQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %104
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDInvalidUseC) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchSSDQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %5
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDInvalidUseD) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchSSDQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %6
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedInvalidUseA) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureSampleWeightedQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %6 WeightTextureQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %12 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
+         %14 = OpTypeSampledImage %12
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %4 = OpVariable %_ptr_Input_v4float Input
+    %v2float = OpTypeVector %float 2
+         %17 = OpTypeImage %float 2D 0 1 0 1 Unknown
+%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17
+         %19 = OpTypeSampledImage %17
+%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
+          %5 = OpVariable %_ptr_UniformConstant_14 UniformConstant
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %v3float = OpTypeVector %float 3
+          %2 = OpFunction %void None %8
+         %23 = OpLabel
+         %24 = OpLoad %v4float %4
+         %25 = OpVectorShuffle %v2float %24 %24 0 1
+         %26 = OpLoad %14 %5
+         %27 = OpLoad %v4float %4
+         %28 = OpVectorShuffle %v2float %27 %27 0 1
+         %29 = OpLoad %19 %6
+         %30 = OpImageSampleWeightedQCOM %v4float %26 %28 %29
+               OpStore %3 %30
+         %31 = OpLoad %19 %6
+         %32 = OpLoad %v4float %4
+         %33 = OpVectorShuffle %v3float %32 %32 0 1 0
+         %34 = OpCompositeExtract %float %33 0
+         %35 = OpCompositeExtract %float %33 1
+         %36 = OpCompositeExtract %float %33 2
+         %37 = OpCompositeConstruct %v3float %34 %35 %36
+         %38 = OpImageSampleImplicitLod %v4float %31 %37
+               OpStore %3 %38
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedInvalidUseB) {
+  std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureSampleWeightedQCOM
+               OpExtension "SPV_QCOM_image_processing"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 %7
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 1
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 3
+               OpDecorate %4 Location 0
+               OpDecorate %7 DescriptorSet 0
+               OpDecorate %7 Binding 0
+               OpDecorate %7 WeightTextureQCOM
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %13 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+          %5 = OpVariable %_ptr_UniformConstant_13 UniformConstant
+         %15 = OpTypeSampler
+%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
+          %6 = OpVariable %_ptr_UniformConstant_15 UniformConstant
+         %17 = OpTypeSampledImage %13
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %4 = OpVariable %_ptr_Input_v4float Input
+    %v2float = OpTypeVector %float 2
+         %20 = OpTypeImage %float 2D 0 1 0 1 Unknown
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %7 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+         %22 = OpTypeSampledImage %20
+    %v3float = OpTypeVector %float 3
+          %2 = OpFunction %void None %9
+         %24 = OpLabel
+         %25 = OpLoad %13 %5
+         %26 = OpLoad %15 %6
+         %27 = OpSampledImage %17 %25 %26
+         %28 = OpLoad %v4float %4
+         %29 = OpVectorShuffle %v2float %28 %28 0 1
+         %30 = OpLoad %20 %7
+         %31 = OpLoad %15 %6
+         %32 = OpSampledImage %22 %30 %31
+         %33 = OpImageSampleWeightedQCOM %v4float %27 %29 %32
+               OpStore %3 %33
+         %34 = OpLoad %20 %7
+         %35 = OpLoad %15 %6
+         %36 = OpSampledImage %22 %34 %35
+         %37 = OpLoad %v4float %4
+         %38 = OpVectorShuffle %v3float %37 %37 0 1 0
+         %39 = OpCompositeExtract %float %38 0
+         %40 = OpCompositeExtract %float %38 1
+         %41 = OpCompositeExtract %float %38 2
+         %42 = OpCompositeConstruct %v3float %39 %40 %41
+         %43 = OpImageSampleImplicitLod %v4float %36 %42
+               OpStore %3 %43
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorTargetIT) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchSamplerQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %5 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchWindowSADQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorTargetIS) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %5 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchWindowSADQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchSamplerQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorRefIT) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %4 BlockMatchSamplerQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchWindowSADQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorRefIS) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %4 BlockMatchSamplerQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchWindowSADQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchSamplerQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorTargetNIT) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchSamplerQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+           OpDecorate %6 BlockMatchSamplerQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchWindowSADQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorTargetNIS) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchTextureQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+           OpDecorate %6 BlockMatchSamplerQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchWindowSADQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchSamplerQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorRefNIT) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchTextureQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %5 BlockMatchSamplerQCOM
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchSamplerQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchWindowSADQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorRefNIS) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchTextureQCOM
+           OpDecorate %4 BlockMatchSamplerQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchWindowSADQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchSamplerQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorTargetIT) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchSamplerQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %5 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchWindowSSDQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorTargetIS) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %5 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchWindowSSDQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchSamplerQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorRefIT) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %4 BlockMatchSamplerQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchWindowSSDQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorRefIS) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %4 BlockMatchSamplerQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchWindowSSDQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchSamplerQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorTargetNIT) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchSamplerQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+           OpDecorate %6 BlockMatchSamplerQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchWindowSSDQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorTargetNIS) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchTextureQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+           OpDecorate %6 BlockMatchSamplerQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchWindowSSDQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchSamplerQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorRefNIT) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchTextureQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %5 BlockMatchSamplerQCOM
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchSamplerQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchWindowSSDQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorRefNIS) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchTextureQCOM
+           OpDecorate %4 BlockMatchSamplerQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchWindowSSDQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchSamplerQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADNoDecorTargetIT) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchGatherSADQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADNoDecorRefIT) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchGatherSADQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADNoDecorTargetNIT) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchGatherSADQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADNoDecorRefNIT) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchTextureQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchGatherSADQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDNoDecorTargetIT) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchGatherSSDQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDNoDecorRefIT) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 DescriptorSet 0
+               OpDecorate %4 Binding 4
+               OpDecorate %4 BlockMatchTextureQCOM
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 5
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %3 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+         %19 = OpTypeSampledImage %18
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+          %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+          %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %21 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %7
+         %22 = OpLabel
+         %23 = OpVariable %_ptr_Function_v2uint Function
+         %24 = OpLoad %19 %4
+         %25 = OpLoad %v2uint %23
+         %26 = OpLoad %19 %5
+         %27 = OpLoad %v2uint %23
+         %28 = OpLoad %v2uint %23
+         %29 = OpImageBlockMatchGatherSSDQCOM %v4float %24 %25 %26 %27 %28
+               OpStore %3 %29
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDNoDecorTargetNIT) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+           OpDecorate %6 BlockMatchTextureQCOM
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchGatherSSDQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDNoDecorRefNIT) {
+  const std::string text = R"(
+           OpCapability Shader
+           OpCapability TextureBlockMatchQCOM
+           OpCapability TextureBlockMatch2QCOM
+           OpExtension "SPV_QCOM_image_processing"
+           OpExtension "SPV_QCOM_image_processing2"
+      %1 = OpExtInstImport "GLSL.std.450"
+           OpMemoryModel Logical GLSL450
+           OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+           OpExecutionMode %2 OriginUpperLeft
+           OpDecorate %3 Location 0
+           OpDecorate %4 DescriptorSet 0
+           OpDecorate %4 Binding 1
+           OpDecorate %4 BlockMatchTextureQCOM
+           OpDecorate %5 DescriptorSet 0
+           OpDecorate %5 Binding 3
+           OpDecorate %6 DescriptorSet 0
+           OpDecorate %6 Binding 2
+   %void = OpTypeVoid
+      %8 = OpTypeFunction %void
+   %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+  %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_4 = OpConstant %uint 4
+    %17 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %3 = OpVariable %_ptr_Output_v4float Output
+    %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+     %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+    %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant
+   %23 = OpTypeSampledImage %19
+    %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+    %2 = OpFunction %void None %8
+   %24 = OpLabel
+   %25 = OpVariable %_ptr_Function_v2uint Function
+   %26 = OpLoad %19 %4
+   %27 = OpLoad %21 %5
+   %28 = OpSampledImage %23 %26 %27
+   %29 = OpLoad %v2uint %25
+   %30 = OpLoad %19 %6
+   %31 = OpLoad %21 %5
+   %32 = OpSampledImage %23 %30 %31
+   %33 = OpImageBlockMatchGatherSSDQCOM %v4float %28 %29 %32 %29 %29
+         OpStore %3 %33
+         OpReturn
+         OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Missing decoration BlockMatchTextureQCOM"));
+}
+
+TEST_F(ValidateImage,
+       QCOMImageProcessing2BlockMatchWindowSADInvalidUseTargetI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %5 BlockMatchSamplerQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchWindowSADQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %5
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADInvalidUseRefI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %5 BlockMatchSamplerQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchWindowSADQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %6
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage,
+       QCOMImageProcessing2BlockMatchWindowSADInvalidUseTargetNI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %103 BlockMatchSamplerQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchWindowSADQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %102
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADInvalidUseRefNI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %103 BlockMatchSamplerQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchWindowSADQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %104
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage,
+       QCOMImageProcessing2BlockMatchWindowSSDInvalidUseTargetI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %5 BlockMatchSamplerQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchWindowSSDQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %5
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDInvalidUseRefI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %5 BlockMatchSamplerQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchSamplerQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchWindowSSDQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %6
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage,
+       QCOMImageProcessing2BlockMatchWindowSSDInvalidUseTargetNI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %103 BlockMatchSamplerQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchWindowSSDQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %102
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDInvalidUseRefNI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %103 BlockMatchSamplerQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchWindowSSDQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %104
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage,
+       QCOMImageProcessing2BlockMatchGatherSADInvalidUseTargetI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchGatherSADQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %5
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADInvalidUseRefI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchGatherSADQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %6
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage,
+       QCOMImageProcessing2BlockMatchGatherSADInvalidUseTargetNI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchGatherSADQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %102
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADInvalidUseRefNI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchGatherSADQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %104
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage,
+       QCOMImageProcessing2BlockMatchGatherSSDInvalidUseTargetI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchGatherSSDQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %5
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDInvalidUseRefI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main" %3 %4 %5 %6
+               OpExecutionMode %2 OriginUpperLeft
+               OpDecorate %3 Location 0
+               OpDecorate %4 Location 0
+               OpDecorate %5 DescriptorSet 0
+               OpDecorate %5 Binding 4
+               OpDecorate %6 DescriptorSet 0
+               OpDecorate %6 Binding 5
+               OpDecorate %5 BlockMatchTextureQCOM
+               OpDecorate %6 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+          %3 = OpVariable %_ptr_Input_v4float Input
+     %uint_4 = OpConstant %uint 4
+         %16 = OpConstantComposite %v2uint %uint_4 %uint_4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %4 = OpVariable %_ptr_Output_v4float Output
+         %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+         %20 = OpTypeSampledImage %18
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+          %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %v2float = OpTypeVector %float 2
+         %23 = OpTypeImage %float 2D 0 1 0 1 Unknown
+          %2 = OpFunction %void None %8
+         %24 = OpLabel
+         %25 = OpVariable %_ptr_Function_v2uint Function
+               OpStore %25 %16
+         %26 = OpLoad %20 %5
+         %27 = OpLoad %v2uint %25
+         %28 = OpLoad %20 %6
+         %29 = OpLoad %v2uint %25
+         %30 = OpLoad %v2uint %25
+         %31 = OpImageBlockMatchGatherSSDQCOM %v4float %26 %27 %28 %29 %30
+               OpStore %4 %31
+         %32 = OpLoad %20 %6
+         %33 = OpLoad %v4float %3
+         %34 = OpVectorShuffle %v2float %33 %33 0 2
+         %35 = OpImageSampleImplicitLod %v4float %32 %34
+               OpStore %4 %35
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage,
+       QCOMImageProcessing2BlockMatchGatherSSDInvalidUseTargetNI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchGatherSSDQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %102
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDInvalidUseRefNI) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpCapability TextureBlockMatchQCOM
+               OpCapability TextureBlockMatch2QCOM
+               OpExtension "SPV_QCOM_image_processing"
+               OpExtension "SPV_QCOM_image_processing2"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %100 Location 0
+               OpDecorate %101 Location 0
+               OpDecorate %102 DescriptorSet 0
+               OpDecorate %102 Binding 1
+               OpDecorate %103 DescriptorSet 0
+               OpDecorate %103 Binding 3
+               OpDecorate %104 DescriptorSet 0
+               OpDecorate %104 Binding 2
+               OpDecorate %102 BlockMatchTextureQCOM
+               OpDecorate %104 BlockMatchTextureQCOM
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %100 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+  %101 = OpVariable %_ptr_Output_v4float Output
+         %42 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42
+ %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+         %46 = OpTypeSampler
+%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
+       %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant
+         %50 = OpTypeSampledImage %42
+ %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant
+    %v2float = OpTypeVector %float 2
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %15 = OpVariable %_ptr_Function_v2uint Function
+         %45 = OpLoad %42 %102
+         %49 = OpLoad %46 %103
+         %51 = OpSampledImage %50 %45 %49
+         %52 = OpLoad %v2uint %15
+         %54 = OpLoad %42 %104
+         %55 = OpLoad %46 %103
+         %56 = OpSampledImage %50 %54 %55
+         %57 = OpLoad %v2uint %15
+         %58 = OpLoad %v2uint %15
+         %59 = OpImageBlockMatchGatherSSDQCOM %v4float %51 %52 %56 %57 %58
+               OpStore %101 %59
+         %69 = OpLoad %42 %104
+         %70 = OpLoad %46 %103
+         %71 = OpSampledImage %50 %69 %70
+         %73 = OpLoad %v4float %100
+         %74 = OpVectorShuffle %v2float %73 %73 0 0
+         %75 = OpImageSampleImplicitLod %v4float %71 %74
+               OpStore %101 %75
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Illegal use of QCOM image processing decorated texture"));
+}
+
+TEST_F(ValidateImage, ImageMSArray_ArrayedSampledTypeRequiresCapability) {
+  const std::string code = R"(
+               OpCapability Shader
+               OpCapability StorageImageMultisample
+               OpCapability StorageImageReadWithoutFormat
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %var_image DescriptorSet 0
+               OpDecorate %var_image Binding 1
+       %void = OpTypeVoid
+       %func = OpTypeFunction %void
+        %f32 = OpTypeFloat 32
+        %u32 = OpTypeInt 32 0
+     %uint_2 = OpConstant %u32 2
+     %uint_1 = OpConstant %u32 1
+     %v2uint = OpTypeVector %u32 2
+    %v4float = OpTypeVector %f32 4
+    %image = OpTypeImage %f32 2D 2 1 1 2 Unknown
+%ptr_image = OpTypePointer UniformConstant %image
+       %10 = OpConstantComposite %v2uint %uint_1 %uint_2
+%var_image = OpVariable %ptr_image UniformConstant
+     %main = OpFunction %void None %func
+ %main_lab = OpLabel
+       %18 = OpLoad %image %var_image
+       %19 = OpImageRead %v4float %18 %10 Sample %uint_2
+             OpReturn
+             OpFunctionEnd
+)";
+
+  const spv_target_env env = SPV_ENV_VULKAN_1_0;
+  CompileSuccessfully(code, env);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Capability ImageMSArray is required to access storage image"));
+}
+
+TEST_F(ValidateImage, ImageMSArray_SampledTypeDoesNotRequireCapability) {
+  const std::string code = R"(
+               OpCapability Shader
+               OpCapability StorageImageMultisample
+               OpCapability StorageImageReadWithoutFormat
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %var_image DescriptorSet 0
+               OpDecorate %var_image Binding 1
+       %void = OpTypeVoid
+       %func = OpTypeFunction %void
+        %f32 = OpTypeFloat 32
+        %u32 = OpTypeInt 32 0
+     %uint_2 = OpConstant %u32 2
+     %uint_1 = OpConstant %u32 1
+     %v2uint = OpTypeVector %u32 2
+    %v4float = OpTypeVector %f32 4
+    %image = OpTypeImage %f32 2D 2 0 1 2 Unknown
+%ptr_image = OpTypePointer UniformConstant %image
+       %10 = OpConstantComposite %v2uint %uint_1 %uint_2
+%var_image = OpVariable %ptr_image UniformConstant
+     %main = OpFunction %void None %func
+ %main_lab = OpLabel
+       %18 = OpLoad %image %var_image
+       %19 = OpImageRead %v4float %18 %10 Sample %uint_2
+             OpReturn
+             OpFunctionEnd
+)";
+
+  const spv_target_env env = SPV_ENV_VULKAN_1_0;
+  CompileSuccessfully(code, env);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env));
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateImage, ImageMSArray_ArrayedTypeDoesNotRequireCapability) {
+  const std::string code = R"(
+               OpCapability Shader
+               OpCapability StorageImageReadWithoutFormat
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpDecorate %var_image DescriptorSet 0
+               OpDecorate %var_image Binding 1
+       %void = OpTypeVoid
+       %func = OpTypeFunction %void
+        %f32 = OpTypeFloat 32
+        %u32 = OpTypeInt 32 0
+     %uint_3 = OpConstant %u32 3
+     %uint_2 = OpConstant %u32 2
+     %uint_1 = OpConstant %u32 1
+     %v3uint = OpTypeVector %u32 3
+    %v4float = OpTypeVector %f32 4
+    %image = OpTypeImage %f32 2D 2 1 0 2 Unknown
+%ptr_image = OpTypePointer UniformConstant %image
+       %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+%var_image = OpVariable %ptr_image UniformConstant
+     %main = OpFunction %void None %func
+ %main_lab = OpLabel
+       %18 = OpLoad %image %var_image
+       %19 = OpImageRead %v4float %18 %10
+             OpReturn
+             OpFunctionEnd
+)";
+
+  const spv_target_env env = SPV_ENV_VULKAN_1_0;
+  CompileSuccessfully(code, env);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env));
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_interfaces_test.cpp b/third_party/SPIRV-Tools/test/val/val_interfaces_test.cpp
index 1756528..4f62be7 100644
--- a/third_party/SPIRV-Tools/test/val/val_interfaces_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_interfaces_test.cpp
@@ -419,9 +419,10 @@
 )";
 
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
-  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
-  EXPECT_THAT(getDiagnosticString(),
-              HasSubstr("Variable has conflicting location decorations"));
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("decorated with Location multiple times is not allowed"));
 }
 
 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableAndMemberAssigned) {
@@ -505,9 +506,10 @@
 )";
 
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
-  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
-  EXPECT_THAT(getDiagnosticString(),
-              HasSubstr("Member index 1 has conflicting location assignments"));
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("decorated with Location multiple times is not allowed"));
 }
 
 TEST_F(ValidateInterfacesTest, VulkanLocationsMissingAssignmentStructMember) {
@@ -584,6 +586,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 0"));
 }
@@ -611,6 +615,8 @@
 
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722"));
   EXPECT_THAT(
       getDiagnosticString(),
       HasSubstr("Entry-point has conflicting output location assignment "
@@ -699,6 +705,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 1"));
 }
@@ -732,6 +740,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 1"));
 }
@@ -762,6 +772,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 1"));
 }
@@ -792,6 +804,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 2"));
 }
@@ -822,6 +836,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 3"));
 }
@@ -854,6 +870,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 1"));
 }
@@ -886,6 +904,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 5"));
 }
@@ -918,6 +938,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 7"));
 }
@@ -950,6 +972,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 1"));
 }
@@ -982,6 +1006,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 3"));
 }
@@ -1016,6 +1042,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 15"));
 }
@@ -1075,6 +1103,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting input location assignment "
                         "at location 1, component 1"));
 }
@@ -1129,9 +1159,10 @@
 )";
 
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
-  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
-  EXPECT_THAT(getDiagnosticString(),
-              HasSubstr("Variable has conflicting component decorations"));
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("decorated with Component multiple times is not allowed"));
 }
 
 TEST_F(ValidateInterfacesTest,
@@ -1158,10 +1189,10 @@
 )";
 
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
-  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(
       getDiagnosticString(),
-      HasSubstr("Member index 0 has conflicting component assignments"));
+      HasSubstr("decorated with Component multiple times is not allowed"));
 }
 
 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableConflictOutputIndex1) {
@@ -1189,6 +1220,8 @@
 
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722"));
   EXPECT_THAT(
       getDiagnosticString(),
       HasSubstr("Entry-point has conflicting output location assignment "
@@ -1359,6 +1392,8 @@
   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722"));
+  EXPECT_THAT(getDiagnosticString(),
               HasSubstr("Entry-point has conflicting output location "
                         "assignment at location 1, component 1"));
 }
@@ -1538,6 +1573,58 @@
           "Interface struct has no Block decoration but has BuiltIn members."));
 }
 
+TEST_F(ValidateInterfacesTest, InvalidLocationTypePointer) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpMemoryModel Logical Simple
+               OpEntryPoint Vertex %1 "Aiqn0" %2 %3
+               OpDecorate %2 Location 0
+       %void = OpTypeVoid
+          %5 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+%_ptr_Private_void = OpTypePointer Private %void
+       %uint = OpTypeInt 32 0
+%uint_4278132784 = OpConstant %uint 4278132784
+%_arr__ptr_Private_void_uint_4278132784 = OpTypeArray %_ptr_Private_void %uint_4278132784
+%_ptr_Output__arr__ptr_Private_void_uint_4278132784 = OpTypePointer Output %_arr__ptr_Private_void_uint_4278132784
+          %2 = OpVariable %_ptr_Output__arr__ptr_Private_void_uint_4278132784 Output
+%_ptr_Output__ptr_Private_void = OpTypePointer Output %_ptr_Private_void
+          %3 = OpVariable %_ptr_Output__arr__ptr_Private_void_uint_4278132784 Output
+          %1 = OpFunction %void None %5
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Invalid type to assign a location"));
+}
+
+TEST_F(ValidateInterfacesTest, ValidLocationTypePhysicalStorageBufferPointer) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability PhysicalStorageBufferAddresses
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Vertex %main "main" %var
+OpDecorate %var Location 0
+OpDecorate %var RestrictPointer
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%ptr = OpTypePointer PhysicalStorageBuffer %int
+%ptr2 = OpTypePointer Input %ptr
+%var = OpVariable %ptr2 Input
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_memory_test.cpp b/third_party/SPIRV-Tools/test/val/val_memory_test.cpp
index d575318..74a17e9 100644
--- a/third_party/SPIRV-Tools/test/val/val_memory_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_memory_test.cpp
@@ -23,12 +23,14 @@
 #include "test/val/val_fixtures.h"
 
 // For pretty-printing tuples with spv_target_env.
-std::ostream& operator<<(std::ostream& stream, spv_target_env target)
-{
+std::ostream& operator<<(std::ostream& stream, spv_target_env target) {
   switch (target) {
-    case SPV_ENV_UNIVERSAL_1_3: return stream << "SPV_ENV_UNIVERSAL_1_3";
-    case SPV_ENV_UNIVERSAL_1_4: return stream << "SPV_ENV_UNIVERSAL_1_4";
-    default:                    return stream << (unsigned)target;
+    case SPV_ENV_UNIVERSAL_1_3:
+      return stream << "SPV_ENV_UNIVERSAL_1_3";
+    case SPV_ENV_UNIVERSAL_1_4:
+      return stream << "SPV_ENV_UNIVERSAL_1_4";
+    default:
+      return stream << (unsigned)target;
   }
 }
 
@@ -2346,6 +2348,186 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
+TEST_F(ValidateMemory, CoopMatKHRLoadStoreSuccess) {
+  std::string spirv =
+      GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR",
+                                "MakePointerVisibleKHR|NonPrivatePointerKHR");
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+}
+
+TEST_F(ValidateMemory, CoopMatKHRStoreMemoryAccessFail) {
+  std::string spirv =
+      GenCoopMatLoadStoreShader("MakePointerVisibleKHR|NonPrivatePointerKHR",
+                                "MakePointerVisibleKHR|NonPrivatePointerKHR");
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("MakePointerVisibleKHR cannot be used with OpStore"));
+}
+
+TEST_F(ValidateMemory, CoopMatKHRLoadMemoryAccessFail) {
+  std::string spirv =
+      GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR",
+                                "MakePointerAvailableKHR|NonPrivatePointerKHR");
+
+  CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("MakePointerAvailableKHR cannot be used with OpLoad"));
+}
+
+TEST_F(ValidateMemory, CoopMatKHRInvalidStorageClassFail) {
+  const std::string body = R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%f16 = OpTypeFloat 16
+%u32 = OpTypeInt 32 0
+
+%u32_8 = OpConstant %u32 8
+%use_A = OpConstant %u32 0
+%subgroup = OpConstant %u32 3
+
+%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A
+
+%str = OpTypeStruct %f16mat
+%str_ptr = OpTypePointer Workgroup %str
+%sh = OpVariable %str_ptr Workgroup
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+
+OpReturn
+OpFunctionEnd)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "Cooperative matrix types (or types containing them) can only be "
+          "allocated in Function or Private storage classes or as function "
+          "parameters"));
+}
+
+TEST_F(ValidateMemory, CoopMatMatrixKHRLengthResultTypeBad) {
+  const std::string body = R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%f16 = OpTypeFloat 16
+%u32 = OpTypeInt 32 0
+%i32 = OpTypeInt 32 1
+
+%u32_8 = OpConstant %u32 8
+%use_A = OpConstant %u32 0
+%subgroup = OpConstant %u32 3
+
+%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+
+%1 = OpCooperativeMatrixLengthKHR %i32 %f16mat
+
+OpReturn
+OpFunctionEnd)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("The Result Type of OpCooperativeMatrixLengthKHR <id> "
+                "'12[%12]' must be OpTypeInt with width 32 and signedness 0"));
+}
+
+TEST_F(ValidateMemory, CoopMatMatrixKHRLengthOperandTypeBad) {
+  const std::string body =
+      R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%f16 = OpTypeFloat 16
+%u32 = OpTypeInt 32 0
+%i32 = OpTypeInt 32 1
+
+%u32_8 = OpConstant %u32 8
+%use_A = OpConstant %u32 0
+%subgroup = OpConstant %u32 3
+
+%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+
+%1 = OpCooperativeMatrixLengthKHR %u32 %u32
+
+OpReturn
+OpFunctionEnd)";
+
+  CompileSuccessfully(body.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("The type in OpCooperativeMatrixLengthKHR <id> '5[%uint]' "
+                "must be OpTypeCooperativeMatrixKHR"));
+}
+
+TEST_F(ValidateMemory, CoopMatMatrixKHRLengthGood) {
+  const std::string body =
+      R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability CooperativeMatrixKHR
+OpExtension "SPV_KHR_cooperative_matrix"
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%f16 = OpTypeFloat 16
+%u32 = OpTypeInt 32 0
+%i32 = OpTypeInt 32 1
+
+%u32_8 = OpConstant %u32 8
+%use_A = OpConstant %u32 0
+%subgroup = OpConstant %u32 3
+
+%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+
+%1 = OpCooperativeMatrixLengthKHR %u32 %f16mat
+
+OpReturn
+OpFunctionEnd)";
+
+  CompileSuccessfully(body.c_str());
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
 TEST_F(ValidateMemory, VulkanRTAOutsideOfStructBad) {
   std::string spirv = R"(
 OpCapability Shader
@@ -3765,9 +3947,8 @@
       HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
 }
 
-using ValidateSizedVariable =
-    spvtest::ValidateBase<std::tuple<std::string, std::string,
-                                     std::string, spv_target_env>>;
+using ValidateSizedVariable = spvtest::ValidateBase<
+    std::tuple<std::string, std::string, std::string, spv_target_env>>;
 
 CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit, bool buffer_block) {
   CodeGenerator generator;
@@ -3777,7 +3958,8 @@
       "\"SPV_KHR_8bit_storage\"\n";
   generator.memory_model_ = "OpMemoryModel Logical GLSL450\n";
   if (is_8bit) {
-    generator.before_types_ = "OpMemberDecorate %char_buffer_block 0 Offset 0\n";
+    generator.before_types_ =
+        "OpMemberDecorate %char_buffer_block 0 Offset 0\n";
     if (buffer_block)
       generator.before_types_ += "OpDecorate %char_buffer_block BufferBlock\n";
 
@@ -4933,6 +5115,60 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
 }
 
+TEST_F(ValidateMemory, AccessChainNegativeStructIndex32) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%_struct_4 = OpTypeStruct %int %int %int
+%_ptr_Function__struct_4 = OpTypePointer Function %_struct_4
+%_ptr_Function_int = OpTypePointer Function %int
+%int_n224 = OpConstant %int -224
+%fn = OpFunction %void Inline %void_fn
+%entry = OpLabel
+%var = OpVariable %_ptr_Function__struct_4 Function
+%gep = OpInBoundsAccessChain %_ptr_Function_int %var %int_n224
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("Index is out of bounds"));
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("cannot find index -224"));
+}
+
+TEST_F(ValidateMemory, AccessChainNegativeStructIndex64) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability Linkage
+OpCapability Int64
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%long = OpTypeInt 64 1
+%_struct_4 = OpTypeStruct %int %int %int
+%_ptr_Function__struct_4 = OpTypePointer Function %_struct_4
+%_ptr_Function_int = OpTypePointer Function %int
+%long_n224 = OpConstant %long -224
+%fn = OpFunction %void Inline %void_fn
+%entry = OpLabel
+%var = OpVariable %_ptr_Function__struct_4 Function
+%gep = OpInBoundsAccessChain %_ptr_Function_int %var %long_n224
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("Index is out of bounds"));
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("cannot find index -224"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_modes_test.cpp b/third_party/SPIRV-Tools/test/val/val_modes_test.cpp
index 8dc0fbc..83a0503 100644
--- a/third_party/SPIRV-Tools/test/val/val_modes_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_modes_test.cpp
@@ -1027,6 +1027,162 @@
                         "constant instructions."));
 }
 
+using AllowMultipleExecutionModes = spvtest::ValidateBase<std::string>;
+
+TEST_P(AllowMultipleExecutionModes, DifferentOperand) {
+  const std::string mode = GetParam();
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability DenormPreserve
+OpCapability DenormFlushToZero
+OpCapability SignedZeroInfNanPreserve
+OpCapability RoundingModeRTE
+OpCapability RoundingModeRTZ
+OpExtension "SPV_KHR_float_controls"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main )" + mode +
+                            R"( 16
+OpExecutionMode %main )" + mode +
+                            R"( 32
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(AllowMultipleExecutionModes, SameOperand) {
+  const std::string mode = GetParam();
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability DenormPreserve
+OpCapability DenormFlushToZero
+OpCapability SignedZeroInfNanPreserve
+OpCapability RoundingModeRTE
+OpCapability RoundingModeRTZ
+OpExtension "SPV_KHR_float_controls"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main )" + mode +
+                            R"( 32
+OpExecutionMode %main )" + mode +
+                            R"( 32
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("execution mode must not be specified multiple times "
+                        "for the same entry point and operands"));
+}
+
+INSTANTIATE_TEST_SUITE_P(MultipleFloatControlsExecModes,
+                         AllowMultipleExecutionModes,
+                         Values("DenormPreserve", "DenormFlushToZero",
+                                "SignedZeroInfNanPreserve", "RoundingModeRTE",
+                                "RoundingModeRTZ"));
+
+using MultipleExecModes = spvtest::ValidateBase<std::string>;
+
+TEST_P(MultipleExecModes, DuplicateMode) {
+  const std::string mode = GetParam();
+  const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpExecutionMode %main )" + mode +
+                            R"(
+OpExecutionMode %main )" + mode +
+                            R"(
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("execution mode must not be specified multiple times "
+                        "per entry point"));
+}
+
+INSTANTIATE_TEST_SUITE_P(MultipleFragmentExecMode, MultipleExecModes,
+                         Values("DepthReplacing", "DepthGreater", "DepthLess",
+                                "DepthUnchanged"));
+
+TEST_F(ValidateMode, FloatControls2FPFastMathDefaultSameOperand) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float %none
+OpExecutionModeId %main FPFastMathDefault %float %none
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%int = OpTypeInt 32 0
+%none = OpConstant %int 0
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("execution mode must not be specified multiple times "
+                        "for the same entry point and operands"));
+}
+
+TEST_F(ValidateMode, FloatControls2FPFastMathDefaultDifferentOperand) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability Float16
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float %none
+OpExecutionModeId %main FPFastMathDefault %half %none
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%int = OpTypeInt 32 0
+%none = OpConstant %int 0
+%half = OpTypeFloat 16
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
+}
+
 TEST_F(ValidateMode, FragmentShaderInterlockVertexBad) {
   const std::string spirv = R"(
 OpCapability Shader
@@ -1306,6 +1462,752 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
 }
 
+TEST_F(ValidateMode, MaximalReconvergenceRequiresExtension) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main MaximallyReconvergesKHR
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("(6023) requires one of these extensions: "
+                        "SPV_KHR_maximal_reconvergence "));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultNotExecutionModeId) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionMode %main FPFastMathDefault %int_0 %int_0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("OpExecutionMode is only valid when the Mode operand "
+                        "is an execution mode that takes no Extra Operands, or "
+                        "takes Extra Operands that are not id operands"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultNotAType) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %int_0 %int_0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "The Target Type operand must be a floating-point scalar type"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultNotAFloatType) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %int %int_0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "The Target Type operand must be a floating-point scalar type"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultNotAFloatScalarType) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float2 %int_0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float2 = OpTypeVector %float 2
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "The Target Type operand must be a floating-point scalar type"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultSpecConstant) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float %int_0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpSpecConstant %int 0
+%float = OpTypeFloat 32
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("The Fast Math Default operand must be a "
+                        "non-specialization constant"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultInvalidMask) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float %constant
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 524288
+%float = OpTypeFloat 32
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("The Fast Math Default operand is an invalid bitmask value"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultContainsFast) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float %constant
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 16
+%float = OpTypeFloat 32
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("The Fast Math Default operand must not include Fast"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowReassoc) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float %constant
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 327680
+%float = OpTypeFloat 32
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("The Fast Math Default operand must include AllowContract and "
+                "AllowReassoc when AllowTransform is specified"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowContract) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float %constant
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 393216
+%float = OpTypeFloat 32
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("The Fast Math Default operand must include AllowContract and "
+                "AllowReassoc when AllowTransform is specified"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingContractAndReassoc) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float %constant
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 262144
+%float = OpTypeFloat 32
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("The Fast Math Default operand must include AllowContract and "
+                "AllowReassoc when AllowTransform is specified"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultSignedZeroInfNanPreserve) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpCapability SignedZeroInfNanPreserve
+OpExtension "SPV_KHR_float_controls2"
+OpExtension "SPV_KHR_float_controls"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpExecutionModeId %main FPFastMathDefault %float %constant
+OpExecutionMode %main SignedZeroInfNanPreserve 32
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 0
+%float = OpTypeFloat 32
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("FPFastMathDefault and SignedZeroInfNanPreserve execution "
+                "modes cannot be applied to the same entry point"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultConractionOff) {
+  const std::string spirv = R"(
+OpCapability Kernel
+OpCapability Addresses
+OpCapability FloatControls2
+OpCapability SignedZeroInfNanPreserve
+OpExtension "SPV_KHR_float_controls2"
+OpExtension "SPV_KHR_float_controls"
+OpMemoryModel Physical64 OpenCL
+OpEntryPoint Kernel %main "main"
+OpExecutionModeId %main FPFastMathDefault %float %constant
+OpExecutionMode %main ContractionOff
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 0
+%float = OpTypeFloat 32
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("FPFastMathDefault and ContractionOff execution modes "
+                        "cannot be applied to the same entry point"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultNoContractionNotInCallTree) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionModeId %main FPFastMathDefault %float %constant
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add NoContraction
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 0
+%float = OpTypeFloat 32
+%zero = OpConstant %float 0
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+%add = OpFAdd %float %zero %zero
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionModeId %main FPFastMathDefault %float %constant
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add NoContraction
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 0
+%float = OpTypeFloat 32
+%zero = OpConstant %float 0
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%call = OpFunctionCall %void %func
+OpReturn
+OpFunctionEnd
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+%add = OpFAdd %float %zero %zero
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("NoContraction cannot be used by an entry point with "
+                        "the FPFastMathDefault execution mode"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree2) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability Kernel
+OpCapability Addresses
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Physical64 OpenCL
+OpEntryPoint Kernel %main "main"
+OpExecutionModeId %main FPFastMathDefault %float %constant
+OpDecorate %const NoContraction
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 0
+%float = OpTypeFloat 32
+%zero = OpConstant %float 0
+%const = OpSpecConstantOp %float FAdd %zero %zero
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%call = OpFunctionCall %void %func
+OpReturn
+OpFunctionEnd
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+%add = OpFAdd %float %const %zero
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("NoContraction cannot be used by an entry point with "
+                        "the FPFastMathDefault execution mode"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultFastMathFastNotInCallTree) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionModeId %main FPFastMathDefault %float %constant
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add FPFastMathMode Fast
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 0
+%float = OpTypeFloat 32
+%zero = OpConstant %float 0
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+%add = OpFAdd %float %zero %zero
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionModeId %main FPFastMathDefault %float %constant
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %add FPFastMathMode Fast
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 0
+%float = OpTypeFloat 32
+%zero = OpConstant %float 0
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%call = OpFunctionCall %void %func
+OpReturn
+OpFunctionEnd
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+%add = OpFAdd %float %zero %zero
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("FPFastMathMode Fast cannot be used by an entry point "
+                        "with the FPFastMathDefault execution mode"));
+}
+
+TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree2) {
+  const std::string spirv = R"(
+OpCapability Kernel
+OpCapability Addresses
+OpCapability FloatControls2
+OpExtension "SPV_KHR_float_controls2"
+OpMemoryModel Physical64 OpenCL
+OpEntryPoint Kernel %main "main"
+OpExecutionModeId %main FPFastMathDefault %float %constant
+OpDecorate %const FPFastMathMode Fast
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%constant = OpConstant %int 0
+%float = OpTypeFloat 32
+%zero = OpConstant %float 0
+%const = OpSpecConstantOp %float FAdd %zero %zero
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%call = OpFunctionCall %void %func
+OpReturn
+OpFunctionEnd
+%func = OpFunction %void None %void_fn
+%func_entry = OpLabel
+%add = OpFAdd %float %const %zero
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("FPFastMathMode Fast cannot be used by an entry point "
+                        "with the FPFastMathDefault execution mode"));
+}
+
+TEST_F(ValidateMode, FragmentShaderRequireFullQuadsKHR) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability GroupNonUniform
+OpCapability GroupNonUniformVote
+OpCapability GroupNonUniformBallot
+OpCapability QuadControlKHR
+OpExtension "SPV_KHR_quad_control"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main"
+OpExecutionMode %4 OriginUpperLeft
+OpExecutionMode %4 RequireFullQuadsKHR
+OpDecorate %17 Location 0
+OpDecorate %31 BuiltIn HelperInvocation
+OpDecorate %40 Location 0
+OpDecorate %44 DescriptorSet 0
+OpDecorate %44 Binding 0
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 0
+%7 = OpTypeVector %6 4
+%8 = OpTypePointer Function %7
+%10 = OpTypeBool
+%11 = OpConstantTrue %10
+%12 = OpConstant %6 7
+%14 = OpTypeFloat 32
+%15 = OpTypeVector %14 4
+%16 = OpTypePointer Output %15
+%17 = OpVariable %16 Output
+%18 = OpConstant %14 1
+%19 = OpConstant %14 0
+%20 = OpConstantComposite %15 %18 %19 %19 %18
+%23 = OpConstant %6 4
+%27 = OpConstant %6 1
+%28 = OpTypePointer Output %14
+%30 = OpTypePointer Input %10
+%31 = OpVariable %30 Input
+%36 = OpConstant %6 2
+%38 = OpTypeVector %14 2
+%39 = OpTypePointer Input %38
+%40 = OpVariable %39 Input
+%41 = OpTypeImage %14 2D 0 0 0 1 Unknown
+%42 = OpTypeSampledImage %41
+%43 = OpTypePointer UniformConstant %42
+%44 = OpVariable %43 UniformConstant
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%9 = OpVariable %8 Function
+%13 = OpGroupNonUniformBallot %7 %12 %11
+OpStore %9 %13
+OpStore %17 %20
+%21 = OpLoad %7 %9
+%22 = OpGroupNonUniformBallotBitCount %6 %12 Reduce %21
+%24 = OpIEqual %10 %22 %23
+OpSelectionMerge %26 None
+OpBranchConditional %24 %25 %26
+%25 = OpLabel
+%29 = OpAccessChain %28 %17 %27
+OpStore %29 %18
+OpBranch %26
+%26 = OpLabel
+%32 = OpLoad %10 %31
+%33 = OpGroupNonUniformAny %10 %12 %32
+OpSelectionMerge %35 None
+OpBranchConditional %33 %34 %35
+%34 = OpLabel
+%37 = OpAccessChain %28 %17 %36
+OpStore %37 %18
+OpBranch %35
+%35 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_THAT(SPV_ERROR_INVALID_DATA,
+              ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "Execution mode can only be used with the Fragment execution model"));
+}
+
+TEST_F(ValidateMode, FragmentShaderQuadDerivativesKHR) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability GroupNonUniform
+OpCapability GroupNonUniformVote
+OpCapability QuadControlKHR
+OpExtension "SPV_KHR_quad_control"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main"
+OpExecutionMode %4 OriginUpperLeft
+OpExecutionMode %4 QuadDerivativesKHR
+OpDecorate %12 BuiltIn FragCoord
+OpDecorate %41 Location 0
+OpDecorate %45 DescriptorSet 0
+OpDecorate %45 Binding 0
+OpDecorate %49 Location 0
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeBool
+%7 = OpTypePointer Function %6
+%9 = OpTypeFloat 32
+%10 = OpTypeVector %9 4
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpTypeInt 32 0
+%14 = OpConstant %13 1
+%15 = OpTypePointer Input %9
+%18 = OpConstant %9 8.5
+%21 = OpConstant %9 0.100000001
+%25 = OpConstant %13 0
+%28 = OpConstant %9 3.5
+%30 = OpConstant %9 6
+%36 = OpConstant %13 7
+%40 = OpTypePointer Output %10
+%41 = OpVariable %40 Output
+%42 = OpTypeImage %9 2D 0 0 0 1 Unknown
+%43 = OpTypeSampledImage %42
+%44 = OpTypePointer UniformConstant %43
+%45 = OpVariable %44 UniformConstant
+%47 = OpTypeVector %9 2
+%48 = OpTypePointer Input %47
+%49 = OpVariable %48 Input
+%53 = OpConstant %9 0.899999976
+%54 = OpConstant %9 0.200000003
+%55 = OpConstant %9 1
+%56 = OpConstantComposite %10 %53 %54 %54 %55
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%16 = OpAccessChain %15 %12 %14
+%17 = OpLoad %9 %16
+%19 = OpFSub %9 %17 %18
+%20 = OpExtInst %9 %1 FAbs %19
+%22 = OpFOrdLessThan %6 %20 %21
+OpSelectionMerge %24 None
+OpBranchConditional %22 %23 %24
+%23 = OpLabel
+%26 = OpAccessChain %15 %12 %25
+%27 = OpLoad %9 %26
+%29 = OpFSub %9 %27 %28
+%31 = OpFMod %9 %29 %30
+%33 = OpFOrdLessThan %6 %31 %21
+OpBranch %24
+%24 = OpLabel
+%34 = OpPhi %6 %22 %5 %33 %23
+OpStore %8 %34
+%35 = OpLoad %6 %8
+%37 = OpGroupNonUniformAny %6 %36 %35
+OpSelectionMerge %39 None
+OpBranchConditional %37 %38 %52
+%38 = OpLabel
+%46 = OpLoad %43 %45
+%50 = OpLoad %47 %49
+%51 = OpImageSampleImplicitLod %10 %46 %50
+OpStore %41 %51
+OpBranch %39
+%52 = OpLabel
+OpStore %41 %56
+OpBranch %39
+%39 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_THAT(SPV_ERROR_INVALID_DATA,
+              ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "Execution mode can only be used with the Fragment execution model"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_non_uniform_test.cpp b/third_party/SPIRV-Tools/test/val/val_non_uniform_test.cpp
index af571d3..530676d 100644
--- a/third_party/SPIRV-Tools/test/val/val_non_uniform_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_non_uniform_test.cpp
@@ -44,6 +44,10 @@
 OpCapability GroupNonUniformArithmetic
 OpCapability GroupNonUniformClustered
 OpCapability GroupNonUniformQuad
+OpCapability GroupNonUniformPartitionedNV
+OpCapability QuadControlKHR
+OpExtension "SPV_NV_shader_subgroup_partitioned"
+OpExtension "SPV_KHR_quad_control"
 )";
 
   ss << capabilities_and_extensions;
@@ -62,16 +66,27 @@
 %float = OpTypeFloat 32
 %u32vec4 = OpTypeVector %u32 4
 %u32vec3 = OpTypeVector %u32 3
+%v2bool = OpTypeVector %bool 2
+%v4float = OpTypeVector %float 4
+%struct = OpTypeStruct %int
+%v4int = OpTypeVector %int 4
 
 %true = OpConstantTrue %bool
 %false = OpConstantFalse %bool
 
 %u32_0 = OpConstant %u32 0
+%int_0 = OpConstant %int 0
 
 %float_0 = OpConstant %float 0
 
 %u32vec4_null = OpConstantComposite %u32vec4 %u32_0 %u32_0 %u32_0 %u32_0
 %u32vec3_null = OpConstantComposite %u32vec3 %u32_0 %u32_0 %u32_0
+%v2bool_false = OpConstantNull %v2bool
+%v4float_null = OpConstantNull %v4float
+%struct_null = OpConstantNull %struct
+%v4int_null = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
+
+%u32_undef = OpUndef %u32
 
 %cross_device = OpConstant %u32 0
 %device = OpConstant %u32 1
@@ -122,6 +137,32 @@
   }
 }
 
+std::string ConvertMatch(const std::string& type) {
+  if (type == "%bool") {
+    return "%true";
+  } else if (type == "%u32") {
+    return "%u32_0";
+  } else if (type == "%int") {
+    return "%int_0";
+  } else if (type == "%float") {
+    return "%float_0";
+  } else if (type == "%u32vec4") {
+    return "%u32vec4_null";
+  } else if (type == "%u32vec3") {
+    return "%u32vec3_null";
+  } else if (type == "%v2bool") {
+    return "%v2bool_false";
+  } else if (type == "%v4float") {
+    return "%v4float_null";
+  } else if (type == "%struct") {
+    return "%struct_null";
+  } else if (type == "%v4int") {
+    return "%v4int_null";
+  }
+
+  return "INVALID";
+}
+
 TEST_P(GroupNonUniform, Vulkan1p1) {
   std::string opcode = std::get<0>(GetParam());
   std::string type = std::get<1>(GetParam());
@@ -129,10 +170,20 @@
   std::string args = std::get<3>(GetParam());
   std::string error = std::get<4>(GetParam());
 
+  const std::string match = "match_res";
+  size_t pos = std::string::npos;
+  while ((pos = args.find(match)) != std::string::npos) {
+    const std::string replace = ConvertMatch(type);
+    args = args.substr(0, pos) + replace + args.substr(pos + match.size());
+  }
+
   std::ostringstream sstr;
   sstr << "%result = " << opcode << " ";
   sstr << type << " ";
-  sstr << ConvertScope(execution_scope) << " ";
+  if (opcode != "OpGroupNonUniformQuadAllKHR" &&
+      opcode != "OpGroupNonUniformQuadAnyKHR") {
+    sstr << ConvertScope(execution_scope) << " ";
+  }
   sstr << args << "\n";
 
   CompileSuccessfully(GenerateShaderCode(sstr.str()), SPV_ENV_VULKAN_1_1);
@@ -162,10 +213,20 @@
   std::string args = std::get<3>(GetParam());
   std::string error = std::get<4>(GetParam());
 
+  const std::string match = "match_res";
+  size_t pos = std::string::npos;
+  while ((pos = args.find(match)) != std::string::npos) {
+    const std::string replace = ConvertMatch(type);
+    args = args.substr(0, pos) + replace + args.substr(pos + match.size());
+  }
+
   std::ostringstream sstr;
   sstr << "%result = " << opcode << " ";
   sstr << type << " ";
-  sstr << ConvertScope(execution_scope) << " ";
+  if (opcode != "OpGroupNonUniformQuadAllKHR" &&
+      opcode != "OpGroupNonUniformQuadAnyKHR") {
+    sstr << ConvertScope(execution_scope) << " ";
+  }
   sstr << args << "\n";
 
   CompileSuccessfully(GenerateShaderCode(sstr.str()), SPV_ENV_UNIVERSAL_1_3);
@@ -292,6 +353,542 @@
                                  Values("Expected Value to be a vector of four "
                                         "components of integer type scalar")));
 
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformElectGood, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformElect"),
+                                 Values("%bool"), Values(spv::Scope::Subgroup),
+                                 Values(""), Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformElectBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformElect"),
+            Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3",
+                   "%v2bool", "%v4float", "%struct"),
+            Values(spv::Scope::Subgroup), Values(""),
+            Values("Result must be a boolean scalar type")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformAnyAllGood, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformAny",
+                                        "OpGroupNonUniformAll"),
+                                 Values("%bool"), Values(spv::Scope::Subgroup),
+                                 Values("%true", "%false"), Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformAnyAllBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformAny", "OpGroupNonUniformAll"),
+            Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3",
+                   "%v2bool", "%v4float", "%struct"),
+            Values(spv::Scope::Subgroup), Values("%true"),
+            Values("Result must be a boolean scalar type")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformAnyAllBadOperand, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformAny", "OpGroupNonUniformAll"),
+            Values("%bool"), Values(spv::Scope::Subgroup),
+            Values("%u32_0", "%int_0", "%float_0", "%u32vec4_null",
+                   "%u32vec3_null", "%v2bool_false", "%v4float_null",
+                   "%struct_null"),
+            Values("Predicate must be a boolean scalar type")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformAllEqualGood, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformAllEqual"),
+                                 Values("%bool"), Values(spv::Scope::Subgroup),
+                                 Values("%true", "%false"), Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformAllEqualBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformAllEqual"),
+            Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3",
+                   "%v2bool", "%v4float", "%struct"),
+            Values(spv::Scope::Subgroup), Values("%true"),
+            Values("Result must be a boolean scalar type")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformAllEqualBadOperand, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformAllEqual"), Values("%bool"),
+            Values(spv::Scope::Subgroup), Values("%struct_null"),
+            Values("Value must be a scalar or vector of integer, "
+                   "floating-point, or boolean type")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformBroadcastGood, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformBroadcast",
+                                        "OpGroupNonUniformQuadBroadcast",
+                                        "OpGroupNonUniformQuadSwap"),
+                                 Values("%bool", "%u32", "%int", "%float",
+                                        "%u32vec4", "%u32vec3", "%v2bool",
+                                        "%v4float", "%v4int"),
+                                 Values(spv::Scope::Subgroup),
+                                 Values("match_res %u32_0"), Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBroadcastShuffleBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBroadcast", "OpGroupNonUniformShuffle",
+                   "OpGroupNonUniformShuffleXor", "OpGroupNonUniformShuffleUp",
+                   "OpGroupNonUniformShuffleDown",
+                   "OpGroupNonUniformQuadBroadcast",
+                   "OpGroupNonUniformQuadSwap"),
+            Values("%void", "%struct"), Values(spv::Scope::Subgroup),
+            Values("%u32_0 %u32_0"),
+            Values("Result must be a scalar or vector of integer, "
+                   "floating-point, or boolean type")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBroadcastShuffleBadOperand1, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBroadcast", "OpGroupNonUniformShuffle",
+                   "OpGroupNonUniformShuffleXor", "OpGroupNonUniformShuffleUp",
+                   "OpGroupNonUniformShuffleDown",
+                   "OpGroupNonUniformQuadBroadcast",
+                   "OpGroupNonUniformQuadSwap"),
+            Values("%bool"), Values(spv::Scope::Subgroup),
+            Values("%u32_0 %u32_0", "%int_0 %u32_0", "%float_0 %u32_0",
+                   "%u32vec4_null %u32_0", "%u32vec3_null %u32_0",
+                   "%v2bool_false %u32_0", "%v4float_null %u32_0",
+                   "%struct_null %u32_0", "%v4int_null %u32_0"),
+            Values("The type of Value must match the Result type")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBroadcastShuffleBadOperand2, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBroadcast", "OpGroupNonUniformShuffle",
+                   "OpGroupNonUniformShuffleXor", "OpGroupNonUniformShuffleUp",
+                   "OpGroupNonUniformShuffleDown",
+                   "OpGroupNonUniformQuadBroadcast",
+                   "OpGroupNonUniformQuadSwap"),
+            Values("%bool"), Values(spv::Scope::Subgroup),
+            Values("%true %true", "%true %int_0", "%true %float_0",
+                   "%true %u32vec4_null", "%true %u32vec3_null",
+                   "%true %v4float_null", "%true %v2bool_false",
+                   "%true %struct_null", "%true %v4int_null"),
+            Values("must be an unsigned integer scalar")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformBroadcastShuffleOperand2NotConstant,
+                         GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformBroadcast",
+                                        "OpGroupNonUniformQuadBroadcast",
+                                        "OpGroupNonUniformQuadSwap"),
+                                 Values("%bool"), Values(spv::Scope::Subgroup),
+                                 Values("%true %u32_undef"),
+                                 Values("must be a constant instruction")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformBroadcastFirstGood, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformBroadcastFirst"),
+                                 Values("%bool", "%u32", "%int", "%float",
+                                        "%u32vec4", "%u32vec3", "%v2bool",
+                                        "%v4float", "%v4int"),
+                                 Values(spv::Scope::Subgroup),
+                                 Values("match_res"), Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBroadcasFirsttBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBroadcastFirst"),
+            Values("%void", "%struct"), Values(spv::Scope::Subgroup),
+            Values("%u32_0"),
+            Values("Result must be a scalar or vector of integer, "
+                   "floating-point, or boolean type")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBroadcastBadOperand, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBroadcastFirst"), Values("%bool"),
+            Values(spv::Scope::Subgroup),
+            Values("%u32_0", "%int_0", "%float_0", "%u32vec4_null",
+                   "%u32vec3_null", "%v2bool_false", "%v4float_null",
+                   "%struct_null", "%v4int_null"),
+            Values("The type of Value must match the Result type")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotGood, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformBallot"),
+                                 Values("%u32vec4"),
+                                 Values(spv::Scope::Subgroup),
+                                 Values("%true", "%false"), Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBallotBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBallot"),
+            Values("%void", "%bool", "%u32", "%int", "%float", "%u32vec3",
+                   "%v2bool", "%v4float", "%struct", "%v4int"),
+            Values(spv::Scope::Subgroup), Values("%true", "%false"),
+            Values("Result must be a 4-component unsigned integer vector")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBadOperand, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformBallot"),
+                                 Values("%u32vec4"),
+                                 Values(spv::Scope::Subgroup),
+                                 Values("%u32_0", "%int_0", "%float_0",
+                                        "%u32vec4_null", "%u32vec3_null",
+                                        "%v2bool_false", "%v4float_null",
+                                        "%struct_null", "%v4int_null"),
+                                 Values("Predicate must be a boolean scalar")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformInverseBallotGood, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformInverseBallot"),
+                                 Values("%bool"), Values(spv::Scope::Subgroup),
+                                 Values("%u32vec4_null"), Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformInverseBallotBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformInverseBallot"),
+            Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3",
+                   "%v2bool", "%v4float", "%struct", "%v4int"),
+            Values(spv::Scope::Subgroup), Values("%u32vec4_null"),
+            Values("Result must be a boolean scalar")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformInverseBallotBadOperand, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformInverseBallot"), Values("%bool"),
+            Values(spv::Scope::Subgroup),
+            Values("%true", "%false", "%u32_0", "%int_0", "%float_0",
+                   "%u32vec3_null", "%v2bool_false", "%v4float_null",
+                   "%struct_null", "%v4int_null"),
+            Values("Value must be a 4-component unsigned integer vector")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBitExtractGood, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformBallotBitExtract"),
+                                 Values("%bool"), Values(spv::Scope::Subgroup),
+                                 Values("%u32vec4_null %u32_0"), Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBallotBitExtractBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBallotBitExtract"),
+            Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3",
+                   "%v2bool", "%v4float", "%struct", "%v4int"),
+            Values(spv::Scope::Subgroup), Values("%u32vec4_null %u32_0"),
+            Values("Result must be a boolean scalar")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBallotBitExtractBadOperand1, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBallotBitExtract"), Values("%bool"),
+            Values(spv::Scope::Subgroup),
+            Values("%true %u32_0", "%false %u32_0", "%u32_0 %u32_0",
+                   "%int_0 %u32_0", "%float_0 %u32_0", "%u32vec3_null %u32_0",
+                   "%v2bool_false %u32_0", "%v4float_null %u32_0",
+                   "%struct_null %u32_0", "%v4int_null %u32_0"),
+            Values("Value must be a 4-component unsigned integer vector")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBallotBitExtractBadOperand2, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBallotBitExtract"), Values("%bool"),
+            Values(spv::Scope::Subgroup),
+            Values("%u32vec4_null %true", "%u32vec4_null %false",
+                   "%u32vec4_null %int_0", "%u32vec4_null %float_0",
+                   "%u32vec4_null %u32vec3_null", "%u32vec4_null %v2bool_false",
+                   "%u32vec4_null %v4float_null", "%u32vec4_null %struct_null",
+                   "%u32vec4_null %v4int_null"),
+            Values("Id must be an unsigned integer scalar")));
+
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotFindGood, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformBallotFindLSB",
+                                        "OpGroupNonUniformBallotFindMSB"),
+                                 Values("%u32"), Values(spv::Scope::Subgroup),
+                                 Values("%u32vec4_null"), Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBallotFindBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBallotFindLSB",
+                   "OpGroupNonUniformBallotFindMSB"),
+            Values("%void", "%bool", "%int", "%float", "%u32vec4", "%u32vec3",
+                   "%v2bool", "%v4float", "%struct", "%v4int"),
+            Values(spv::Scope::Subgroup), Values("%u32vec4_null"),
+            Values("Result must be an unsigned integer scalar")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBallotFindBadOperand, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformBallotFindLSB",
+                   "OpGroupNonUniformBallotFindMSB"),
+            Values("%u32"), Values(spv::Scope::Subgroup),
+            Values("%true", "%false", "%u32_0", "%int_0", "%float_0",
+                   "%u32vec3_null", "%v2bool_false", "%v4float_null",
+                   "%struct_null", "%v4int_null"),
+            Values("Value must be a 4-component unsigned integer vector")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformIntegerArithmeticGood, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul",
+                   "OpGroupNonUniformSMin", "OpGroupNonUniformSMax",
+                   "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr",
+                   "OpGroupNonUniformBitwiseXor"),
+            Values("%u32", "%int", "%u32vec4", "%u32vec3", "%v4int"),
+            Values(spv::Scope::Subgroup),
+            Values("Reduce match_res", "InclusiveScan match_res",
+                   "ExclusiveScan match_res",
+                   "ClusteredReduce match_res %u32_0",
+                   "PartitionedReduceNV match_res %u32vec4_null",
+                   "PartitionedInclusiveScanNV match_res %u32vec4_null",
+                   "PartitionedExclusiveScanNV match_res %v4int_null"),
+            Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformIntegerArithmeticBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul",
+                   "OpGroupNonUniformSMin", "OpGroupNonUniformSMax",
+                   "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr",
+                   "OpGroupNonUniformBitwiseXor"),
+            Values("%bool", "%float", "%v4float", "%struct"),
+            Values(spv::Scope::Subgroup),
+            Values("Reduce match_res", "InclusiveScan match_res",
+                   "ExclusiveScan match_res",
+                   "ClusteredReduce match_res %u32_0"),
+            Values("Result must be an integer scalar or vector")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformIntegerArithmeticBadValue, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul",
+                   "OpGroupNonUniformSMin", "OpGroupNonUniformSMax",
+                   "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr",
+                   "OpGroupNonUniformBitwiseXor"),
+            Values("%int", "%u32vec4", "%u32vec3", "%v4int"),
+            Values(spv::Scope::Subgroup),
+            Values("Reduce %u32_0", "InclusiveScan %u32_0",
+                   "ExclusiveScan %u32_0", "ClusteredReduce %u32_0 %u32_0"),
+            Values("The type of Value must match the Result type")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformIntegerArithmeticMissingClusterSize, GroupNonUniform,
+    Combine(
+        Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul",
+               "OpGroupNonUniformSMin", "OpGroupNonUniformUMin",
+               "OpGroupNonUniformSMax", "OpGroupNonUniformUMax",
+               "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr",
+               "OpGroupNonUniformBitwiseXor"),
+        Values("%u32"), Values(spv::Scope::Subgroup),
+        Values("ClusteredReduce match_res"),
+        Values(
+            "ClusterSize must be present when Operation is ClusteredReduce")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformIntegerArithmeticMissingBallot, GroupNonUniform,
+    Combine(
+        Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul",
+               "OpGroupNonUniformSMin", "OpGroupNonUniformUMin",
+               "OpGroupNonUniformSMax", "OpGroupNonUniformUMax",
+               "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr",
+               "OpGroupNonUniformBitwiseXor"),
+        Values("%u32"), Values(spv::Scope::Subgroup),
+        Values("PartitionedReduceNV match_res",
+               "PartitionedInclusiveScanNV match_res",
+               "PartitionedExclusiveScanNV match_res"),
+        Values("Ballot must be present when Operation is PartitionedReduceNV, "
+               "PartitionedInclusiveScanNV, or PartitionedExclusiveScanNV")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformIntegerArithmeticBadClusterSizeType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul",
+                   "OpGroupNonUniformSMin", "OpGroupNonUniformUMin",
+                   "OpGroupNonUniformSMax", "OpGroupNonUniformUMax",
+                   "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr",
+                   "OpGroupNonUniformBitwiseXor"),
+            Values("%u32"), Values(spv::Scope::Subgroup),
+            Values("ClusteredReduce match_res %true",
+                   "ClusteredReduce match_res %false",
+                   "ClusteredReduce match_res %int_0",
+                   "ClusteredReduce match_res %float_0",
+                   "ClusteredReduce match_res %u32vec4_null",
+                   "ClusteredReduce match_res %u32vec3_null",
+                   "ClusteredReduce match_res %v2bool_false",
+                   "ClusteredReduce match_res %v4float_null",
+                   "ClusteredReduce match_res %struct_null",
+                   "ClusteredReduce match_res %v4int_null"),
+            Values("ClusterSize must be an unsigned integer scalar")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformIntegerArithmeticBadBallotType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul",
+                   "OpGroupNonUniformSMin", "OpGroupNonUniformUMin",
+                   "OpGroupNonUniformSMax", "OpGroupNonUniformUMax",
+                   "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr",
+                   "OpGroupNonUniformBitwiseXor"),
+            Values("%u32"), Values(spv::Scope::Subgroup),
+            Values("PartitionedReduceNV match_res %true",
+                   "PartitionedReduceNV match_res %false",
+                   "PartitionedReduceNV match_res %int_0",
+                   "PartitionedReduceNV match_res %float_0",
+                   "PartitionedReduceNV match_res %u32_0",
+                   "PartitionedReduceNV match_res %u32vec3_null",
+                   "PartitionedReduceNV match_res %v2bool_false",
+                   "PartitionedReduceNV match_res %v4float_null",
+                   "PartitionedReduceNV match_res %struct_null"),
+            Values("Ballot must be a 4-component integer vector")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformIntegerArithmeticClusterSizeNotConstant, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul",
+                   "OpGroupNonUniformSMin", "OpGroupNonUniformUMin",
+                   "OpGroupNonUniformSMax", "OpGroupNonUniformUMax",
+                   "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr",
+                   "OpGroupNonUniformBitwiseXor"),
+            Values("%u32"), Values(spv::Scope::Subgroup),
+            Values("ClusteredReduce match_res %u32_undef"),
+            Values("ClusterSize must be a constant instruction")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformUnsignedIntegerArithmeticGood, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformUMin", "OpGroupNonUniformUMax"),
+            Values("%u32", "%u32vec4", "%u32vec3"),
+            Values(spv::Scope::Subgroup),
+            Values("Reduce match_res", "InclusiveScan match_res",
+                   "ExclusiveScan match_res",
+                   "ClusteredReduce match_res %u32_0"),
+            Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformUnsignedIntegerArithmeticBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformUMin", "OpGroupNonUniformUMax"),
+            Values("%bool", "%int", "%float", "%v4float", "%struct", "%v4int"),
+            Values(spv::Scope::Subgroup),
+            Values("Reduce match_res", "InclusiveScan match_res",
+                   "ExclusiveScan match_res",
+                   "ClusteredReduce match_res %u32_0"),
+            Values("Result must be an unsigned integer scalar or vector")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformUnsignedIntegerArithmeticBadValue, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformUMin", "OpGroupNonUniformUMax"),
+            Values("%u32vec4", "%u32vec3"), Values(spv::Scope::Subgroup),
+            Values("Reduce %u32_0", "InclusiveScan %u32_0",
+                   "ExclusiveScan %u32_0", "ClusteredReduce %u32_0 %u32_0"),
+            Values("The type of Value must match the Result type")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformFloatArithmeticGood, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul",
+                   "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"),
+            Values("%float", "%v4float"), Values(spv::Scope::Subgroup),
+            Values("Reduce match_res", "InclusiveScan match_res",
+                   "ExclusiveScan match_res",
+                   "ClusteredReduce match_res %u32_0"),
+            Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformFloatArithmeticBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul",
+                   "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"),
+            Values("%bool", "%u32", "%int", "%u32vec4", "%u32vec3", "%struct",
+                   "%v4int"),
+            Values(spv::Scope::Subgroup),
+            Values("Reduce match_res", "InclusiveScan match_res",
+                   "ExclusiveScan match_res",
+                   "ClusteredReduce match_res %u32_0"),
+            Values("Result must be a floating-point scalar or vector")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformFloatArithmeticBadValue, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul",
+                   "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"),
+            Values("%v4float"), Values(spv::Scope::Subgroup),
+            Values("Reduce %float_0", "InclusiveScan %float_0",
+                   "ExclusiveScan %float_0", "ClusteredReduce %float_0 %u32_0"),
+            Values("The type of Value must match the Result type")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformFloatArithmeticMissingClusterSize, GroupNonUniform,
+    Combine(
+        Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul",
+               "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"),
+        Values("%float"), Values(spv::Scope::Subgroup),
+        Values("ClusteredReduce match_res"),
+        Values(
+            "ClusterSize must be present when Operation is ClusteredReduce")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformFloatArithmeticBadClusterSizeType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul",
+                   "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"),
+            Values("%float"), Values(spv::Scope::Subgroup),
+            Values("ClusteredReduce match_res %true",
+                   "ClusteredReduce match_res %false",
+                   "ClusteredReduce match_res %int_0",
+                   "ClusteredReduce match_res %float_0",
+                   "ClusteredReduce match_res %u32vec4_null",
+                   "ClusteredReduce match_res %u32vec3_null",
+                   "ClusteredReduce match_res %v2bool_false",
+                   "ClusteredReduce match_res %v4float_null",
+                   "ClusteredReduce match_res %struct_null",
+                   "ClusteredReduce match_res %v4int_null"),
+            Values("ClusterSize must be an unsigned integer scalar")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformFloatArithmeticClusterSizeNotConstant, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul",
+                   "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"),
+            Values("%float"), Values(spv::Scope::Subgroup),
+            Values("ClusteredReduce match_res %u32_undef"),
+            Values("ClusterSize must be a constant instruction")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBooleanArithmeticGood, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr",
+                   "OpGroupNonUniformLogicalXor"),
+            Values("%bool", "%v2bool"), Values(spv::Scope::Subgroup),
+            Values("Reduce match_res", "InclusiveScan match_res",
+                   "ExclusiveScan match_res",
+                   "ClusteredReduce match_res %u32_0"),
+            Values("")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBooleanArithmeticBadResultType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr",
+                   "OpGroupNonUniformLogicalXor"),
+            Values("%u32", "%int", "%float", "%u32vec4", "%u32vec3", "%struct",
+                   "%v4float", "%v4int"),
+            Values(spv::Scope::Subgroup),
+            Values("Reduce match_res", "InclusiveScan match_res",
+                   "ExclusiveScan match_res",
+                   "ClusteredReduce match_res %u32_0"),
+            Values("Result must be a boolean scalar or vector")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBooleanArithmeticBadValue, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr",
+                   "OpGroupNonUniformLogicalXor"),
+            Values("%v2bool"), Values(spv::Scope::Subgroup),
+            Values("Reduce %true", "InclusiveScan %true",
+                   "ExclusiveScan %false", "ClusteredReduce %false %u32_0"),
+            Values("The type of Value must match the Result type")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBooleanArithmeticMissingClusterSize, GroupNonUniform,
+    Combine(
+        Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr",
+               "OpGroupNonUniformLogicalXor"),
+        Values("%bool"), Values(spv::Scope::Subgroup),
+        Values("ClusteredReduce match_res"),
+        Values(
+            "ClusterSize must be present when Operation is ClusteredReduce")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBooleanArithmeticBadClusterSizeType, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr",
+                   "OpGroupNonUniformLogicalXor"),
+            Values("%bool"), Values(spv::Scope::Subgroup),
+            Values("ClusteredReduce match_res %true",
+                   "ClusteredReduce match_res %false",
+                   "ClusteredReduce match_res %int_0",
+                   "ClusteredReduce match_res %float_0",
+                   "ClusteredReduce match_res %u32vec4_null",
+                   "ClusteredReduce match_res %u32vec3_null",
+                   "ClusteredReduce match_res %v2bool_false",
+                   "ClusteredReduce match_res %v4float_null",
+                   "ClusteredReduce match_res %struct_null",
+                   "ClusteredReduce match_res %v4int_null"),
+            Values("ClusterSize must be an unsigned integer scalar")));
+
+INSTANTIATE_TEST_SUITE_P(
+    GroupNonUniformBooleanArithmeticClusterSizeNotConstant, GroupNonUniform,
+    Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr",
+                   "OpGroupNonUniformLogicalXor"),
+            Values("%bool"), Values(spv::Scope::Subgroup),
+            Values("ClusteredReduce match_res %u32_undef"),
+            Values("ClusterSize must be a constant instruction")));
+
+// Subgroup scope is not actual parameter, but used for test expectations,
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformQuadAllKHR, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformQuadAllKHR"),
+                                 Values("%bool"), Values(spv::Scope::Subgroup),
+                                 Values("%true"), Values("")));
+
+// Subgroup scope is not actual parameter, but used for test expectations,
+INSTANTIATE_TEST_SUITE_P(GroupNonUniformQuadAnyKHR, GroupNonUniform,
+                         Combine(Values("OpGroupNonUniformQuadAnyKHR"),
+                                 Values("%bool"), Values(spv::Scope::Subgroup),
+                                 Values("%true"), Values("")));
+
 TEST_F(ValidateGroupNonUniform, VulkanGroupNonUniformBallotBitCountOperation) {
   std::string test = R"(
 OpCapability Shader
@@ -327,6 +924,146 @@
           "be only: Reduce, InclusiveScan, or ExclusiveScan."));
 }
 
+TEST_F(ValidateGroupNonUniform, BroadcastNonConstantSpv1p4) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability GroupNonUniformBallot
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main" %var
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %var DescriptorSet 0
+OpDecorate %var Binding 0
+OpDecorate %struct Block
+OpMemberDecorate %struct 0 Offset 0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%subgroup = OpConstant %int 3
+%struct = OpTypeStruct %int
+%ptr_struct = OpTypePointer StorageBuffer %struct
+%ptr_int = OpTypePointer StorageBuffer %int
+%var = OpVariable %ptr_struct StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%gep = OpAccessChain %ptr_int %var %int_0
+%ld = OpLoad %int %gep
+%broadcast = OpGroupNonUniformBroadcast %int %subgroup %int_0 %ld
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Before SPIR-V 1.5, Id must be a constant instruction"));
+}
+
+TEST_F(ValidateGroupNonUniform, BroadcastNonConstantSpv1p5) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability GroupNonUniformBallot
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main" %var
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %var DescriptorSet 0
+OpDecorate %var Binding 0
+OpDecorate %struct Block
+OpMemberDecorate %struct 0 Offset 0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%subgroup = OpConstant %int 3
+%struct = OpTypeStruct %int
+%ptr_struct = OpTypePointer StorageBuffer %struct
+%ptr_int = OpTypePointer StorageBuffer %int
+%var = OpVariable %ptr_struct StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%gep = OpAccessChain %ptr_int %var %int_0
+%ld = OpLoad %int %gep
+%broadcast = OpGroupNonUniformBroadcast %int %subgroup %int_0 %ld
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_5);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+}
+
+TEST_F(ValidateGroupNonUniform, QuadBroadcastNonConstantSpv1p4) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability GroupNonUniformQuad
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main" %var
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %var DescriptorSet 0
+OpDecorate %var Binding 0
+OpDecorate %struct Block
+OpMemberDecorate %struct 0 Offset 0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%subgroup = OpConstant %int 3
+%struct = OpTypeStruct %int
+%ptr_struct = OpTypePointer StorageBuffer %struct
+%ptr_int = OpTypePointer StorageBuffer %int
+%var = OpVariable %ptr_struct StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%gep = OpAccessChain %ptr_int %var %int_0
+%ld = OpLoad %int %gep
+%broadcast = OpGroupNonUniformQuadBroadcast %int %subgroup %int_0 %ld
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Before SPIR-V 1.5, Index must be a constant instruction"));
+}
+
+TEST_F(ValidateGroupNonUniform, QuadBroadcastNonConstantSpv1p5) {
+  const std::string text = R"(
+OpCapability Shader
+OpCapability GroupNonUniformQuad
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main" %var
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %var DescriptorSet 0
+OpDecorate %var Binding 0
+OpDecorate %struct Block
+OpMemberDecorate %struct 0 Offset 0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%subgroup = OpConstant %int 3
+%struct = OpTypeStruct %int
+%ptr_struct = OpTypePointer StorageBuffer %struct
+%ptr_int = OpTypePointer StorageBuffer %int
+%var = OpVariable %ptr_struct StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%gep = OpAccessChain %ptr_int %var %int_0
+%ld = OpLoad %int %gep
+%broadcast = OpGroupNonUniformQuadBroadcast %int %subgroup %int_0 %ld
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_5);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_ray_tracing_test.cpp b/third_party/SPIRV-Tools/test/val/val_ray_tracing_test.cpp
index 58b9356..60f2f89 100644
--- a/third_party/SPIRV-Tools/test/val/val_ray_tracing_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_ray_tracing_test.cpp
@@ -578,6 +578,95 @@
                         "IncomingRayPayloadKHR"));
 }
 
+TEST_F(ValidateRayTracing, InterfaceIncomingRayPayload) {
+  const std::string body = R"(
+OpCapability RayTracingKHR
+OpExtension "SPV_KHR_ray_tracing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint CallableKHR %main "main" %inData1 %inData2
+OpName %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%inData_ptr = OpTypePointer IncomingRayPayloadKHR %int
+%inData1 = OpVariable %inData_ptr IncomingRayPayloadKHR
+%inData2 = OpVariable %inData_ptr IncomingRayPayloadKHR
+%main = OpFunction %void None %func
+%label = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-IncomingRayPayloadKHR-04700"));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Entry-point has more than one variable with the "
+                "IncomingRayPayloadKHR storage class in the interface"));
+}
+
+TEST_F(ValidateRayTracing, InterfaceHitAttribute) {
+  const std::string body = R"(
+OpCapability RayTracingKHR
+OpExtension "SPV_KHR_ray_tracing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint CallableKHR %main "main" %inData1 %inData2
+OpName %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%inData_ptr = OpTypePointer HitAttributeKHR %int
+%inData1 = OpVariable %inData_ptr HitAttributeKHR
+%inData2 = OpVariable %inData_ptr HitAttributeKHR
+%main = OpFunction %void None %func
+%label = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04702"));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Entry-point has more than one variable with the "
+                        "HitAttributeKHR storage class in the interface"));
+}
+
+TEST_F(ValidateRayTracing, InterfaceIncomingCallableData) {
+  const std::string body = R"(
+OpCapability RayTracingKHR
+OpExtension "SPV_KHR_ray_tracing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint CallableKHR %main "main" %inData1 %inData2
+OpName %main "main"
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%inData_ptr = OpTypePointer IncomingCallableDataKHR %int
+%inData1 = OpVariable %inData_ptr IncomingCallableDataKHR
+%inData2 = OpVariable %inData_ptr IncomingCallableDataKHR
+%main = OpFunction %void None %func
+%label = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-StandaloneSpirv-IncomingCallableDataKHR-04706"));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Entry-point has more than one variable with the "
+                "IncomingCallableDataKHR storage class in the interface"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/third_party/SPIRV-Tools/tools/fuzz/fuzz.cpp b/third_party/SPIRV-Tools/tools/fuzz/fuzz.cpp
index ca6633a..5f2a008 100644
--- a/third_party/SPIRV-Tools/tools/fuzz/fuzz.cpp
+++ b/third_party/SPIRV-Tools/tools/fuzz/fuzz.cpp
@@ -41,12 +41,6 @@
 
 enum class FuzzingTarget { kSpirv, kWgsl };
 
-// Check that the std::system function can actually be used.
-bool CheckExecuteCommand() {
-  int res = std::system(nullptr);
-  return res != 0;
-}
-
 // Execute a command using the shell.
 // Returns true if and only if the command's exit status was 0.
 bool ExecuteCommand(const std::string& command) {
@@ -770,11 +764,6 @@
       }
       break;
     case FuzzActions::SHRINK: {
-      if (!CheckExecuteCommand()) {
-        std::cerr << "could not find shell interpreter for executing a command"
-                  << std::endl;
-        return 1;
-      }
       if (!Shrink(target_env, fuzzer_options, validator_options, binary_in,
                   initial_facts, shrink_transformations_file,
                   shrink_temp_file_prefix, interestingness_test, &binary_out,
diff --git a/third_party/SPIRV-Tools/tools/io.h b/third_party/SPIRV-Tools/tools/io.h
index 8bbee3a..a48e3c3 100644
--- a/third_party/SPIRV-Tools/tools/io.h
+++ b/third_party/SPIRV-Tools/tools/io.h
@@ -144,6 +144,7 @@
 
   ~OutputFile() {
     if (fp_ == stdout) {
+      fflush(stdout);
       SET_STDOUT_MODE(old_mode_);
     } else if (fp_ != nullptr) {
       fclose(fp_);
diff --git a/third_party/SPIRV-Tools/tools/link/linker.cpp b/third_party/SPIRV-Tools/tools/link/linker.cpp
index 381d8b9..f3898aa 100644
--- a/third_party/SPIRV-Tools/tools/link/linker.cpp
+++ b/third_party/SPIRV-Tools/tools/link/linker.cpp
@@ -59,6 +59,13 @@
                NOTE: The SPIR-V version used by the linked binary module
                depends only on the version of the inputs, and is not affected
                by this option.
+  --use-highest-version
+               Upgrade the output SPIR-V version to the highest of the input
+               files, instead of requiring all of them to have the same
+               version.
+               NOTE: If one of the older input files uses an instruction that
+               is deprecated in the highest SPIR-V version, the output will
+               be invalid.
   --verify-ids
                Verify that IDs in the resulting modules are truly unique.
   --version
@@ -78,6 +85,7 @@
 FLAG_LONG_bool(   allow_partial_linkage, /* default_value= */ false,               /* required= */ false);
 FLAG_SHORT_string(o,                     /* default_value= */ "",                  /* required= */ false);
 FLAG_LONG_string( target_env,            /* default_value= */ kDefaultEnvironment, /* required= */ false);
+FLAG_LONG_bool(   use_highest_version,   /* default_value= */ false,               /* required= */ false);
 // clang-format on
 
 int main(int, const char* argv[]) {
@@ -120,6 +128,7 @@
   options.SetAllowPartialLinkage(flags::allow_partial_linkage.value());
   options.SetCreateLibrary(flags::create_library.value());
   options.SetVerifyIds(flags::verify_ids.value());
+  options.SetUseHighestVersion(flags::use_highest_version.value());
 
   if (inFiles.empty()) {
     fprintf(stderr, "error: No input file specified\n");
diff --git a/third_party/SPIRV-Tools/tools/opt/opt.cpp b/third_party/SPIRV-Tools/tools/opt/opt.cpp
index ce2103c..f8456d7 100644
--- a/third_party/SPIRV-Tools/tools/opt/opt.cpp
+++ b/third_party/SPIRV-Tools/tools/opt/opt.cpp
@@ -335,6 +335,12 @@
                These conditions are guaranteed to be met after running
                dead-branch elimination.)");
   printf(R"(
+  --modify-maximal-reconvergence=[add|remove]
+               Add or remove the MaximallyReconvergesKHR execution mode to all
+               entry points in the module.
+               Note: when adding the execution mode, no attempt is made to
+               determine if any ray tracing repack instructions are used.)");
+  printf(R"(
   --loop-unswitch
                Hoists loop-invariant conditionals out of loops by duplicating
                the loop on each branch of the conditional and adjusting each
@@ -392,6 +398,11 @@
                Ensure that the optimizer preserves all bindings declared within
                the module, even when those bindings are unused.)");
   printf(R"(
+  --preserve-interface
+               Ensure that input and output variables are not removed from the
+               shader, even if they are unused. Note that this option applies to
+               all passes that will be run regardless of the order of the flags.)");
+  printf(R"(
   --preserve-spec-constants
                Ensure that the optimizer preserves all specialization constants declared
                within the module, even when those constants are unused.)");
@@ -496,6 +507,10 @@
                covers reflection information defined by
                SPV_GOOGLE_hlsl_functionality1 and SPV_KHR_non_semantic_info)");
   printf(R"(
+  --switch-descriptorset=<from>:<to>
+               Switch any DescriptoSet decorations using the value <from> to
+               the new value <to>.)");
+  printf(R"(
   --target-env=<env>
                Set the target environment. Without this flag the target
                environment defaults to spv1.5. <env> must be one of
@@ -510,6 +525,10 @@
                USR/SYS time are returned by getrusage() and can have a small
                error.)");
   printf(R"(
+  --trim-capabilities
+               Remove unnecessary capabilities and extensions declared within the
+               module.)");
+  printf(R"(
   --upgrade-memory-model
                Upgrades the Logical GLSL450 memory model to Logical VulkanKHR.
                Transforms memory, image, atomic and barrier operations to conform
@@ -697,6 +716,7 @@
                      spvtools::ValidatorOptions* validator_options,
                      spvtools::OptimizerOptions* optimizer_options) {
   std::vector<std::string> pass_flags;
+  bool preserve_interface = true;
   for (int argi = 1; argi < argc; ++argi) {
     const char* cur_arg = argv[argi];
     if ('-' == cur_arg[0]) {
@@ -786,6 +806,8 @@
         validator_options->SetSkipBlockLayout(true);
       } else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
         validator_options->SetRelaxStructStore(true);
+      } else if (0 == strcmp(cur_arg, "--preserve-interface")) {
+        preserve_interface = true;
       } else {
         // Some passes used to accept the form '--pass arg', canonicalize them
         // to '--pass=arg'.
@@ -808,7 +830,7 @@
     }
   }
 
-  if (!optimizer->RegisterPassesFromFlags(pass_flags)) {
+  if (!optimizer->RegisterPassesFromFlags(pass_flags, preserve_interface)) {
     return {OPT_STOP, 1};
   }
 
diff --git a/third_party/SPIRV-Tools/tools/reduce/reduce.cpp b/third_party/SPIRV-Tools/tools/reduce/reduce.cpp
index 3760054..959f5a2 100644
--- a/third_party/SPIRV-Tools/tools/reduce/reduce.cpp
+++ b/third_party/SPIRV-Tools/tools/reduce/reduce.cpp
@@ -14,6 +14,7 @@
 
 #include <cassert>
 #include <cerrno>
+#include <cstdlib>
 #include <cstring>
 #include <functional>
 #include <sstream>
@@ -29,12 +30,6 @@
 
 namespace {
 
-// Check that the std::system function can actually be used.
-bool CheckExecuteCommand() {
-  int res = std::system(nullptr);
-  return res != 0;
-}
-
 // Execute a command using the shell.
 // Returns true if and only if the command's exit status was 0.
 bool ExecuteCommand(const std::string& command) {
@@ -282,12 +277,6 @@
     return status.code;
   }
 
-  if (!CheckExecuteCommand()) {
-    std::cerr << "could not find shell interpreter for executing a command"
-              << std::endl;
-    return 2;
-  }
-
   spvtools::reduce::Reducer reducer(target_env);
 
   std::stringstream joined;
diff --git a/third_party/SPIRV-Tools/tools/sva/package.json b/third_party/SPIRV-Tools/tools/sva/package.json
index 3072d4c..15feaca 100644
--- a/third_party/SPIRV-Tools/tools/sva/package.json
+++ b/third_party/SPIRV-Tools/tools/sva/package.json
@@ -15,11 +15,11 @@
     "bundle": "rollup -c"
   },
   "devDependencies": {
-    "chai": "^4.2.0",
-    "eslint": "^6.3.0",
+    "chai": "^4.3.7",
+    "eslint": "^8.41.0",
     "esm": "^3.2.25",
-    "mocha": "^6.2.0",
-    "rollup": "^1.21.4",
-    "serve": "^11.1.0"
+    "mocha": "^10.2.0",
+    "rollup": "^3.23.0",
+    "serve": "^14.2.0"
   }
 }
diff --git a/third_party/SPIRV-Tools/tools/sva/src/spirv.data.js b/third_party/SPIRV-Tools/tools/sva/src/spirv.data.js
index ba969d8..67c0966 100644
--- a/third_party/SPIRV-Tools/tools/sva/src/spirv.data.js
+++ b/third_party/SPIRV-Tools/tools/sva/src/spirv.data.js
@@ -4376,6 +4376,9 @@
         "ShaderClockKHR": {
           "value": 5055
         },
+        "QuadControlKHR": {
+          "value": 5087
+        },
         "FragmentFullyCoveredEXT": {
           "value": 5265
         },
diff --git a/third_party/SPIRV-Tools/tools/sva/yarn.lock b/third_party/SPIRV-Tools/tools/sva/yarn.lock
index 2dc95d8..eed94ce 100644
--- a/third_party/SPIRV-Tools/tools/sva/yarn.lock
+++ b/third_party/SPIRV-Tools/tools/sva/yarn.lock
@@ -2,158 +2,206 @@
 # yarn lockfile v1
 
 
-"@babel/code-frame@^7.0.0":
-  version "7.5.5"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
-  integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==
+"@eslint-community/eslint-utils@^4.2.0":
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
+  integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
   dependencies:
-    "@babel/highlight" "^7.0.0"
+    eslint-visitor-keys "^3.3.0"
 
-"@babel/highlight@^7.0.0":
-  version "7.5.0"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540"
-  integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==
+"@eslint-community/regexpp@^4.4.0":
+  version "4.5.1"
+  resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884"
+  integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==
+
+"@eslint/eslintrc@^2.0.3":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331"
+  integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==
   dependencies:
-    chalk "^2.0.0"
-    esutils "^2.0.2"
-    js-tokens "^4.0.0"
+    ajv "^6.12.4"
+    debug "^4.3.2"
+    espree "^9.5.2"
+    globals "^13.19.0"
+    ignore "^5.2.0"
+    import-fresh "^3.2.1"
+    js-yaml "^4.1.0"
+    minimatch "^3.1.2"
+    strip-json-comments "^3.1.1"
 
-"@types/estree@0.0.39":
-  version "0.0.39"
-  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
-  integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+"@eslint/js@8.41.0":
+  version "8.41.0"
+  resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.41.0.tgz#080321c3b68253522f7646b55b577dd99d2950b3"
+  integrity sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==
 
-"@types/node@^12.7.5":
-  version "12.7.5"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.5.tgz#e19436e7f8e9b4601005d73673b6dc4784ffcc2f"
-  integrity sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==
+"@humanwhocodes/config-array@^0.11.8":
+  version "0.11.8"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
+  integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==
+  dependencies:
+    "@humanwhocodes/object-schema" "^1.2.1"
+    debug "^4.1.1"
+    minimatch "^3.0.5"
 
-"@zeit/schemas@2.6.0":
-  version "2.6.0"
-  resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.6.0.tgz#004e8e553b4cd53d538bd38eac7bcbf58a867fe3"
-  integrity sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==
+"@humanwhocodes/module-importer@^1.0.1":
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+  integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
+
+"@humanwhocodes/object-schema@^1.2.1":
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
+  integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
+
+"@nodelib/fs.scandir@2.1.5":
+  version "2.1.5"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+  integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+  dependencies:
+    "@nodelib/fs.stat" "2.0.5"
+    run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5":
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+  integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.8":
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+  integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+  dependencies:
+    "@nodelib/fs.scandir" "2.1.5"
+    fastq "^1.6.0"
+
+"@zeit/schemas@2.29.0":
+  version "2.29.0"
+  resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.29.0.tgz#a59ae6ebfdf4ddc66a876872dd736baa58b6696c"
+  integrity sha512-g5QiLIfbg3pLuYUJPlisNKY+epQJTcMDsOnVNkscrDP1oi7vmJnzOANYJI/1pZcVJ6umUkBv3aFtlg1UvUHGzA==
 
 accepts@~1.3.5:
-  version "1.3.7"
-  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
-  integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+  version "1.3.8"
+  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+  integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
   dependencies:
-    mime-types "~2.1.24"
-    negotiator "0.6.2"
+    mime-types "~2.1.34"
+    negotiator "0.6.3"
 
-acorn-jsx@^5.0.2:
+acorn-jsx@^5.3.2:
+  version "5.3.2"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
+  integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
+
+acorn@^8.8.0:
+  version "8.8.2"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
+  integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
+
+ajv@8.11.0:
+  version "8.11.0"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f"
+  integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    json-schema-traverse "^1.0.0"
+    require-from-string "^2.0.2"
+    uri-js "^4.2.2"
+
+ajv@^6.10.0, ajv@^6.12.4:
+  version "6.12.6"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+  integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+ansi-align@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59"
+  integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==
+  dependencies:
+    string-width "^4.1.0"
+
+ansi-colors@4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
+  integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
+
+ansi-regex@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+  integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-regex@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
+  integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+  dependencies:
+    color-convert "^2.0.1"
+
+ansi-styles@^6.1.0:
+  version "6.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
+  integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
+
+anymatch@~3.1.2:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+  integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+  dependencies:
+    normalize-path "^3.0.0"
+    picomatch "^2.0.4"
+
+arch@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
+  integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
+
+arg@5.0.2:
   version "5.0.2"
-  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f"
-  integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==
+  resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
+  integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
 
-acorn@^7.0.0:
-  version "7.1.1"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
-  integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==
-
-ajv@6.5.3:
-  version "6.5.3"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9"
-  integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==
-  dependencies:
-    fast-deep-equal "^2.0.1"
-    fast-json-stable-stringify "^2.0.0"
-    json-schema-traverse "^0.4.1"
-    uri-js "^4.2.2"
-
-ajv@^6.10.0, ajv@^6.10.2:
-  version "6.10.2"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
-  integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
-  dependencies:
-    fast-deep-equal "^2.0.1"
-    fast-json-stable-stringify "^2.0.0"
-    json-schema-traverse "^0.4.1"
-    uri-js "^4.2.2"
-
-ansi-align@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
-  integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
-  dependencies:
-    string-width "^2.0.0"
-
-ansi-colors@3.2.3:
-  version "3.2.3"
-  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
-  integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
-
-ansi-escapes@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
-  integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
-
-ansi-regex@^2.0.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
-  integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
-
-ansi-regex@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
-  integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
-
-ansi-regex@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
-  integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
-
-ansi-styles@^3.2.0, ansi-styles@^3.2.1:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
-  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
-  dependencies:
-    color-convert "^1.9.0"
-
-arch@^2.1.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e"
-  integrity sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg==
-
-arg@2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/arg/-/arg-2.0.0.tgz#c06e7ff69ab05b3a4a03ebe0407fac4cba657545"
-  integrity sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==
-
-argparse@^1.0.7:
-  version "1.0.10"
-  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
-  integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
-  dependencies:
-    sprintf-js "~1.0.2"
+argparse@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+  integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
 
 assertion-error@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
   integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
 
-astral-regex@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
-  integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
-
 balanced-match@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
-  integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
 
-boxen@1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
-  integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
+binary-extensions@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+  integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
+boxen@7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/boxen/-/boxen-7.0.0.tgz#9e5f8c26e716793fc96edcf7cf754cdf5e3fbf32"
+  integrity sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==
   dependencies:
-    ansi-align "^2.0.0"
-    camelcase "^4.0.0"
-    chalk "^2.0.1"
-    cli-boxes "^1.0.0"
-    string-width "^2.0.0"
-    term-size "^1.2.0"
-    widest-line "^2.0.0"
+    ansi-align "^3.0.1"
+    camelcase "^7.0.0"
+    chalk "^5.0.1"
+    cli-boxes "^3.0.0"
+    string-width "^5.1.2"
+    type-fest "^2.13.0"
+    widest-line "^4.0.1"
+    wrap-ansi "^8.0.1"
 
 brace-expansion@^1.1.7:
   version "1.1.11"
@@ -163,6 +211,20 @@
     balanced-match "^1.0.0"
     concat-map "0.0.1"
 
+brace-expansion@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+  integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+  dependencies:
+    balanced-match "^1.0.0"
+
+braces@~3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+  dependencies:
+    fill-range "^7.0.1"
+
 browser-stdout@1.3.1:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
@@ -171,163 +233,154 @@
 bytes@3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
-  integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
+  integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==
 
 callsites@^3.0.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
   integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
 
-camelcase@^4.0.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
-  integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
+camelcase@^6.0.0:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
+  integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
 
-camelcase@^5.0.0:
-  version "5.3.1"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
-  integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+camelcase@^7.0.0:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048"
+  integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==
 
-chai@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5"
-  integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==
+chai@^4.3.7:
+  version "4.3.7"
+  resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51"
+  integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==
   dependencies:
     assertion-error "^1.1.0"
     check-error "^1.0.2"
-    deep-eql "^3.0.1"
+    deep-eql "^4.1.2"
     get-func-name "^2.0.0"
-    pathval "^1.1.0"
+    loupe "^2.3.1"
+    pathval "^1.1.1"
     type-detect "^4.0.5"
 
-chalk@2.4.1:
-  version "2.4.1"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
-  integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==
+chalk-template@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.4.0.tgz#692c034d0ed62436b9062c1707fadcd0f753204b"
+  integrity sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==
   dependencies:
-    ansi-styles "^3.2.1"
-    escape-string-regexp "^1.0.5"
-    supports-color "^5.3.0"
+    chalk "^4.1.2"
 
-chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2:
-  version "2.4.2"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
-  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+chalk@5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6"
+  integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==
+
+chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
   dependencies:
-    ansi-styles "^3.2.1"
-    escape-string-regexp "^1.0.5"
-    supports-color "^5.3.0"
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
 
-chardet@^0.7.0:
-  version "0.7.0"
-  resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
-  integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+chalk@^5.0.1:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3"
+  integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==
 
 check-error@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
-  integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
+  integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==
 
-cli-boxes@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
-  integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
-
-cli-cursor@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
-  integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
+chokidar@3.5.3:
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+  integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
   dependencies:
-    restore-cursor "^2.0.0"
+    anymatch "~3.1.2"
+    braces "~3.0.2"
+    glob-parent "~5.1.2"
+    is-binary-path "~2.1.0"
+    is-glob "~4.0.1"
+    normalize-path "~3.0.0"
+    readdirp "~3.6.0"
+  optionalDependencies:
+    fsevents "~2.3.2"
 
-cli-width@^2.0.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
-  integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+cli-boxes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145"
+  integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==
 
-clipboardy@1.2.3:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef"
-  integrity sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==
+clipboardy@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092"
+  integrity sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==
   dependencies:
-    arch "^2.1.0"
-    execa "^0.8.0"
+    arch "^2.2.0"
+    execa "^5.1.1"
+    is-wsl "^2.2.0"
 
-cliui@^4.0.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
-  integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==
+cliui@^7.0.2:
+  version "7.0.4"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+  integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
   dependencies:
-    string-width "^2.1.1"
-    strip-ansi "^4.0.0"
-    wrap-ansi "^2.0.0"
+    string-width "^4.2.0"
+    strip-ansi "^6.0.0"
+    wrap-ansi "^7.0.0"
 
-code-point-at@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
-  integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
-
-color-convert@^1.9.0:
-  version "1.9.3"
-  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
-  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+color-convert@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
   dependencies:
-    color-name "1.1.3"
+    color-name "~1.1.4"
 
-color-name@1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
-  integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+color-name@~1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
 
-compressible@~2.0.14:
-  version "2.0.17"
-  resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1"
-  integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==
+compressible@~2.0.16:
+  version "2.0.18"
+  resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
+  integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
   dependencies:
-    mime-db ">= 1.40.0 < 2"
+    mime-db ">= 1.43.0 < 2"
 
-compression@1.7.3:
-  version "1.7.3"
-  resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db"
-  integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==
+compression@1.7.4:
+  version "1.7.4"
+  resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
+  integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
   dependencies:
     accepts "~1.3.5"
     bytes "3.0.0"
-    compressible "~2.0.14"
+    compressible "~2.0.16"
     debug "2.6.9"
-    on-headers "~1.0.1"
+    on-headers "~1.0.2"
     safe-buffer "5.1.2"
     vary "~1.1.2"
 
 concat-map@0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-  integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+  integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
 
 content-disposition@0.5.2:
   version "0.5.2"
   resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
-  integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
+  integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==
 
-cross-spawn@^5.0.1:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
-  integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
+cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+  integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
   dependencies:
-    lru-cache "^4.0.1"
-    shebang-command "^1.2.0"
-    which "^1.2.9"
-
-cross-spawn@^6.0.0, cross-spawn@^6.0.5:
-  version "6.0.5"
-  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
-  integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
-  dependencies:
-    nice-try "^1.0.4"
-    path-key "^2.0.1"
-    semver "^5.5.0"
-    shebang-command "^1.2.0"
-    which "^1.2.9"
+    path-key "^3.1.0"
+    shebang-command "^2.0.0"
+    which "^2.0.1"
 
 debug@2.6.9:
   version "2.6.9"
@@ -336,29 +389,22 @@
   dependencies:
     ms "2.0.0"
 
-debug@3.2.6:
-  version "3.2.6"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
-  integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+debug@4.3.4, debug@^4.1.1, debug@^4.3.2:
+  version "4.3.4"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
   dependencies:
-    ms "^2.1.1"
+    ms "2.1.2"
 
-debug@^4.0.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
-  integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
-  dependencies:
-    ms "^2.1.1"
+decamelize@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
+  integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
 
-decamelize@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
-  integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
-
-deep-eql@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
-  integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==
+deep-eql@^4.1.2:
+  version "4.1.3"
+  resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d"
+  integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==
   dependencies:
     type-detect "^4.0.0"
 
@@ -367,22 +413,15 @@
   resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
   integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
 
-deep-is@~0.1.3:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
-  integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
+deep-is@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+  integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
 
-define-properties@^1.1.2, define-properties@^1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
-  integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
-  dependencies:
-    object-keys "^1.0.12"
-
-diff@3.5.0:
-  version "3.5.0"
-  resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
-  integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+diff@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
+  integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
 
 doctrine@^3.0.0:
   version "3.0.0"
@@ -391,319 +430,254 @@
   dependencies:
     esutils "^2.0.2"
 
-emoji-regex@^7.0.1:
-  version "7.0.3"
-  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
-  integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+eastasianwidth@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
+  integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
 
-end-of-stream@^1.1.0:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
-  integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
+emoji-regex@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+  integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+emoji-regex@^9.2.2:
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
+  integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+
+escalade@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+  integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+  integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+eslint-scope@^7.2.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b"
+  integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
   dependencies:
-    once "^1.4.0"
+    esrecurse "^4.3.0"
+    estraverse "^5.2.0"
 
-es-abstract@^1.5.1:
-  version "1.14.2"
-  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497"
-  integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994"
+  integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
+
+eslint@^8.41.0:
+  version "8.41.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.41.0.tgz#3062ca73363b4714b16dbc1e60f035e6134b6f1c"
+  integrity sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==
   dependencies:
-    es-to-primitive "^1.2.0"
-    function-bind "^1.1.1"
-    has "^1.0.3"
-    has-symbols "^1.0.0"
-    is-callable "^1.1.4"
-    is-regex "^1.0.4"
-    object-inspect "^1.6.0"
-    object-keys "^1.1.1"
-    string.prototype.trimleft "^2.0.0"
-    string.prototype.trimright "^2.0.0"
-
-es-to-primitive@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377"
-  integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==
-  dependencies:
-    is-callable "^1.1.4"
-    is-date-object "^1.0.1"
-    is-symbol "^1.0.2"
-
-escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
-  integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-
-eslint-scope@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9"
-  integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==
-  dependencies:
-    esrecurse "^4.1.0"
-    estraverse "^4.1.1"
-
-eslint-utils@^1.4.2:
-  version "1.4.2"
-  resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab"
-  integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==
-  dependencies:
-    eslint-visitor-keys "^1.0.0"
-
-eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
-  integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
-
-eslint@^6.3.0:
-  version "6.4.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.4.0.tgz#5aa9227c3fbe921982b2eda94ba0d7fae858611a"
-  integrity sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==
-  dependencies:
-    "@babel/code-frame" "^7.0.0"
+    "@eslint-community/eslint-utils" "^4.2.0"
+    "@eslint-community/regexpp" "^4.4.0"
+    "@eslint/eslintrc" "^2.0.3"
+    "@eslint/js" "8.41.0"
+    "@humanwhocodes/config-array" "^0.11.8"
+    "@humanwhocodes/module-importer" "^1.0.1"
+    "@nodelib/fs.walk" "^1.2.8"
     ajv "^6.10.0"
-    chalk "^2.1.0"
-    cross-spawn "^6.0.5"
-    debug "^4.0.1"
+    chalk "^4.0.0"
+    cross-spawn "^7.0.2"
+    debug "^4.3.2"
     doctrine "^3.0.0"
-    eslint-scope "^5.0.0"
-    eslint-utils "^1.4.2"
-    eslint-visitor-keys "^1.1.0"
-    espree "^6.1.1"
-    esquery "^1.0.1"
+    escape-string-regexp "^4.0.0"
+    eslint-scope "^7.2.0"
+    eslint-visitor-keys "^3.4.1"
+    espree "^9.5.2"
+    esquery "^1.4.2"
     esutils "^2.0.2"
-    file-entry-cache "^5.0.1"
-    functional-red-black-tree "^1.0.1"
-    glob-parent "^5.0.0"
-    globals "^11.7.0"
-    ignore "^4.0.6"
+    fast-deep-equal "^3.1.3"
+    file-entry-cache "^6.0.1"
+    find-up "^5.0.0"
+    glob-parent "^6.0.2"
+    globals "^13.19.0"
+    graphemer "^1.4.0"
+    ignore "^5.2.0"
     import-fresh "^3.0.0"
     imurmurhash "^0.1.4"
-    inquirer "^6.4.1"
     is-glob "^4.0.0"
-    js-yaml "^3.13.1"
+    is-path-inside "^3.0.3"
+    js-yaml "^4.1.0"
     json-stable-stringify-without-jsonify "^1.0.1"
-    levn "^0.3.0"
-    lodash "^4.17.14"
-    minimatch "^3.0.4"
-    mkdirp "^0.5.1"
+    levn "^0.4.1"
+    lodash.merge "^4.6.2"
+    minimatch "^3.1.2"
     natural-compare "^1.4.0"
-    optionator "^0.8.2"
-    progress "^2.0.0"
-    regexpp "^2.0.1"
-    semver "^6.1.2"
-    strip-ansi "^5.2.0"
-    strip-json-comments "^3.0.1"
-    table "^5.2.3"
+    optionator "^0.9.1"
+    strip-ansi "^6.0.1"
+    strip-json-comments "^3.1.0"
     text-table "^0.2.0"
-    v8-compile-cache "^2.0.3"
 
 esm@^3.2.25:
   version "3.2.25"
   resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
   integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
 
-espree@^6.1.1:
-  version "6.1.1"
-  resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de"
-  integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==
+espree@^9.5.2:
+  version "9.5.2"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b"
+  integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==
   dependencies:
-    acorn "^7.0.0"
-    acorn-jsx "^5.0.2"
-    eslint-visitor-keys "^1.1.0"
+    acorn "^8.8.0"
+    acorn-jsx "^5.3.2"
+    eslint-visitor-keys "^3.4.1"
 
-esprima@^4.0.0:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
-  integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-
-esquery@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
-  integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
+esquery@^1.4.2:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
+  integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
   dependencies:
-    estraverse "^4.0.0"
+    estraverse "^5.1.0"
 
-esrecurse@^4.1.0:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
-  integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
-  dependencies:
-    estraverse "^4.1.0"
-
-estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
+esrecurse@^4.3.0:
   version "4.3.0"
-  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
-  integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+  integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+  dependencies:
+    estraverse "^5.2.0"
+
+estraverse@^5.1.0, estraverse@^5.2.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+  integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
 
 esutils@^2.0.2:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
   integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
 
-execa@^0.7.0:
-  version "0.7.0"
-  resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
-  integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
+execa@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+  integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
   dependencies:
-    cross-spawn "^5.0.1"
-    get-stream "^3.0.0"
-    is-stream "^1.1.0"
-    npm-run-path "^2.0.0"
-    p-finally "^1.0.0"
-    signal-exit "^3.0.0"
-    strip-eof "^1.0.0"
+    cross-spawn "^7.0.3"
+    get-stream "^6.0.0"
+    human-signals "^2.1.0"
+    is-stream "^2.0.0"
+    merge-stream "^2.0.0"
+    npm-run-path "^4.0.1"
+    onetime "^5.1.2"
+    signal-exit "^3.0.3"
+    strip-final-newline "^2.0.0"
 
-execa@^0.8.0:
-  version "0.8.0"
-  resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da"
-  integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=
-  dependencies:
-    cross-spawn "^5.0.1"
-    get-stream "^3.0.0"
-    is-stream "^1.1.0"
-    npm-run-path "^2.0.0"
-    p-finally "^1.0.0"
-    signal-exit "^3.0.0"
-    strip-eof "^1.0.0"
-
-execa@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
-  integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
-  dependencies:
-    cross-spawn "^6.0.0"
-    get-stream "^4.0.0"
-    is-stream "^1.1.0"
-    npm-run-path "^2.0.0"
-    p-finally "^1.0.0"
-    signal-exit "^3.0.0"
-    strip-eof "^1.0.0"
-
-external-editor@^3.0.3:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
-  integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
-  dependencies:
-    chardet "^0.7.0"
-    iconv-lite "^0.4.24"
-    tmp "^0.0.33"
-
-fast-deep-equal@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
-  integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+  integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
 
 fast-json-stable-stringify@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
-  integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
 
-fast-levenshtein@~2.0.4:
+fast-levenshtein@^2.0.6:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
-  integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+  integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
 
 fast-url-parser@1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d"
-  integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=
+  integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==
   dependencies:
     punycode "^1.3.2"
 
-figures@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
-  integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
+fastq@^1.6.0:
+  version "1.15.0"
+  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
+  integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
   dependencies:
-    escape-string-regexp "^1.0.5"
+    reusify "^1.0.4"
 
-file-entry-cache@^5.0.1:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
-  integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
+file-entry-cache@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
+  integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
   dependencies:
-    flat-cache "^2.0.1"
+    flat-cache "^3.0.4"
 
-find-up@3.0.0, find-up@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
-  integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+fill-range@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
   dependencies:
-    locate-path "^3.0.0"
+    to-regex-range "^5.0.1"
 
-flat-cache@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
-  integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
+find-up@5.0.0, find-up@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+  integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
   dependencies:
-    flatted "^2.0.0"
-    rimraf "2.6.3"
-    write "1.0.3"
+    locate-path "^6.0.0"
+    path-exists "^4.0.0"
 
-flat@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2"
-  integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==
+flat-cache@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
+  integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
   dependencies:
-    is-buffer "~2.0.3"
+    flatted "^3.1.0"
+    rimraf "^3.0.2"
 
-flatted@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
-  integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
+flat@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
+  integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
+
+flatted@^3.1.0:
+  version "3.2.7"
+  resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
+  integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
 
 fs.realpath@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
-  integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+  integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
 
-function-bind@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
-  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+fsevents@~2.3.2:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
 
-functional-red-black-tree@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
-  integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
-
-get-caller-file@^1.0.1:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
-  integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
-
-get-caller-file@^2.0.1:
+get-caller-file@^2.0.5:
   version "2.0.5"
   resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
   integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
 
 get-func-name@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
-  integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41"
+  integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==
 
-get-stream@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
-  integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
+get-stream@^6.0.0:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+  integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
 
-get-stream@^4.0.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
-  integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
+glob-parent@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+  integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
   dependencies:
-    pump "^3.0.0"
+    is-glob "^4.0.3"
 
-glob-parent@^5.0.0:
+glob-parent@~5.1.2:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
   integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
   dependencies:
     is-glob "^4.0.1"
 
-glob@7.1.3:
-  version "7.1.3"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
-  integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
+glob@7.2.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
+  integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
   dependencies:
     fs.realpath "^1.0.0"
     inflight "^1.0.4"
@@ -713,65 +687,53 @@
     path-is-absolute "^1.0.0"
 
 glob@^7.1.3:
-  version "7.1.4"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
-  integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
+  version "7.2.3"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+  integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
   dependencies:
     fs.realpath "^1.0.0"
     inflight "^1.0.4"
     inherits "2"
-    minimatch "^3.0.4"
+    minimatch "^3.1.1"
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-globals@^11.7.0:
-  version "11.12.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
-  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-
-growl@1.10.5:
-  version "1.10.5"
-  resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
-  integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
-
-has-flag@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
-  integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
-
-has-symbols@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
-  integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
-
-has@^1.0.1, has@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
-  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+globals@^13.19.0:
+  version "13.20.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
+  integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
   dependencies:
-    function-bind "^1.1.1"
+    type-fest "^0.20.2"
+
+graphemer@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
+  integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
+
+has-flag@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
 
 he@1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
   integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
 
-iconv-lite@^0.4.24:
-  version "0.4.24"
-  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
-  integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
-  dependencies:
-    safer-buffer ">= 2.1.2 < 3"
+human-signals@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+  integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
 
-ignore@^4.0.6:
-  version "4.0.6"
-  resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
-  integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+ignore@^5.2.0:
+  version "5.2.4"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
+  integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
 
-import-fresh@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118"
-  integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==
+import-fresh@^3.0.0, import-fresh@^3.2.1:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+  integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
   dependencies:
     parent-module "^1.0.0"
     resolve-from "^4.0.0"
@@ -779,12 +741,12 @@
 imurmurhash@^0.1.4:
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
-  integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+  integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
 
 inflight@^1.0.4:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
-  integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+  integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
   dependencies:
     once "^1.3.0"
     wrappy "1"
@@ -795,193 +757,147 @@
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
 
 ini@~1.3.0:
-  version "1.3.7"
-  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
-  integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
+  version "1.3.8"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
+  integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
 
-inquirer@^6.4.1:
-  version "6.5.2"
-  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca"
-  integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==
+is-binary-path@~2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+  integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
   dependencies:
-    ansi-escapes "^3.2.0"
-    chalk "^2.4.2"
-    cli-cursor "^2.1.0"
-    cli-width "^2.0.0"
-    external-editor "^3.0.3"
-    figures "^2.0.0"
-    lodash "^4.17.12"
-    mute-stream "0.0.7"
-    run-async "^2.2.0"
-    rxjs "^6.4.0"
-    string-width "^2.1.0"
-    strip-ansi "^5.1.0"
-    through "^2.3.6"
+    binary-extensions "^2.0.0"
 
-invert-kv@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
-  integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
-
-is-buffer@~2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
-  integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
-
-is-callable@^1.1.4:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
-  integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
-
-is-date-object@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
-  integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=
+is-docker@^2.0.0:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
+  integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
 
 is-extglob@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
-  integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+  integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
 
-is-fullwidth-code-point@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
-  integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
-  dependencies:
-    number-is-nan "^1.0.0"
+is-fullwidth-code-point@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+  integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
 
-is-fullwidth-code-point@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
-  integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
-
-is-glob@^4.0.0, is-glob@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
-  integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+  integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
   dependencies:
     is-extglob "^2.1.1"
 
-is-promise@^2.1.0:
+is-number@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-path-inside@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+  integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+is-plain-obj@^2.1.0:
   version "2.1.0"
-  resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
-  integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
+  integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
 
-is-regex@^1.0.4:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
-  integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=
+is-port-reachable@4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d"
+  integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==
+
+is-stream@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+  integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
+is-unicode-supported@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
+  integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
+
+is-wsl@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
+  integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
   dependencies:
-    has "^1.0.1"
-
-is-stream@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
-  integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
-
-is-symbol@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
-  integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==
-  dependencies:
-    has-symbols "^1.0.0"
+    is-docker "^2.0.0"
 
 isexe@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
-  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+  integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
 
-js-tokens@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
-  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-
-js-yaml@3.13.1, js-yaml@^3.13.1:
-  version "3.13.1"
-  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
-  integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+js-yaml@4.1.0, js-yaml@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+  integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
   dependencies:
-    argparse "^1.0.7"
-    esprima "^4.0.0"
+    argparse "^2.0.1"
 
 json-schema-traverse@^0.4.1:
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
   integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
 
+json-schema-traverse@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+  integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
 json-stable-stringify-without-jsonify@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
-  integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+  integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
 
-lcid@^2.0.0:
+levn@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+  integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
+  dependencies:
+    prelude-ls "^1.2.1"
+    type-check "~0.4.0"
+
+locate-path@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+  integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+  dependencies:
+    p-locate "^5.0.0"
+
+lodash.merge@^4.6.2:
+  version "4.6.2"
+  resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+  integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
+log-symbols@4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
+  integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
+  dependencies:
+    chalk "^4.1.0"
+    is-unicode-supported "^0.1.0"
+
+loupe@^2.3.1:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53"
+  integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==
+  dependencies:
+    get-func-name "^2.0.0"
+
+merge-stream@^2.0.0:
   version "2.0.0"
-  resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
-  integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==
-  dependencies:
-    invert-kv "^2.0.0"
+  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+  integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
 
-levn@^0.3.0, levn@~0.3.0:
-  version "0.3.0"
-  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
-  integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
-  dependencies:
-    prelude-ls "~1.1.2"
-    type-check "~0.3.2"
-
-locate-path@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
-  integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
-  dependencies:
-    p-locate "^3.0.0"
-    path-exists "^3.0.0"
-
-lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14:
-  version "4.17.21"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
-  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-log-symbols@2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
-  integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
-  dependencies:
-    chalk "^2.0.1"
-
-lru-cache@^4.0.1:
-  version "4.1.5"
-  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
-  integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
-  dependencies:
-    pseudomap "^1.0.2"
-    yallist "^2.1.2"
-
-map-age-cleaner@^0.1.1:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
-  integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
-  dependencies:
-    p-defer "^1.0.0"
-
-mem@^4.0.0:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
-  integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==
-  dependencies:
-    map-age-cleaner "^0.1.1"
-    mimic-fn "^2.0.0"
-    p-is-promise "^2.0.0"
-
-mime-db@1.40.0:
-  version "1.40.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
-  integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
-
-"mime-db@>= 1.40.0 < 2":
-  version "1.41.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.41.0.tgz#9110408e1f6aa1b34aef51f2c9df3caddf46b6a0"
-  integrity sha512-B5gxBI+2K431XW8C2rcc/lhppbuji67nf9v39eH8pkWoZDxnAL0PxdpH32KYRScniF8qDHBDlI+ipgg5WrCUYw==
+mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
+  version "1.52.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
 
 mime-db@~1.33.0:
   version "1.33.0"
@@ -995,237 +911,150 @@
   dependencies:
     mime-db "~1.33.0"
 
-mime-types@~2.1.24:
-  version "2.1.24"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
-  integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
+mime-types@~2.1.34:
+  version "2.1.35"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
   dependencies:
-    mime-db "1.40.0"
+    mime-db "1.52.0"
 
-mimic-fn@^1.0.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
-  integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
-
-mimic-fn@^2.0.0:
+mimic-fn@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
   integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
 
-minimatch@3.0.4, minimatch@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
-  integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
   dependencies:
     brace-expansion "^1.1.7"
 
-minimist@0.0.8:
-  version "0.0.8"
-  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
-  integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+minimatch@5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b"
+  integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==
+  dependencies:
+    brace-expansion "^2.0.1"
 
 minimist@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
-  integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+  integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
 
-mkdirp@0.5.1, mkdirp@^0.5.1:
-  version "0.5.1"
-  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
-  integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+mocha@^10.2.0:
+  version "10.2.0"
+  resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8"
+  integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==
   dependencies:
-    minimist "0.0.8"
-
-mocha@^6.2.0:
-  version "6.2.0"
-  resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.0.tgz#f896b642843445d1bb8bca60eabd9206b8916e56"
-  integrity sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==
-  dependencies:
-    ansi-colors "3.2.3"
+    ansi-colors "4.1.1"
     browser-stdout "1.3.1"
-    debug "3.2.6"
-    diff "3.5.0"
-    escape-string-regexp "1.0.5"
-    find-up "3.0.0"
-    glob "7.1.3"
-    growl "1.10.5"
+    chokidar "3.5.3"
+    debug "4.3.4"
+    diff "5.0.0"
+    escape-string-regexp "4.0.0"
+    find-up "5.0.0"
+    glob "7.2.0"
     he "1.2.0"
-    js-yaml "3.13.1"
-    log-symbols "2.2.0"
-    minimatch "3.0.4"
-    mkdirp "0.5.1"
-    ms "2.1.1"
-    node-environment-flags "1.0.5"
-    object.assign "4.1.0"
-    strip-json-comments "2.0.1"
-    supports-color "6.0.0"
-    which "1.3.1"
-    wide-align "1.1.3"
-    yargs "13.2.2"
-    yargs-parser "13.0.0"
-    yargs-unparser "1.5.0"
+    js-yaml "4.1.0"
+    log-symbols "4.1.0"
+    minimatch "5.0.1"
+    ms "2.1.3"
+    nanoid "3.3.3"
+    serialize-javascript "6.0.0"
+    strip-json-comments "3.1.1"
+    supports-color "8.1.1"
+    workerpool "6.2.1"
+    yargs "16.2.0"
+    yargs-parser "20.2.4"
+    yargs-unparser "2.0.0"
 
 ms@2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
-  integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+  integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
 
-ms@2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
-  integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-
-ms@^2.1.1:
+ms@2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
 
-mute-stream@0.0.7:
-  version "0.0.7"
-  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
-  integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
+ms@2.1.3:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+nanoid@3.3.3:
+  version "3.3.3"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
+  integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==
 
 natural-compare@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
-  integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
+  integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
 
-negotiator@0.6.2:
-  version "0.6.2"
-  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
-  integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+negotiator@0.6.3:
+  version "0.6.3"
+  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+  integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
 
-nice-try@^1.0.4:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
-  integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
 
-node-environment-flags@1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a"
-  integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==
+npm-run-path@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+  integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
   dependencies:
-    object.getownpropertydescriptors "^2.0.3"
-    semver "^5.7.0"
+    path-key "^3.0.0"
 
-npm-run-path@^2.0.0:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
-  integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
-  dependencies:
-    path-key "^2.0.0"
-
-number-is-nan@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
-  integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
-
-object-inspect@^1.6.0:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b"
-  integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==
-
-object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
-  integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-
-object.assign@4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
-  integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
-  dependencies:
-    define-properties "^1.1.2"
-    function-bind "^1.1.1"
-    has-symbols "^1.0.0"
-    object-keys "^1.0.11"
-
-object.getownpropertydescriptors@^2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
-  integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=
-  dependencies:
-    define-properties "^1.1.2"
-    es-abstract "^1.5.1"
-
-on-headers@~1.0.1:
+on-headers@~1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
   integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
 
-once@^1.3.0, once@^1.3.1, once@^1.4.0:
+once@^1.3.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
-  integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+  integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
   dependencies:
     wrappy "1"
 
-onetime@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
-  integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
+onetime@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+  integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
   dependencies:
-    mimic-fn "^1.0.0"
+    mimic-fn "^2.1.0"
 
-optionator@^0.8.2:
-  version "0.8.2"
-  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
-  integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=
+optionator@^0.9.1:
+  version "0.9.1"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
+  integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
   dependencies:
-    deep-is "~0.1.3"
-    fast-levenshtein "~2.0.4"
-    levn "~0.3.0"
-    prelude-ls "~1.1.2"
-    type-check "~0.3.2"
-    wordwrap "~1.0.0"
+    deep-is "^0.1.3"
+    fast-levenshtein "^2.0.6"
+    levn "^0.4.1"
+    prelude-ls "^1.2.1"
+    type-check "^0.4.0"
+    word-wrap "^1.2.3"
 
-os-locale@^3.0.0, os-locale@^3.1.0:
+p-limit@^3.0.2:
   version "3.1.0"
-  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
-  integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
   dependencies:
-    execa "^1.0.0"
-    lcid "^2.0.0"
-    mem "^4.0.0"
+    yocto-queue "^0.1.0"
 
-os-tmpdir@~1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
-  integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-
-p-defer@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
-  integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
-
-p-finally@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
-  integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
-
-p-is-promise@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
-  integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
-
-p-limit@^2.0.0:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537"
-  integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==
+p-locate@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+  integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
   dependencies:
-    p-try "^2.0.0"
-
-p-locate@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
-  integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
-  dependencies:
-    p-limit "^2.0.0"
-
-p-try@^2.0.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
-  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+    p-limit "^3.0.2"
 
 parent-module@^1.0.0:
   version "1.0.1"
@@ -1234,73 +1063,72 @@
   dependencies:
     callsites "^3.0.0"
 
-path-exists@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
-  integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+path-exists@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+  integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
 
 path-is-absolute@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
-  integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+  integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
 
 path-is-inside@1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
-  integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+  integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==
 
-path-key@^2.0.0, path-key@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
-  integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+path-key@^3.0.0, path-key@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+  integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
 
 path-to-regexp@2.2.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45"
   integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==
 
-pathval@^1.1.0:
+pathval@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
   integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
 
-prelude-ls@~1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
-  integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
+picomatch@^2.0.4, picomatch@^2.2.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
 
-progress@^2.0.0:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
-  integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
-
-pseudomap@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
-  integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
-
-pump@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
-  integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
-  dependencies:
-    end-of-stream "^1.1.0"
-    once "^1.3.1"
+prelude-ls@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+  integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
 
 punycode@^1.3.2:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
-  integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
+  integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==
 
 punycode@^2.1.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
-  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
+  integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
+
+queue-microtask@^1.2.2:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+  integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+randombytes@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+  integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+  dependencies:
+    safe-buffer "^5.1.0"
 
 range-parser@1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
-  integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
+  integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==
 
 rc@^1.0.1, rc@^1.1.6:
   version "1.2.8"
@@ -1312,10 +1140,12 @@
     minimist "^1.2.0"
     strip-json-comments "~2.0.1"
 
-regexpp@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
-  integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
+readdirp@~3.6.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+  integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+  dependencies:
+    picomatch "^2.2.1"
 
 registry-auth-token@3.3.2:
   version "3.3.2"
@@ -1328,451 +1158,317 @@
 registry-url@3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
-  integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
+  integrity sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==
   dependencies:
     rc "^1.0.1"
 
 require-directory@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
-  integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+  integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
 
-require-main-filename@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
-  integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
-
-require-main-filename@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
-  integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+require-from-string@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+  integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
 
 resolve-from@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
   integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
 
-restore-cursor@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
-  integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
-  dependencies:
-    onetime "^2.0.0"
-    signal-exit "^3.0.2"
+reusify@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 
-rimraf@2.6.3:
-  version "2.6.3"
-  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
-  integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+rimraf@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+  integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
   dependencies:
     glob "^7.1.3"
 
-rollup@^1.21.4:
-  version "1.21.4"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.21.4.tgz#00a41a30f90095db890301b226cbe2918e4cf54d"
-  integrity sha512-Pl512XVCmVzgcBz5h/3Li4oTaoDcmpuFZ+kdhS/wLreALz//WuDAMfomD3QEYl84NkDu6Z6wV9twlcREb4qQsw==
-  dependencies:
-    "@types/estree" "0.0.39"
-    "@types/node" "^12.7.5"
-    acorn "^7.0.0"
+rollup@^3.23.0:
+  version "3.23.0"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.23.0.tgz#b8d6146dac4bf058ee817f92820988e9b358b564"
+  integrity sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==
+  optionalDependencies:
+    fsevents "~2.3.2"
 
-run-async@^2.2.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
-  integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
+run-parallel@^1.1.9:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+  integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
   dependencies:
-    is-promise "^2.1.0"
-
-rxjs@^6.4.0:
-  version "6.5.3"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a"
-  integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==
-  dependencies:
-    tslib "^1.9.0"
+    queue-microtask "^1.2.2"
 
 safe-buffer@5.1.2:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
   integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
 
-safe-buffer@^5.0.1:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
-  integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+safe-buffer@^5.0.1, safe-buffer@^5.1.0:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+  integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
 
-"safer-buffer@>= 2.1.2 < 3":
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
-  integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+serialize-javascript@6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
+  integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
+  dependencies:
+    randombytes "^2.1.0"
 
-semver@^5.5.0, semver@^5.7.0:
-  version "5.7.1"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
-  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
-
-semver@^6.1.2:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
-  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-serve-handler@6.1.0:
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.0.tgz#f1606dc6ff8f9029a1ee042c11dfe7903a5cb92e"
-  integrity sha512-63N075Tn3PsFYcu0NVV7tb367UbiW3gnC+/50ohL4oqOhAG6bmbaWqiRcXQgbzqc0ALBjSAzg7VTfa0Qw4E3hA==
+serve-handler@6.1.5:
+  version "6.1.5"
+  resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.5.tgz#a4a0964f5c55c7e37a02a633232b6f0d6f068375"
+  integrity sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==
   dependencies:
     bytes "3.0.0"
     content-disposition "0.5.2"
     fast-url-parser "1.1.3"
     mime-types "2.1.18"
-    minimatch "3.0.4"
+    minimatch "3.1.2"
     path-is-inside "1.0.2"
     path-to-regexp "2.2.1"
     range-parser "1.2.0"
 
-serve@^11.1.0:
-  version "11.1.0"
-  resolved "https://registry.yarnpkg.com/serve/-/serve-11.1.0.tgz#1bfe2f4a08d0130cbf44711cdb7996cb742172e0"
-  integrity sha512-+4wpDtOSS+4ZLyDWMxThutA3iOTawX2+yDovOI8cjOUOmemyvNlHyFAsezBlSgbZKTYChI3tzA1Mh0z6XZ62qA==
+serve@^14.2.0:
+  version "14.2.0"
+  resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.0.tgz#3d768e88fa13ad8644f2393599189707176e66b8"
+  integrity sha512-+HOw/XK1bW8tw5iBilBz/mJLWRzM8XM6MPxL4J/dKzdxq1vfdEWSwhaR7/yS8EJp5wzvP92p1qirysJvnEtjXg==
   dependencies:
-    "@zeit/schemas" "2.6.0"
-    ajv "6.5.3"
-    arg "2.0.0"
-    boxen "1.3.0"
-    chalk "2.4.1"
-    clipboardy "1.2.3"
-    compression "1.7.3"
-    serve-handler "6.1.0"
-    update-check "1.5.2"
+    "@zeit/schemas" "2.29.0"
+    ajv "8.11.0"
+    arg "5.0.2"
+    boxen "7.0.0"
+    chalk "5.0.1"
+    chalk-template "0.4.0"
+    clipboardy "3.0.0"
+    compression "1.7.4"
+    is-port-reachable "4.0.0"
+    serve-handler "6.1.5"
+    update-check "1.5.4"
 
-set-blocking@^2.0.0:
+shebang-command@^2.0.0:
   version "2.0.0"
-  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
-  integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
-
-shebang-command@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
-  integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+  integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
   dependencies:
-    shebang-regex "^1.0.0"
+    shebang-regex "^3.0.0"
 
-shebang-regex@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
-  integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+shebang-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+  integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
 
-signal-exit@^3.0.0, signal-exit@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
-  integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+signal-exit@^3.0.3:
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+  integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
 
-slice-ansi@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
-  integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
+string-width@^4.1.0, string-width@^4.2.0:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+  integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
   dependencies:
-    ansi-styles "^3.2.0"
-    astral-regex "^1.0.0"
-    is-fullwidth-code-point "^2.0.0"
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.1"
 
-sprintf-js@~1.0.2:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
-  integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
-
-string-width@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
-  integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+string-width@^5.0.1, string-width@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
+  integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
   dependencies:
-    code-point-at "^1.0.0"
-    is-fullwidth-code-point "^1.0.0"
-    strip-ansi "^3.0.0"
+    eastasianwidth "^0.2.0"
+    emoji-regex "^9.2.2"
+    strip-ansi "^7.0.1"
 
-"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
-  integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
   dependencies:
-    is-fullwidth-code-point "^2.0.0"
-    strip-ansi "^4.0.0"
+    ansi-regex "^5.0.1"
 
-string-width@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
-  integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
+strip-ansi@^7.0.1:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
+  integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
   dependencies:
-    emoji-regex "^7.0.1"
-    is-fullwidth-code-point "^2.0.0"
-    strip-ansi "^5.1.0"
+    ansi-regex "^6.0.1"
 
-string.prototype.trimleft@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634"
-  integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==
-  dependencies:
-    define-properties "^1.1.3"
-    function-bind "^1.1.1"
+strip-final-newline@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+  integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
 
-string.prototype.trimright@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58"
-  integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==
-  dependencies:
-    define-properties "^1.1.3"
-    function-bind "^1.1.1"
+strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+  integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
 
-strip-ansi@^3.0.0, strip-ansi@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
-  integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
-  dependencies:
-    ansi-regex "^2.0.0"
-
-strip-ansi@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
-  integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
-  dependencies:
-    ansi-regex "^3.0.0"
-
-strip-ansi@^5.1.0, strip-ansi@^5.2.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
-  integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
-  dependencies:
-    ansi-regex "^4.1.0"
-
-strip-eof@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
-  integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
-
-strip-json-comments@2.0.1, strip-json-comments@~2.0.1:
+strip-json-comments@~2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
-  integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+  integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
 
-strip-json-comments@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
-  integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==
-
-supports-color@6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a"
-  integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==
+supports-color@8.1.1:
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+  integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
   dependencies:
-    has-flag "^3.0.0"
+    has-flag "^4.0.0"
 
-supports-color@^5.3.0:
-  version "5.5.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
-  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+supports-color@^7.1.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
   dependencies:
-    has-flag "^3.0.0"
-
-table@^5.2.3:
-  version "5.4.6"
-  resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
-  integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==
-  dependencies:
-    ajv "^6.10.2"
-    lodash "^4.17.14"
-    slice-ansi "^2.1.0"
-    string-width "^3.0.0"
-
-term-size@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
-  integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
-  dependencies:
-    execa "^0.7.0"
+    has-flag "^4.0.0"
 
 text-table@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
-  integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+  integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
 
-through@^2.3.6:
-  version "2.3.8"
-  resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
-  integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
-
-tmp@^0.0.33:
-  version "0.0.33"
-  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
-  integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+to-regex-range@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
   dependencies:
-    os-tmpdir "~1.0.2"
+    is-number "^7.0.0"
 
-tslib@^1.9.0:
-  version "1.10.0"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
-  integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
-
-type-check@~0.3.2:
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
-  integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
+type-check@^0.4.0, type-check@~0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+  integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
   dependencies:
-    prelude-ls "~1.1.2"
+    prelude-ls "^1.2.1"
 
 type-detect@^4.0.0, type-detect@^4.0.5:
   version "4.0.8"
   resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
   integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
 
-update-check@1.5.2:
-  version "1.5.2"
-  resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.2.tgz#2fe09f725c543440b3d7dabe8971f2d5caaedc28"
-  integrity sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==
+type-fest@^0.20.2:
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+  integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type-fest@^2.13.0:
+  version "2.19.0"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b"
+  integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==
+
+update-check@1.5.4:
+  version "1.5.4"
+  resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.4.tgz#5b508e259558f1ad7dbc8b4b0457d4c9d28c8743"
+  integrity sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==
   dependencies:
     registry-auth-token "3.3.2"
     registry-url "3.1.0"
 
 uri-js@^4.2.2:
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
-  integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+  version "4.4.1"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+  integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
   dependencies:
     punycode "^2.1.0"
 
-v8-compile-cache@^2.0.3:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
-  integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
-
 vary@~1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
-  integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+  integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
 
-which-module@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
-  integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-
-which@1.3.1, which@^1.2.9:
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
-  integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+which@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
   dependencies:
     isexe "^2.0.0"
 
-wide-align@1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
-  integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+widest-line@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-4.0.1.tgz#a0fc673aaba1ea6f0a0d35b3c2795c9a9cc2ebf2"
+  integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==
   dependencies:
-    string-width "^1.0.2 || 2"
+    string-width "^5.0.1"
 
-widest-line@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
-  integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
+word-wrap@^1.2.3:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
+  integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
+
+workerpool@6.2.1:
+  version "6.2.1"
+  resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
+  integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==
+
+wrap-ansi@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
   dependencies:
-    string-width "^2.1.1"
+    ansi-styles "^4.0.0"
+    string-width "^4.1.0"
+    strip-ansi "^6.0.0"
 
-wordwrap@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
-  integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
-
-wrap-ansi@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
-  integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
+wrap-ansi@^8.0.1:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
+  integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
   dependencies:
-    string-width "^1.0.1"
-    strip-ansi "^3.0.1"
+    ansi-styles "^6.1.0"
+    string-width "^5.0.1"
+    strip-ansi "^7.0.1"
 
 wrappy@1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
-  integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+  integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
 
-write@1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
-  integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
+y18n@^5.0.5:
+  version "5.0.8"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+  integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yargs-parser@20.2.4:
+  version "20.2.4"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
+  integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
+
+yargs-parser@^20.2.2:
+  version "20.2.9"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
+  integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+
+yargs-unparser@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
+  integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
   dependencies:
-    mkdirp "^0.5.1"
+    camelcase "^6.0.0"
+    decamelize "^4.0.0"
+    flat "^5.0.2"
+    is-plain-obj "^2.1.0"
 
-"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
-  version "4.0.3"
-  resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
-  integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
-
-yallist@^2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
-  integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
-
-yargs-parser@13.0.0:
-  version "13.0.0"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b"
-  integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==
+yargs@16.2.0:
+  version "16.2.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+  integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
   dependencies:
-    camelcase "^5.0.0"
-    decamelize "^1.2.0"
-
-yargs-parser@^11.1.1:
-  version "11.1.1"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
-  integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==
-  dependencies:
-    camelcase "^5.0.0"
-    decamelize "^1.2.0"
-
-yargs-parser@^13.0.0:
-  version "13.1.1"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
-  integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
-  dependencies:
-    camelcase "^5.0.0"
-    decamelize "^1.2.0"
-
-yargs-unparser@1.5.0:
-  version "1.5.0"
-  resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d"
-  integrity sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==
-  dependencies:
-    flat "^4.1.0"
-    lodash "^4.17.11"
-    yargs "^12.0.5"
-
-yargs@13.2.2:
-  version "13.2.2"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993"
-  integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==
-  dependencies:
-    cliui "^4.0.0"
-    find-up "^3.0.0"
-    get-caller-file "^2.0.1"
-    os-locale "^3.1.0"
+    cliui "^7.0.2"
+    escalade "^3.1.1"
+    get-caller-file "^2.0.5"
     require-directory "^2.1.1"
-    require-main-filename "^2.0.0"
-    set-blocking "^2.0.0"
-    string-width "^3.0.0"
-    which-module "^2.0.0"
-    y18n "^4.0.0"
-    yargs-parser "^13.0.0"
+    string-width "^4.2.0"
+    y18n "^5.0.5"
+    yargs-parser "^20.2.2"
 
-yargs@^12.0.5:
-  version "12.0.5"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
-  integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
-  dependencies:
-    cliui "^4.0.0"
-    decamelize "^1.2.0"
-    find-up "^3.0.0"
-    get-caller-file "^1.0.1"
-    os-locale "^3.0.0"
-    require-directory "^2.1.1"
-    require-main-filename "^1.0.1"
-    set-blocking "^2.0.0"
-    string-width "^2.0.0"
-    which-module "^2.0.0"
-    y18n "^3.2.1 || ^4.0.0"
-    yargs-parser "^11.1.1"
+yocto-queue@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
diff --git a/third_party/SPIRV-Tools/utils/check_copyright.py b/third_party/SPIRV-Tools/utils/check_copyright.py
index e3e74bc..a849d04 100755
--- a/third_party/SPIRV-Tools/utils/check_copyright.py
+++ b/third_party/SPIRV-Tools/utils/check_copyright.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # coding=utf-8
 # Copyright (c) 2016 Google Inc.
 #
diff --git a/third_party/SPIRV-Tools/utils/check_symbol_exports.py b/third_party/SPIRV-Tools/utils/check_symbol_exports.py
index e1ca0b7..e44294f 100755
--- a/third_party/SPIRV-Tools/utils/check_symbol_exports.py
+++ b/third_party/SPIRV-Tools/utils/check_symbol_exports.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright (c) 2017 Google Inc.
 
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/third_party/SPIRV-Tools/utils/fixup_fuzz_result.py b/third_party/SPIRV-Tools/utils/fixup_fuzz_result.py
index 9fe54a3..5b14a7d 100755
--- a/third_party/SPIRV-Tools/utils/fixup_fuzz_result.py
+++ b/third_party/SPIRV-Tools/utils/fixup_fuzz_result.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright (c) 2018 Google Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/third_party/SPIRV-Tools/utils/generate_changelog.py b/third_party/SPIRV-Tools/utils/generate_changelog.py
index 54db728..348bc50 100644
--- a/third_party/SPIRV-Tools/utils/generate_changelog.py
+++ b/third_party/SPIRV-Tools/utils/generate_changelog.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 # Copyright (c) 2023 Google Inc.
 #
diff --git a/third_party/SPIRV-Tools/utils/generate_grammar_tables.py b/third_party/SPIRV-Tools/utils/generate_grammar_tables.py
index 6b7167b..88534ff 100755
--- a/third_party/SPIRV-Tools/utils/generate_grammar_tables.py
+++ b/third_party/SPIRV-Tools/utils/generate_grammar_tables.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright (c) 2016 Google Inc.
 
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -540,7 +540,7 @@
 
     # We have a few operand kinds that require their optional counterpart to
     # exist in the operand info table.
-    optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat']
+    optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat', 'CooperativeMatrixOperands', 'RawAccessChainOperands']
     optional_enums = [e for e in enums if e[0] in optional_enums]
     enums.extend(optional_enums)
 
diff --git a/third_party/SPIRV-Tools/utils/generate_language_headers.py b/third_party/SPIRV-Tools/utils/generate_language_headers.py
index 83fa99e..18a8d5e 100755
--- a/third_party/SPIRV-Tools/utils/generate_language_headers.py
+++ b/third_party/SPIRV-Tools/utils/generate_language_headers.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright (c) 2017 Google Inc.
 
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/third_party/SPIRV-Tools/utils/generate_registry_tables.py b/third_party/SPIRV-Tools/utils/generate_registry_tables.py
index 28152ef..69628fa 100755
--- a/third_party/SPIRV-Tools/utils/generate_registry_tables.py
+++ b/third_party/SPIRV-Tools/utils/generate_registry_tables.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright (c) 2016 Google Inc.
 
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,9 @@
 """Generates the vendor tool table from the SPIR-V XML registry."""
 
 import errno
+import io
 import os.path
-import xml.etree.ElementTree
+from xml.etree.ElementTree import XML, XMLParser, TreeBuilder
 
 
 def mkdir_p(directory):
@@ -78,8 +79,9 @@
                         help='output file for SPIR-V generators table')
     args = parser.parse_args()
 
-    with open(args.xml) as xml_in:
-       registry = xml.etree.ElementTree.fromstring(xml_in.read())
+    with io.open(args.xml, encoding='utf-8') as xml_in:
+      parser = XMLParser(target=TreeBuilder(), encoding='utf-8')
+      registry = XML(xml_in.read(), parser=parser)
 
     mkdir_p(os.path.dirname(args.generator_output))
     with open(args.generator_output, 'w') as f:
diff --git a/third_party/SPIRV-Tools/utils/generate_vim_syntax.py b/third_party/SPIRV-Tools/utils/generate_vim_syntax.py
index da7e99b..5c9c6b2 100755
--- a/third_party/SPIRV-Tools/utils/generate_vim_syntax.py
+++ b/third_party/SPIRV-Tools/utils/generate_vim_syntax.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright (c) 2016 Google Inc.
 
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/third_party/SPIRV-Tools/utils/roll_deps.sh b/third_party/SPIRV-Tools/utils/roll_deps.sh
index 6289c94..d19ee00 100755
--- a/third_party/SPIRV-Tools/utils/roll_deps.sh
+++ b/third_party/SPIRV-Tools/utils/roll_deps.sh
@@ -29,7 +29,6 @@
 }
 
 
-# We are not rolling google test for now. The latest version requires C++14.
 dependencies=("external/effcee/"
               "external/googletest/"
               "external/re2/"
diff --git a/third_party/SPIRV-Tools/utils/update_build_version.py b/third_party/SPIRV-Tools/utils/update_build_version.py
index 5a78ada..bb66e18 100755
--- a/third_party/SPIRV-Tools/utils/update_build_version.py
+++ b/third_party/SPIRV-Tools/utils/update_build_version.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 # Copyright (c) 2016 Google Inc.
 #
@@ -62,9 +62,7 @@
 def command_output(cmd, directory):
     """Runs a command in a directory and returns its standard output stream.
 
-    Captures the standard error stream.
-
-    Raises a RuntimeError if the command fails to launch or otherwise fails.
+    Returns (False, None) if the command fails to launch or otherwise fails.
     """
     try:
       # Set shell=True on Windows so that Chromium's git.bat can be found when
@@ -74,11 +72,10 @@
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE,
                            shell=os.name == 'nt')
-      (stdout, stderr) = p.communicate()
+      (stdout, _) = p.communicate()
       if p.returncode != 0:
-        logging.error('Failed to run "{}" in "{}": {}'.format(cmd, directory, stderr.decode()))
+        return False, None
     except Exception as e:
-        logging.error('Failed to run "{}" in "{}": {}'.format(cmd, directory, str(e)))
         return False, None
     return p.returncode == 0, stdout
 
@@ -111,26 +108,30 @@
     Runs 'git describe', or alternately 'git rev-parse HEAD', in directory.  If
     successful, returns the output; otherwise returns 'unknown hash, <date>'."""
 
-    success, output = command_output(['git', 'describe'], repo_path)
-    if not success:
-      output = command_output(['git', 'rev-parse', 'HEAD'], repo_path)
-
+    # if we're in a git repository, attempt to extract version info
+    success, output = command_output(["git", "rev-parse", "--show-toplevel"], repo_path)
     if success:
-      # decode() is needed here for Python3 compatibility. In Python2,
-      # str and bytes are the same type, but not in Python3.
-      # Popen.communicate() returns a bytes instance, which needs to be
-      # decoded into text data first in Python3. And this decode() won't
-      # hurt Python2.
-      return output.rstrip().decode()
+        success, output = command_output(["git", "describe", "--tags", "--match=v*", "--long"], repo_path)
+        if not success:
+            success, output = command_output(["git", "rev-parse", "HEAD"], repo_path)
+
+        if success:
+            # decode() is needed here for Python3 compatibility. In Python2,
+            # str and bytes are the same type, but not in Python3.
+            # Popen.communicate() returns a bytes instance, which needs to be
+            # decoded into text data first in Python3. And this decode() won't
+            # hurt Python2.
+            return output.rstrip().decode()
 
     # This is the fallback case where git gives us no information,
-    # e.g. because the source tree might not be in a git tree.
+    # e.g. because the source tree might not be in a git tree or
+    # git is not available on the system.
     # In this case, usually use a timestamp.  However, to ensure
     # reproducible builds, allow the builder to override the wall
     # clock time with environment variable SOURCE_DATE_EPOCH
     # containing a (presumably) fixed timestamp.
     timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))
-    iso_date = datetime.datetime.utcfromtimestamp(timestamp).isoformat()
+    iso_date = datetime.datetime.fromtimestamp(timestamp, datetime.timezone.utc).isoformat()
     return "unknown hash, {}".format(iso_date)
 
 def main():