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(), ¶m_vec, &input_func);
- AddParam(GetUintId(), ¶m_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():