Squashed 'third_party/SPIRV-Tools/' changes from b0e22d28f5e..f37547c73a9
f37547c73a9 spirv-val: Add Vulkan EXT builtins (#4115)
1bd539b9bfc Support pending Intel extensions (#4116)
56f8ed48efd Validate Sampled=1 for Vulkan ImageQuerySizeLod, ImageQueryLevels, ImageQueryLod (#4103)
e25db023c47 spirv-val: Add Vulkan Memory Scope VUs (#4106)
8383bd5d6f2 Migrate all Kokoro build scripts over to use the docker VM image (#4114)
ee39b5db5f1 spirv-val: Add Vulkan Addressing Model check (#4107)
9150cd441f4 Remove WebGPU support (#4108)
b2cfc5d1cec spirv-val: Vulkan atomic storage class (#4079)
cec658c1160 Avoid integrity check failures caused by propagating line instructions (#4096)
b1507d0d2ba Linker usability improvements (#4084)
7bbe1a31641 Revert "Generate differentiated error codes for buffer oob checking (#4097)" (#4100)
c32277c0ba0 Generate differentiated error codes for buffer oob checking (#4097)
f3ccb633dfd use std::string::empty() to test for emptiness (#4098)
ad77ed7a8d5 spirv-val: Label standalone Vulkan VUID (#4091)
aa005e8bd43 spirv-val: Add Vulkan decroation VUID (#4090)
4ed1f4fce9e Fix binding number calculation in desc sroa (#4095)
af3a3d481f6 Build deps: dump ini from 1.3.5 to 1.3.7 in tools/sva (#4092)
94d1a80159e spirv-val: Add Vulkan FP Mode VUID (#4088)
6d05ed8410b spirv-val: Fix Vulkan image sampled check (#4085)
37c03859de9 spirv-val: Add Vulkan ForwardPointer VUID (#4089)
d630e5f8c10 spirv-val: Add Vulkan ImageTexelPointer format check (#4087)
1bb80d2778a spirv-val: Add Vulkan Group Operation VUID (#4086)
17ffa89097b spirv-val: Add first StandAlone VUID 04633 (#4077)
8f4b35c332e spirv-val: Add Subgroup VUIDs (#4074)
4e31fdd4aa1 spirv-fuzz: Fix OpPhi handling in DuplicateRegionWithSelection (#4065)
ad898cb9498 validation: validate return type of OpImageRead (#4072)
305caff2ebb validation: tighter validation of multisampled images (#4059)
a0370efd589 validate OpTypeImage Sampled values for environemnts (#4064)
09d1fea5890 Force using Python 3 git-sync-deps (#4067)
7170218b8de validate StorageImageMultisampled capability (#4062)
3b85234542c spirv-val: Add last TessLevelOuter and TessLevelInner VUID (#4055)
171290703a6 spirv-val: Add last ClipDistance and CullDistance VUID (#4054)
1a6b4053fa0 spirv-val: Add last ViewportIndex and Layer VUID (#4053)
9df5225e672 spirv-val: Add last Position VUID (#4052)
862d44a86ed Allow forward pointer to be used in types generally (#4044)
bda102d7a76 opt: Run DCE when SPV_KHR_shader_clock is used (#4049)
b27b1afd12d Update CHANGES to include latest ray tacing fixes.
cd050786621 Take new (raytracing) termination instructions into account. (#4050)
21f7c5675da Start SPIRV-Tools v2020.7
4c2f34a5048 Finalize SPIRV-Tools v2020.6
c9c1f54330d Update CHANGES
10e0ae7946c Do run DCE if SPV_KHR_ray_query is used. (#4047)
84546647a0d Update CHANGES
c1d5a045f6f Change ref_analysis to RefAnalysis to follow coding standards. (#4045)
c502a15f25c Handle 8-bit index in elim dead member (#4043)
32573bb2168 Add validation support for the ray tracing built-in variables (#4041)
7046c05d2fb Add texel buffer out-of-bounds checking instrumentation (#4038)
cf2d1e7afcd Update spirv-header deps (#4040)
1299436c8f1 Reject SPIR-V that applies void to OpUndef, OpCopyObject, OpPhi (#4036)
2c458414c08 BuildModule: optionally avoid adding new OpLine instructions (#4033)
a79aa038ec1 Remove prototype for unimplemented method (#4031)
git-subtree-dir: third_party/SPIRV-Tools
git-subtree-split: f37547c73a981bcf3f8b1a471e3000e606dd41a8
diff --git a/Android.mk b/Android.mk
index 0b64ea6..1000f42 100644
--- a/Android.mk
+++ b/Android.mk
@@ -93,7 +93,6 @@
source/opt/dead_branch_elim_pass.cpp \
source/opt/dead_insert_elim_pass.cpp \
source/opt/dead_variable_elimination.cpp \
- source/opt/decompose_initialized_variables_pass.cpp \
source/opt/decoration_manager.cpp \
source/opt/debug_info_manager.cpp \
source/opt/def_use_manager.cpp \
@@ -112,7 +111,6 @@
source/opt/fold_spec_constant_op_and_composite_pass.cpp \
source/opt/freeze_spec_constant_value_pass.cpp \
source/opt/function.cpp \
- source/opt/generate_webgpu_initializers_pass.cpp \
source/opt/graphics_robust_access_pass.cpp \
source/opt/if_conversion.cpp \
source/opt/inline_pass.cpp \
@@ -126,7 +124,6 @@
source/opt/instrument_pass.cpp \
source/opt/ir_context.cpp \
source/opt/ir_loader.cpp \
- source/opt/legalize_vector_shuffle_pass.cpp \
source/opt/licm_pass.cpp \
source/opt/local_access_chain_convert_pass.cpp \
source/opt/local_redundancy_elimination.cpp \
@@ -161,10 +158,8 @@
source/opt/scalar_replacement_pass.cpp \
source/opt/set_spec_constant_default_value_pass.cpp \
source/opt/simplification_pass.cpp \
- source/opt/split_invalid_unreachable_pass.cpp \
source/opt/ssa_rewrite_pass.cpp \
source/opt/strength_reduction_pass.cpp \
- source/opt/strip_atomic_counter_memory_pass.cpp \
source/opt/strip_debug_info_pass.cpp \
source/opt/strip_reflect_info_pass.cpp \
source/opt/struct_cfg_analysis.cpp \
diff --git a/BUILD.gn b/BUILD.gn
index 2387fc6..845eb29 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -539,8 +539,6 @@
"source/opt/dead_insert_elim_pass.h",
"source/opt/dead_variable_elimination.cpp",
"source/opt/dead_variable_elimination.h",
- "source/opt/decompose_initialized_variables_pass.cpp",
- "source/opt/decompose_initialized_variables_pass.h",
"source/opt/decoration_manager.cpp",
"source/opt/decoration_manager.h",
"source/opt/debug_info_manager.cpp",
@@ -578,8 +576,6 @@
"source/opt/freeze_spec_constant_value_pass.h",
"source/opt/function.cpp",
"source/opt/function.h",
- "source/opt/generate_webgpu_initializers_pass.cpp",
- "source/opt/generate_webgpu_initializers_pass.h",
"source/opt/graphics_robust_access_pass.cpp",
"source/opt/graphics_robust_access_pass.h",
"source/opt/if_conversion.cpp",
@@ -608,8 +604,6 @@
"source/opt/ir_loader.cpp",
"source/opt/ir_loader.h",
"source/opt/iterator.h",
- "source/opt/legalize_vector_shuffle_pass.cpp",
- "source/opt/legalize_vector_shuffle_pass.h",
"source/opt/licm_pass.cpp",
"source/opt/licm_pass.h",
"source/opt/local_access_chain_convert_pass.cpp",
@@ -680,14 +674,10 @@
"source/opt/set_spec_constant_default_value_pass.h",
"source/opt/simplification_pass.cpp",
"source/opt/simplification_pass.h",
- "source/opt/split_invalid_unreachable_pass.cpp",
- "source/opt/split_invalid_unreachable_pass.h",
"source/opt/ssa_rewrite_pass.cpp",
"source/opt/ssa_rewrite_pass.h",
"source/opt/strength_reduction_pass.cpp",
"source/opt/strength_reduction_pass.h",
- "source/opt/strip_atomic_counter_memory_pass.cpp",
- "source/opt/strip_atomic_counter_memory_pass.h",
"source/opt/strip_debug_info_pass.cpp",
"source/opt/strip_debug_info_pass.h",
"source/opt/strip_reflect_info_pass.cpp",
diff --git a/CHANGES b/CHANGES
index 3c81249..d7a49f7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,7 +1,96 @@
Revision history for SPIRV-Tools
-v2020.6 2020-09-24
- - Start SPIRV-Tools v2020.6
+v2020.7-dev 2020-12-07
+ - Start v2020.7-dev
+
+v2020.6 2020-12-07
+ - General
+ CMake: Add SPIRV_TOOLS_BUILD_STATIC flag (#3910)
+ - Disassembler
+ Add some context comments to disassembly. (#3847)
+ - Optimizer
+ - Take new (raytracing) termination instructions into account. (#4050)
+ - Do run DCE if SPV_KHR_ray_query is used. (#4047)
+ - Handle 8-bit index in elim dead member (#4043)
+ - Add texel buffer out-of-bounds checking instrumentation (#4038)
+ - Update MeshShadingNV dependencies (and land Ray tracing updates) (#4028)
+ - Fix buffer oob instrumentation for matrix refs (#4025)
+ - Fix SSA re-writing in the presence of variable pointers. (#4010)
+ - Add support to prevent functions from being inlined if they have
+ DontInline flag (#3858)
+ - Add SPV_EXT_shader_image_int64 (#3852)
+ - Support SPV_KHR_fragment_shading_rate (#3943)
+ - Fix use-after-move in val/validate.cpp (#3848)
+ - Debug Info
+ - properly preserve DebugValue indexes operand (#4022)
+ - Add DebugValue for invisible store in single_store_elim (#4002)
+ - Propagate OpLine to all applied instructions in spirv-opt (#3951)
+ - Add DebugValue for DebugDecl invisible to value assignment (#3973)
+ - Add DebugValue for function param regardless of scope (#3923)
+ - Debug info preservation in convert-local-access-chains pass (#3835)
+ - Debug info preservation in redundancy-elimination pass (#3839)
+ - Debug info preservation in if-conversion pass (#3861)
+ - Validator
+ - Add validation support for the ray tracing built-in variables (#4041)
+ - Use less stack space when validating Vulkan builtins (#4019)
+ - Fix SPV_KHR_fragment_shading_rate VUID label (#4014)
+ - Label Layer and ViewportIndex VUIDs (#4013)
+ - Allow the ViewportIndex and Layer built-ins on SPIR-V 1.5 (#3986)
+ - Fix validation of OpPhi instructions (#3919)
+ - Fuzz
+ - Fix facts arising from CompositeConstruct (#4034)
+ - Do not flatten conditionals that create synonyms (#4030)
+ - Add support for reining in rogue fuzzer passes (#3987)
+ - Fix assertion failure in FuzzerPassAddCompositeExtract (#3995)
+ - Fix invalid equation facts (#4009)
+ - Fix bugs in TransformationFlattenConditionalBranch (#4006)
+ - Fix bug related to transformation applicability (#3990)
+ - Add expand vector reduction transformation (#3869)
+ - Add FuzzerPassAddCompositeExtract (#3904)
+ - Fix mismatch with shrinker step limit (#3985)
+ - Fix off-by-one error in replayer (#3982)
+ - Get order right for OpSelect arguments (#3974)
+ - Do not add synonym-creating loops in dead blocks (#3975)
+ - Skip OpTypeSampledImage when propagating up (#3976)
+ - Pass OpUndef in function call if needed (#3978)
+ - Fix off-by-one in TransformationCompositeConstruct (#3979)
+ - Tolerate absent ids in data synonym fact management (#3966)
+ - Fix to id availability (#3971)
+ - Fix operand types (#3962)
+ - Don't flatten conditional if condition is irrelevant (#3944)
+ - Do not produce OpPhis of type OpTypeSampledImage (#3964)
+ - Restrict fuzzer pass to reachable blocks (#3970)
+ - Handle more types when extending OpPhi instructions (#3969)
+ - Skip early terminator wrappers when merging returns (#3968)
+ - Avoid irrelevant constants in synonym-creating loops (#3967)
+ - Skip dead blocks in FuzzerPassAddOpPhiSynonyms (#3965)
+ - Avoid the type manager when looking for struct types (#3963)
+ - Fix to TransformationDuplicateRegionWithSelection (#3941)
+ - Skip OpFunction when replacing irrelevant ids (#3932)
+ - Use component-wise selectors when flattening conditional branches (#3921)
+ - Avoid void struct member when outlining functions (#3936)
+ - Do not allow Block-decorated structs when adding parameters (#3931)
+ - Fix to operand id type (#3937)
+ - Handle dead blocks in TransformationEquationInstruction (#3933)
+ - Do not allow sampled image load when flattening conditionals (#3930)
+ - Take care of OpPhi instructions when inlining (#3939)
+ - Fix to TransformationInlineFunction (#3913)
+ - Wrap early terminators before merging returns (#3925)
+ - Lower probability of adding bit instruction synonyms (#3917)
+ - Fix handling of OpPhi in FlattenConditionalBranch (#3916)
+ - Avoid creating blocks without parents (#3908)
+ - Do not allow creation of constants of block-decorated structs (#3903)
+ - Fixes related to irrelevant ids (#3901)
+ - Fix to transformation that adds a synonym via a loop (#3898)
+ - Fix to duplicate region with selection (#3896)
+ - Do not expose synonym facts for non-existent ids (#3891)
+ - Do not add synonyms involving irrelevant ids (#3890)
+ - Do not replace irrelevant ids that are not in blocks (#3892)
+ - Wrap OpKill and similar in function calls (#3884)
+ - Integrate spirv-reduce with shrinker (#3849)
+ - Report fresh ids in transformations (#3856)
+ - Support OpNot bit instruction case (#3841)
+ - Return IR and transformation context after replay (#3846)
v2020.5 2020-09-22
- General
diff --git a/DEPS b/DEPS
index 350cfb4..3762681 100644
--- a/DEPS
+++ b/DEPS
@@ -6,7 +6,7 @@
'effcee_revision': '2ec8f8738118cc483b67c04a759fee53496c5659',
'googletest_revision': '3af06fe1664d30f98de1e78c53a7087e842a2547',
're2_revision': 'ca11026a032ce2a3de4b3c389ee53d2bdc8794d6',
- 'spirv_headers_revision': '4de110ce1c78fda37932c735ef7f747e6f6cbee8',
+ 'spirv_headers_revision': 'f027d53ded7e230e008d37c8b47ede7cd308e19d',
}
deps = {
diff --git a/README.md b/README.md
index 44f582f..3637305 100644
--- a/README.md
+++ b/README.md
@@ -136,7 +136,6 @@
* Loop-invariant code motion
* Loop unroll
* Other
- * Generate WebGPU initializers
* Graphics robust access
* Upgrade memory model to VulkanKHR
diff --git a/android_test/jni/Application.mk b/android_test/jni/Application.mk
index d7ccd34..4e66465 100644
--- a/android_test/jni/Application.mk
+++ b/android_test/jni/Application.mk
@@ -1,5 +1,5 @@
APP_ABI := all
APP_BUILD_SCRIPT := Android.mk
-APP_STL := gnustl_static
+APP_STL := c++_static
APP_PLATFORM := android-9
NDK_TOOLCHAIN_VERSION := 4.9
diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp
index 9c01cb6..2b47a56 100644
--- a/include/spirv-tools/instrument.hpp
+++ b/include/spirv-tools/instrument.hpp
@@ -171,6 +171,10 @@
static const int kInstErrorBindlessUninit = 1;
static const int kInstErrorBuffAddrUnallocRef = 2;
static const int kInstErrorBindlessBuffOOB = 3;
+static const int kInstErrorBuffOOBUniform = 4;
+static const int kInstErrorBuffOOBStorage = 5;
+static const int kInstErrorBuffOOBUniformTexel = 6;
+static const int kInstErrorBuffOOBStorageTexel = 7;
// Direct Input Buffer Offsets
//
diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h
index a0114c3..201ee58 100644
--- a/include/spirv-tools/libspirv.h
+++ b/include/spirv-tools/libspirv.h
@@ -260,6 +260,11 @@
SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION, // Sec 3.6
SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY, // Sec 3.7
+ // The following are concrete enum types from SPV_INTEL_float_controls2
+ // https://github.com/intel/llvm/blob/39fa9b0cbfbae88327118990a05c5b387b56d2ef/sycl/doc/extensions/SPIRV/SPV_INTEL_float_controls2.asciidoc
+ SPV_OPERAND_TYPE_FPDENORM_MODE, // Sec 3.17 FP Denorm Mode
+ SPV_OPERAND_TYPE_FPOPERATION_MODE, // Sec 3.18 FP Operation Mode
+
// This is a sentinel value, and does not represent an operand type.
// It should come last.
SPV_OPERAND_TYPE_NUM_OPERAND_TYPES,
@@ -482,7 +487,7 @@
SPV_ENV_OPENCL_EMBEDDED_2_2, // OpenCL Embedded Profile 2.2 latest revision.
SPV_ENV_UNIVERSAL_1_3, // SPIR-V 1.3 latest revision, no other restrictions.
SPV_ENV_VULKAN_1_1, // Vulkan 1.1 latest revision.
- SPV_ENV_WEBGPU_0, // Work in progress WebGPU 1.0.
+ SPV_ENV_WEBGPU_0, // DEPRECATED, may be removed in the future.
SPV_ENV_UNIVERSAL_1_4, // SPIR-V 1.4 latest revision, no other restrictions.
// Vulkan 1.1 with VK_KHR_spirv_1_4, i.e. SPIR-V 1.4 binary.
diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
index f12774d..1683d07 100644
--- a/include/spirv-tools/optimizer.hpp
+++ b/include/spirv-tools/optimizer.hpp
@@ -68,11 +68,6 @@
// The instance will have an empty message consumer, which ignores all
// messages from the library. Use SetMessageConsumer() to supply a consumer
// if messages are of concern.
- //
- // For collections of passes that are meant to transform the input into
- // another execution environment, then the source environment should be
- // supplied. e.g. for VulkanToWebGPUPasses the environment should be
- // SPV_ENV_VULKAN_1_1 not SPV_ENV_WEBGPU_0.
explicit Optimizer(spv_target_env env);
// Disables copy/move constructor/assignment operations.
@@ -106,16 +101,6 @@
// from time to time.
Optimizer& RegisterSizePasses();
- // Registers passes that have been prescribed for converting from Vulkan to
- // WebGPU. This sequence of passes is subject to constant review and will
- // change from time to time.
- Optimizer& RegisterVulkanToWebGPUPasses();
-
- // Registers passes that have been prescribed for converting from WebGPU to
- // Vulkan. This sequence of passes is subject to constant review and will
- // change from time to time.
- Optimizer& RegisterWebGPUToVulkanPasses();
-
// Registers passes that attempt to legalize the generated code.
//
// Note: this recipe is specially designed for legalizing SPIR-V. It should be
@@ -238,13 +223,6 @@
// A null pass does nothing to the SPIR-V module to be optimized.
Optimizer::PassToken CreateNullPass();
-// Creates a strip-atomic-counter-memory pass.
-// A strip-atomic-counter-memory pass removes all usages of the
-// AtomicCounterMemory bit in Memory Semantics bitmasks. This bit is a no-op in
-// Vulkan, so isn't needed in that env. And the related capability is not
-// allowed in WebGPU, so it is not allowed in that env.
-Optimizer::PassToken CreateStripAtomicCounterMemoryPass();
-
// Creates a strip-debug-info pass.
// A strip-debug-info pass removes all debug instructions (as documented in
// Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized.
@@ -747,12 +725,16 @@
// 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.
-// |input_length_enable| controls instrumentation of runtime descriptor array
-// references, and |input_init_enable| controls instrumentation of descriptor
-// initialization checking, both of which require input buffer support.
+// |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 input_length_enable = false,
- bool input_init_enable = false, bool input_buff_oob_enable = false);
+ 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);
// Create a pass to instrument physical buffer address checking
// This pass instruments all physical buffer address references to check that
@@ -798,30 +780,11 @@
// where an instruction is moved into a more deeply nested construct.
Optimizer::PassToken CreateCodeSinkingPass();
-// Create a pass to adds initializers for OpVariable calls that require them
-// in WebGPU. Currently this pass naively initializes variables that are
-// missing an initializer with a null value. In the future it may initialize
-// variables to the first value stored in them, if that is a constant.
-Optimizer::PassToken CreateGenerateWebGPUInitializersPass();
-
// Create a pass to fix incorrect storage classes. In order to make code
// generation simpler, DXC may generate code where the storage classes do not
// match up correctly. This pass will fix the errors that it can.
Optimizer::PassToken CreateFixStorageClassPass();
-// Create a pass to legalize OpVectorShuffle operands going into WebGPU. WebGPU
-// forbids using 0xFFFFFFFF, which indicates an undefined result, so this pass
-// converts those literals to 0.
-Optimizer::PassToken CreateLegalizeVectorShufflePass();
-
-// Create a pass to decompose initialized variables into a seperate variable
-// declaration and an initial store.
-Optimizer::PassToken CreateDecomposeInitializedVariablesPass();
-
-// Create a pass to attempt to split up invalid unreachable merge-blocks and
-// continue-targets to legalize for WebGPU.
-Optimizer::PassToken CreateSplitInvalidUnreachablePass();
-
// Creates a graphics robust access pass.
//
// This pass injects code to clamp indexed accesses to buffers and internal
diff --git a/kokoro/android/build.sh b/kokoro/android/build.sh
old mode 100644
new mode 100755
index c05c139..22c9117
--- a/kokoro/android/build.sh
+++ b/kokoro/android/build.sh
@@ -20,33 +20,5 @@
# Display commands being run.
set -x
-BUILD_ROOT=$PWD
-SRC=$PWD/github/SPIRV-Tools
-TARGET_ARCH="armeabi-v7a with NEON"
-export ANDROID_NDK=/opt/android-ndk-r15c
-
-# Get NINJA.
-wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip
-unzip -q ninja-linux.zip
-export PATH="$PWD:$PATH"
-git clone --depth=1 https://github.com/taka-no-me/android-cmake.git android-cmake
-export TOOLCHAIN_PATH=$PWD/android-cmake/android.toolchain.cmake
-
-
-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
-
-mkdir build && cd $SRC/build
-
-# Invoke the build.
-BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT}
-echo $(date): Starting build...
-cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 -DCMAKE_BUILD_TYPE=Release -DANDROID_NATIVE_API_LEVEL=android-14 -DANDROID_ABI="armeabi-v7a with NEON" -DSPIRV_SKIP_TESTS=ON -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_PATH -GNinja -DANDROID_NDK=$ANDROID_NDK ..
-
-echo $(date): Build everything...
-ninja
-echo $(date): Build completed.
+SCRIPT_DIR=`dirname "$BASH_SOURCE"`
+source $SCRIPT_DIR/../scripts/linux/build.sh ASAN clang cmake-android-ndk
diff --git a/kokoro/linux-clang-asan/build.sh b/kokoro/linux-clang-asan/build.sh
old mode 100644
new mode 100755
index 8f86e6e..5cca362
--- a/kokoro/linux-clang-asan/build.sh
+++ b/kokoro/linux-clang-asan/build.sh
@@ -21,4 +21,4 @@
set -x
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
-source $SCRIPT_DIR/../scripts/linux/build.sh ASAN clang
+source $SCRIPT_DIR/../scripts/linux/build.sh ASAN clang cmake
diff --git a/kokoro/linux-clang-debug/build.sh b/kokoro/linux-clang-debug/build.sh
old mode 100644
new mode 100755
index 11b2968..785a6e3
--- a/kokoro/linux-clang-debug/build.sh
+++ b/kokoro/linux-clang-debug/build.sh
@@ -21,4 +21,4 @@
set -x
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
-source $SCRIPT_DIR/../scripts/linux/build.sh DEBUG clang
+source $SCRIPT_DIR/../scripts/linux/build.sh DEBUG clang cmake
diff --git a/kokoro/linux-clang-release-bazel/build.sh b/kokoro/linux-clang-release-bazel/build.sh
old mode 100644
new mode 100755
index 05a9bbb..238ef52
--- a/kokoro/linux-clang-release-bazel/build.sh
+++ b/kokoro/linux-clang-release-bazel/build.sh
@@ -20,24 +20,5 @@
# Display commands being run.
set -x
-CC=clang
-CXX=clang++
-SRC=$PWD/github/SPIRV-Tools
-
-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
-
-gsutil cp gs://bazel/0.29.1/release/bazel-0.29.1-linux-x86_64 .
-chmod +x bazel-0.29.1-linux-x86_64
-
-echo $(date): Build everything...
-./bazel-0.29.1-linux-x86_64 build :all
-echo $(date): Build completed.
-
-echo $(date): Starting bazel test...
-./bazel-0.29.1-linux-x86_64 test :all
-echo $(date): Bazel test completed.
+SCRIPT_DIR=`dirname "$BASH_SOURCE"`
+source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE clang bazel
diff --git a/kokoro/linux-clang-release/build.sh b/kokoro/linux-clang-release/build.sh
old mode 100644
new mode 100755
index 4764331..6a9e013
--- a/kokoro/linux-clang-release/build.sh
+++ b/kokoro/linux-clang-release/build.sh
@@ -21,4 +21,4 @@
set -x
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
-source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE clang
+source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE clang cmake
diff --git a/kokoro/linux-gcc-debug/build.sh b/kokoro/linux-gcc-debug/build.sh
old mode 100644
new mode 100755
index 3ef1e25..c60447e
--- a/kokoro/linux-gcc-debug/build.sh
+++ b/kokoro/linux-gcc-debug/build.sh
@@ -21,4 +21,4 @@
set -x
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
-source $SCRIPT_DIR/../scripts/linux/build.sh DEBUG gcc
+source $SCRIPT_DIR/../scripts/linux/build.sh DEBUG gcc cmake
diff --git a/kokoro/linux-gcc-release/build.sh b/kokoro/linux-gcc-release/build.sh
old mode 100644
new mode 100755
index 3e97d8d..441ab72
--- a/kokoro/linux-gcc-release/build.sh
+++ b/kokoro/linux-gcc-release/build.sh
@@ -21,4 +21,4 @@
set -x
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
-source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE gcc
+source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE gcc cmake
diff --git a/kokoro/ndk-build/build.sh b/kokoro/ndk-build/build.sh
old mode 100644
new mode 100755
index f1f167d..89c5565
--- a/kokoro/ndk-build/build.sh
+++ b/kokoro/ndk-build/build.sh
@@ -20,38 +20,5 @@
# Display commands being run.
set -x
-BUILD_ROOT=$PWD
-SRC=$PWD/github/SPIRV-Tools
-
-# Get NINJA.
-wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip
-unzip -q ninja-linux.zip
-export PATH="$PWD:$PATH"
-
-# NDK Path
-export ANDROID_NDK=/opt/android-ndk-r15c
-
-# Get the dependencies.
-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
-
-mkdir build && cd $SRC/build
-mkdir libs
-mkdir app
-
-# Invoke the build.
-BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT}
-echo $(date): Starting ndk-build ...
-$ANDROID_NDK/ndk-build \
- -C $SRC/android_test \
- NDK_PROJECT_PATH=. \
- NDK_LIBS_OUT=./libs \
- NDK_APP_OUT=./app \
- -j8
-
-echo $(date): ndk-build completed.
-
+SCRIPT_DIR=`dirname "$BASH_SOURCE"`
+source $SCRIPT_DIR/../scripts/linux/build.sh ASAN clang android-ndk-build
diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh
new file mode 100755
index 0000000..ba21698
--- /dev/null
+++ b/kokoro/scripts/linux/build-docker.sh
@@ -0,0 +1,196 @@
+#!/bin/bash
+# Copyright (c) 2018 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.
+#
+# Linux Build Script.
+
+# Fail on any error.
+set -e
+# Display commands being run.
+set -x
+
+. /bin/using.sh # Declare the bash `using` function for configuring toolchains.
+
+if [ $COMPILER = "clang" ]; then
+ using clang-10.0.0
+elif [ $COMPILER = "gcc" ]; then
+ using gcc-9
+fi
+
+cd $ROOT_DIR
+
+function clone_if_missing() {
+ url=$1
+ dir=$2
+ if [[ ! -d "$dir" ]]; then
+ git clone ${@:3} "$url" "$dir"
+ fi
+}
+
+function clean_dir() {
+ dir=$1
+ if [[ -d "$dir" ]]; then
+ rm -fr "$dir"
+ fi
+ mkdir "$dir"
+}
+
+clone_if_missing https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers --depth=1
+clone_if_missing https://github.com/google/googletest external/googletest
+pushd external/googletest; git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7; popd
+clone_if_missing https://github.com/google/effcee external/effcee --depth=1
+clone_if_missing https://github.com/google/re2 external/re2 --depth=1
+clone_if_missing https://github.com/protocolbuffers/protobuf external/protobuf --branch v3.13.0
+
+if [ $TOOL = "cmake" ]; then
+ using cmake-3.17.2
+ using ninja-1.10.0
+
+ # Possible configurations are:
+ # ASAN, COVERAGE, RELEASE, DEBUG, DEBUG_EXCEPTION, RELEASE_MINGW
+ BUILD_TYPE="Debug"
+ if [ $CONFIG = "RELEASE" ] || [ $CONFIG = "RELEASE_MINGW" ]; then
+ BUILD_TYPE="RelWithDebInfo"
+ fi
+
+ SKIP_TESTS="False"
+ ADDITIONAL_CMAKE_FLAGS=""
+ if [ $CONFIG = "ASAN" ]; then
+ ADDITIONAL_CMAKE_FLAGS="-DSPIRV_USE_SANITIZER=address,bounds,null"
+ [ $COMPILER = "clang" ] || { echo "$CONFIG requires clang"; exit 1; }
+ elif [ $CONFIG = "COVERAGE" ]; then
+ ADDITIONAL_CMAKE_FLAGS="-DENABLE_CODE_COVERAGE=ON"
+ SKIP_TESTS="True"
+ elif [ $CONFIG = "DEBUG_EXCEPTION" ]; then
+ ADDITIONAL_CMAKE_FLAGS="-DDISABLE_EXCEPTIONS=ON -DDISABLE_RTTI=ON"
+ elif [ $CONFIG = "RELEASE_MINGW" ]; then
+ ADDITIONAL_CMAKE_FLAGS="-Dgtest_disable_pthreads=ON -DCMAKE_TOOLCHAIN_FILE=$SRC/cmake/linux-mingw-toolchain.cmake"
+ SKIP_TESTS="True"
+ fi
+
+ clean_dir "$ROOT_DIR/build"
+ cd "$ROOT_DIR/build"
+
+ # Invoke the build.
+ BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT}
+ echo $(date): Starting build...
+ cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 -GNinja -DCMAKE_INSTALL_PREFIX=$KOKORO_ARTIFACTS_DIR/install -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DRE2_BUILD_TESTING=OFF -DSPIRV_BUILD_FUZZER=ON $ADDITIONAL_CMAKE_FLAGS ..
+
+ echo $(date): Build everything...
+ ninja
+ echo $(date): Build completed.
+
+ if [ $CONFIG = "COVERAGE" ]; then
+ echo $(date): Check coverage...
+ ninja report-coverage
+ echo $(date): Check coverage completed.
+ fi
+
+ echo $(date): Starting ctest...
+ if [ $SKIP_TESTS = "False" ]; then
+ ctest -j4 --output-on-failure --timeout 300
+ fi
+ echo $(date): ctest completed.
+
+ # Package the build.
+ ninja install
+ cd $KOKORO_ARTIFACTS_DIR
+ tar czf install.tgz install
+elif [ $TOOL = "cmake-smoketest" ]; then
+ using cmake-3.17.2
+ using ninja-1.10.0
+
+ # Get shaderc.
+ SHADERC_DIR=/tmp/shaderc
+ clean_dir "$SHADERC_DIR"
+ cd $SHADERC_DIR
+ git clone https://github.com/google/shaderc.git .
+ cd $SHADERC_DIR/third_party
+
+ # Get shaderc dependencies. Link the appropriate SPIRV-Tools.
+ git clone https://github.com/google/googletest.git
+ git clone https://github.com/KhronosGroup/glslang.git
+ ln -s $ROOT_DIR spirv-tools
+ 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
+
+ cd $SHADERC_DIR
+ mkdir build
+ cd $SHADERC_DIR/build
+
+ # Invoke the build.
+ echo $(date): Starting build...
+ cmake -GNinja -DRE2_BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE="Release" ..
+
+ echo $(date): Build glslang...
+ ninja glslangValidator
+
+ echo $(date): Build everything...
+ ninja
+ echo $(date): Build completed.
+
+ echo $(date): Check Shaderc for copyright notices...
+ ninja check-copyright
+
+ echo $(date): Starting ctest...
+ ctest --output-on-failure -j4
+ echo $(date): ctest completed.
+elif [ $TOOL = "cmake-android-ndk" ]; then
+ using cmake-3.17.2
+ using ndk-r21d
+ using ninja-1.10.0
+
+ clean_dir "$ROOT_DIR/build"
+ cd "$ROOT_DIR/build"
+
+ echo $(date): Starting build...
+ cmake -DCMAKE_BUILD_TYPE=Release \
+ -DANDROID_NATIVE_API_LEVEL=android-16 \
+ -DANDROID_ABI="armeabi-v7a with NEON" \
+ -DSPIRV_SKIP_TESTS=ON \
+ -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \
+ -GNinja \
+ -DANDROID_NDK=$ANDROID_NDK \
+ ..
+
+ echo $(date): Build everything...
+ ninja
+ echo $(date): Build completed.
+elif [ $TOOL = "android-ndk-build" ]; then
+ using ndk-r21d
+
+ clean_dir "$ROOT_DIR/build"
+ cd "$ROOT_DIR/build"
+
+ echo $(date): Starting ndk-build ...
+ $ANDROID_NDK_HOME/ndk-build \
+ -C $ROOT_DIR/android_test \
+ NDK_PROJECT_PATH=. \
+ NDK_LIBS_OUT=./libs \
+ NDK_APP_OUT=./app \
+ -j4
+
+ echo $(date): ndk-build completed.
+elif [ $TOOL = "bazel" ]; then
+ using bazel-3.1.0
+
+ echo $(date): Build everything...
+ bazel build :all
+ echo $(date): Build completed.
+
+ echo $(date): Starting bazel test...
+ bazel test :all
+ echo $(date): Bazel test completed.
+fi
diff --git a/kokoro/scripts/linux/build.sh b/kokoro/scripts/linux/build.sh
index 347f353..4731ebd 100644
--- a/kokoro/scripts/linux/build.sh
+++ b/kokoro/scripts/linux/build.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (c) 2018 Google LLC.
+# Copyright (c) 2021 Google LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,89 +17,38 @@
# Fail on any error.
set -e
-# Display commands being run.
-set -x
-BUILD_ROOT=$PWD
-SRC=$PWD/github/SPIRV-Tools
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd )"
+ROOT_DIR="$( cd "${SCRIPT_DIR}/../../.." >/dev/null 2>&1 && pwd )"
+
CONFIG=$1
COMPILER=$2
-
-SKIP_TESTS="False"
-BUILD_TYPE="Debug"
-
-CMAKE_C_CXX_COMPILER=""
-if [ $COMPILER = "clang" ]
-then
- PATH=/usr/lib/llvm-3.8/bin:$PATH
- CMAKE_C_CXX_COMPILER="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
-fi
-
-# Possible configurations are:
-# ASAN, COVERAGE, RELEASE, DEBUG, DEBUG_EXCEPTION, RELEASE_MINGW
-
-if [ $CONFIG = "RELEASE" ] || [ $CONFIG = "RELEASE_MINGW" ]
-then
- BUILD_TYPE="RelWithDebInfo"
-fi
-
-ADDITIONAL_CMAKE_FLAGS=""
-if [ $CONFIG = "ASAN" ]
-then
- ADDITIONAL_CMAKE_FLAGS="-DSPIRV_USE_SANITIZER=address,bounds,null"
- [ $COMPILER = "clang" ] || { echo "$CONFIG requires clang"; exit 1; }
-elif [ $CONFIG = "COVERAGE" ]
-then
- ADDITIONAL_CMAKE_FLAGS="-DENABLE_CODE_COVERAGE=ON"
- SKIP_TESTS="True"
-elif [ $CONFIG = "DEBUG_EXCEPTION" ]
-then
- ADDITIONAL_CMAKE_FLAGS="-DDISABLE_EXCEPTIONS=ON -DDISABLE_RTTI=ON"
-elif [ $CONFIG = "RELEASE_MINGW" ]
-then
- ADDITIONAL_CMAKE_FLAGS="-Dgtest_disable_pthreads=ON -DCMAKE_TOOLCHAIN_FILE=$SRC/cmake/linux-mingw-toolchain.cmake"
- SKIP_TESTS="True"
-fi
-
-# Get NINJA.
-wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip
-unzip -q ninja-linux.zip
-export PATH="$PWD:$PATH"
-
-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
-git clone --depth=1 --branch v3.13.0 https://github.com/protocolbuffers/protobuf external/protobuf
-
-mkdir build && cd $SRC/build
-
-# Invoke the build.
+TOOL=$3
BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT}
-echo $(date): Starting build...
-cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 -GNinja -DCMAKE_INSTALL_PREFIX=$KOKORO_ARTIFACTS_DIR/install -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DRE2_BUILD_TESTING=OFF -DSPIRV_BUILD_FUZZER=ON $ADDITIONAL_CMAKE_FLAGS $CMAKE_C_CXX_COMPILER ..
-echo $(date): Build everything...
-ninja
-echo $(date): Build completed.
+docker run --rm -i \
+ --volume "${ROOT_DIR}:${ROOT_DIR}" \
+ --volume "${KOKORO_ARTIFACTS_DIR}:${KOKORO_ARTIFACTS_DIR}" \
+ --workdir "${ROOT_DIR}" \
+ --env SCRIPT_DIR=${SCRIPT_DIR} \
+ --env ROOT_DIR=${ROOT_DIR} \
+ --env CONFIG=${CONFIG} \
+ --env COMPILER=${COMPILER} \
+ --env TOOL=${TOOL} \
+ --env KOKORO_ARTIFACTS_DIR="${KOKORO_ARTIFACTS_DIR}" \
+ --env BUILD_SHA="${BUILD_SHA}" \
+ --entrypoint "${SCRIPT_DIR}/build-docker.sh" \
+ "gcr.io/shaderc-build/radial-build:latest"
-if [ $CONFIG = "COVERAGE" ]
-then
- echo $(date): Check coverage...
- ninja report-coverage
- echo $(date): Check coverage completed.
-fi
-echo $(date): Starting ctest...
-if [ $SKIP_TESTS = "False" ]
-then
- ctest -j4 --output-on-failure --timeout 300
-fi
-echo $(date): ctest completed.
+# chown the given directory to the current user, if it exists.
+# Docker creates files with the root user - this can upset the Kokoro artifact copier.
+function chown_dir() {
+ dir=$1
+ if [[ -d "$dir" ]]; then
+ sudo chown -R "$(id -u):$(id -g)" "$dir"
+ fi
+}
-# Package the build.
-ninja install
-cd $KOKORO_ARTIFACTS_DIR
-tar czf install.tgz install
+chown_dir "${ROOT_DIR}/build"
+chown_dir "${ROOT_DIR}/external"
diff --git a/kokoro/shaderc-smoketest/build.sh b/kokoro/shaderc-smoketest/build.sh
old mode 100644
new mode 100755
index 0856c9b..60c816d
--- a/kokoro/shaderc-smoketest/build.sh
+++ b/kokoro/shaderc-smoketest/build.sh
@@ -18,54 +18,5 @@
# Display commands being run.
set -x
-BUILD_ROOT=$PWD
-GITHUB_DIR=$BUILD_ROOT/github
-
-SKIP_TESTS="False"
-BUILD_TYPE="Release"
-
-# Get NINJA.
-wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip
-unzip -q ninja-linux.zip
-export PATH="$PWD:$PATH"
-
-# Get shaderc.
-cd $GITHUB_DIR
-git clone https://github.com/google/shaderc.git
-SHADERC_DIR=$GITHUB_DIR/shaderc
-cd $SHADERC_DIR/third_party
-
-# Get shaderc dependencies. Link the appropriate SPIRV-Tools.
-git clone https://github.com/google/googletest.git
-git clone https://github.com/KhronosGroup/glslang.git
-ln -s $GITHUB_DIR/SPIRV-Tools spirv-tools
-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
-
-cd $SHADERC_DIR
-mkdir build
-cd $SHADERC_DIR/build
-
-# Invoke the build.
-BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT}
-echo $(date): Starting build...
-cmake -GNinja -DRE2_BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
-
-echo $(date): Build glslang...
-ninja glslangValidator
-
-echo $(date): Build everything...
-ninja
-echo $(date): Build completed.
-
-echo $(date): Check Shaderc for copyright notices...
-ninja check-copyright
-
-echo $(date): Starting ctest...
-if [ $SKIP_TESTS = "False" ]
-then
- ctest --output-on-failure -j4
-fi
-echo $(date): ctest completed.
-
+SCRIPT_DIR=`dirname "$BASH_SOURCE"`
+source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE gcc cmake-smoketest
diff --git a/source/binary.cpp b/source/binary.cpp
index 75a997d..7448721 100644
--- a/source/binary.cpp
+++ b/source/binary.cpp
@@ -655,7 +655,9 @@
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
- case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: {
+ case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
+ case SPV_OPERAND_TYPE_FPDENORM_MODE:
+ case SPV_OPERAND_TYPE_FPOPERATION_MODE: {
// A single word that is a plain enum value.
// Map an optional operand type to its corresponding concrete type.
diff --git a/source/disassemble.cpp b/source/disassemble.cpp
index e763251..966a59c 100644
--- a/source/disassemble.cpp
+++ b/source/disassemble.cpp
@@ -326,7 +326,9 @@
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
- case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: {
+ case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
+ case SPV_OPERAND_TYPE_FPDENORM_MODE:
+ case SPV_OPERAND_TYPE_FPOPERATION_MODE: {
spv_operand_desc entry;
if (grammar_.lookupOperand(operand.type, word, &entry))
assert(false && "should have caught this earlier");
diff --git a/source/ext_inst.cpp b/source/ext_inst.cpp
index 3471ebe..795cb0f 100644
--- a/source/ext_inst.cpp
+++ b/source/ext_inst.cpp
@@ -89,7 +89,6 @@
case SPV_ENV_UNIVERSAL_1_3:
case SPV_ENV_VULKAN_1_1:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
- case SPV_ENV_WEBGPU_0:
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
diff --git a/source/fuzz/transformation_duplicate_region_with_selection.cpp b/source/fuzz/transformation_duplicate_region_with_selection.cpp
index 07758cd..2ac6259 100644
--- a/source/fuzz/transformation_duplicate_region_with_selection.cpp
+++ b/source/fuzz/transformation_duplicate_region_with_selection.cpp
@@ -209,7 +209,7 @@
return false;
}
} else {
- auto duplicate_label = original_label_to_duplicate_label[block->id()];
+ auto duplicate_label = original_label_to_duplicate_label.at(block->id());
// Each id assigned to labels in the region must be distinct and fresh.
if (!duplicate_label ||
!CheckIdIsFreshAndNotUsedByThisTransformation(
@@ -217,7 +217,7 @@
return false;
}
}
- for (auto instr : *block) {
+ for (auto& instr : *block) {
if (!instr.HasResultId()) {
continue;
}
@@ -228,7 +228,7 @@
return false;
}
} else {
- auto duplicate_id = original_id_to_duplicate_id[instr.result_id()];
+ auto duplicate_id = original_id_to_duplicate_id.at(instr.result_id());
// Id assigned to this result id in the region must be distinct and
// fresh.
if (!duplicate_id ||
@@ -237,43 +237,48 @@
return false;
}
}
- if (&instr == &*exit_block->tail() ||
- fuzzerutil::IdIsAvailableBeforeInstruction(
- ir_context, &*exit_block->tail(), instr.result_id())) {
- // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3787):
- // Consider not adding OpPhi instructions for the pointers and
- // sampled images which are unused after the region, so that the
- // transformation could be still applicable.
-
- // Using pointers with OpPhi requires capability VariablePointers.
- if (ir_context->get_def_use_mgr()->GetDef(instr.type_id())->opcode() ==
- SpvOpTypePointer &&
- !ir_context->get_feature_mgr()->HasCapability(
- SpvCapabilityVariablePointers)) {
- return false;
- }
-
- // OpTypeSampledImage cannot be the result type of an OpPhi instruction.
- if (ir_context->get_def_use_mgr()->GetDef(instr.type_id())->opcode() ==
- SpvOpTypeSampledImage) {
- return false;
- }
-
- // Every instruction with a result id available at the end of the region
- // must be present in the map |original_id_to_phi_id|, unless overflow
- // ids are present.
- if (original_id_to_phi_id.count(instr.result_id()) == 0) {
- if (!transformation_context.GetOverflowIdSource()->HasOverflowIds()) {
+ // If the instruction is available at the end of the region then we would
+ // like to be able to add an OpPhi instruction at the merge point of the
+ // duplicated region to capture the values computed by both duplicates of
+ // the instruction, so that this is also available after the region. We
+ // do this not just for instructions that are already used after the
+ // region, but for all instructions so that the phi is available to future
+ // transformations.
+ if (AvailableAfterRegion(instr, exit_block, ir_context)) {
+ if (!ValidOpPhiArgument(instr, ir_context)) {
+ // The instruction cannot be used as an OpPhi argument. This is a
+ // blocker if there are uses of the instruction after the region.
+ // Otherwise we can simply avoid generating an OpPhi for this
+ // instruction and its duplicate.
+ if (!ir_context->get_def_use_mgr()->WhileEachUser(
+ &instr,
+ [ir_context,
+ ®ion_set](opt::Instruction* use_instr) -> bool {
+ opt::BasicBlock* use_block =
+ ir_context->get_instr_block(use_instr);
+ return use_block == nullptr ||
+ region_set.count(use_block) > 0;
+ })) {
return false;
}
} else {
- auto phi_id = original_id_to_phi_id[instr.result_id()];
- // Id assigned to this result id in the region must be distinct and
- // fresh.
- if (!phi_id ||
- !CheckIdIsFreshAndNotUsedByThisTransformation(
- phi_id, ir_context, &ids_used_by_this_transformation)) {
- return false;
+ // Every instruction with a result id available at the end of the
+ // region must be present in the map |original_id_to_phi_id|, unless
+ // overflow ids are present.
+ if (original_id_to_phi_id.count(instr.result_id()) == 0) {
+ if (!transformation_context.GetOverflowIdSource()
+ ->HasOverflowIds()) {
+ return false;
+ }
+ } else {
+ auto phi_id = original_id_to_phi_id.at(instr.result_id());
+ // Id assigned to this result id in the region must be distinct and
+ // fresh.
+ if (!phi_id ||
+ !CheckIdIsFreshAndNotUsedByThisTransformation(
+ phi_id, ir_context, &ids_used_by_this_transformation)) {
+ return false;
+ }
}
}
}
@@ -329,7 +334,7 @@
{block->id(),
transformation_context->GetOverflowIdSource()->GetNextOverflowId()});
}
- for (auto instr : *block) {
+ for (auto& instr : *block) {
if (!instr.HasResultId()) {
continue;
}
@@ -338,9 +343,8 @@
{instr.result_id(), transformation_context->GetOverflowIdSource()
->GetNextOverflowId()});
}
- if (&instr == &*exit_block->tail() ||
- fuzzerutil::IdIsAvailableBeforeInstruction(
- ir_context, &*exit_block->tail(), instr.result_id())) {
+ if (AvailableAfterRegion(instr, exit_block, ir_context) &&
+ ValidOpPhiArgument(instr, ir_context)) {
if (original_id_to_phi_id.count(instr.result_id()) == 0) {
original_id_to_phi_id.insert(
{instr.result_id(), transformation_context->GetOverflowIdSource()
@@ -414,12 +418,12 @@
}
fuzzerutil::UpdateModuleIdBound(
- ir_context, original_label_to_duplicate_label[block->id()]);
+ ir_context, original_label_to_duplicate_label.at(block->id()));
std::unique_ptr<opt::BasicBlock> duplicated_block =
MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
ir_context, SpvOpLabel, 0,
- original_label_to_duplicate_label[block->id()],
+ original_label_to_duplicate_label.at(block->id()),
opt::Instruction::OperandList()));
for (auto& instr : *block) {
@@ -444,8 +448,10 @@
duplicated_block->AddInstruction(
std::unique_ptr<opt::Instruction>(cloned_instr));
- fuzzerutil::UpdateModuleIdBound(
- ir_context, original_id_to_duplicate_id[instr.result_id()]);
+ if (instr.HasResultId()) {
+ fuzzerutil::UpdateModuleIdBound(
+ ir_context, original_id_to_duplicate_id.at(instr.result_id()));
+ }
// If an id from the original region was used in this instruction,
// replace it with the value from |original_id_to_duplicate_id|.
@@ -456,8 +462,7 @@
original_label_to_duplicate_label](uint32_t* op) {
if (original_id_to_duplicate_id.count(*op) != 0) {
*op = original_id_to_duplicate_id.at(*op);
- }
- if (original_label_to_duplicate_label.count(*op) != 0) {
+ } else if (original_label_to_duplicate_label.count(*op) != 0) {
*op = original_label_to_duplicate_label.at(*op);
}
});
@@ -484,26 +489,27 @@
for (auto& block : region_blocks) {
for (auto& instr : *block) {
- if (instr.result_id() != 0 &&
- (&instr == &*exit_block->tail() ||
- fuzzerutil::IdIsAvailableBeforeInstruction(
- ir_context, &*exit_block->tail(), instr.result_id()))) {
- // Add the OpPhi instruction for every result id that is
- // available at the end of the region (the last instruction
- // of the |exit_block|)
+ if (instr.result_id() == 0) {
+ continue;
+ }
+ if (AvailableAfterRegion(instr, exit_block, ir_context) &&
+ ValidOpPhiArgument(instr, ir_context)) {
+ // Add an OpPhi instruction for every result id that is available at
+ // the end of the region, as long as the result id is valid for use
+ // with OpPhi.
merge_block->AddInstruction(MakeUnique<opt::Instruction>(
ir_context, SpvOpPhi, instr.type_id(),
- original_id_to_phi_id[instr.result_id()],
+ original_id_to_phi_id.at(instr.result_id()),
opt::Instruction::OperandList({
{SPV_OPERAND_TYPE_ID, {instr.result_id()}},
{SPV_OPERAND_TYPE_ID, {exit_block->id()}},
{SPV_OPERAND_TYPE_ID,
- {original_id_to_duplicate_id[instr.result_id()]}},
+ {original_id_to_duplicate_id.at(instr.result_id())}},
{SPV_OPERAND_TYPE_ID, {duplicated_exit_block->id()}},
})));
fuzzerutil::UpdateModuleIdBound(
- ir_context, original_id_to_phi_id[instr.result_id()]);
+ ir_context, original_id_to_phi_id.at(instr.result_id()));
// If the instruction has been remapped by an OpPhi, look
// for all its uses outside of the region and outside of the
@@ -544,7 +550,8 @@
{{SPV_OPERAND_TYPE_ID, {message_.condition_id()}},
{SPV_OPERAND_TYPE_ID, {message_.entry_block_id()}},
{SPV_OPERAND_TYPE_ID,
- {original_label_to_duplicate_label[message_.entry_block_id()]}}})));
+ {original_label_to_duplicate_label.at(
+ message_.entry_block_id())}}})));
// Move the terminator of |exit_block| to the end of
// |merge_block|.
@@ -678,5 +685,38 @@
return result;
}
+bool TransformationDuplicateRegionWithSelection::AvailableAfterRegion(
+ const opt::Instruction& instr, opt::BasicBlock* exit_block,
+ opt::IRContext* ir_context) {
+ opt::Instruction* final_instruction_in_region = &*exit_block->tail();
+ return &instr == final_instruction_in_region ||
+ fuzzerutil::IdIsAvailableBeforeInstruction(
+ ir_context, final_instruction_in_region, instr.result_id());
+}
+
+bool TransformationDuplicateRegionWithSelection::ValidOpPhiArgument(
+ const opt::Instruction& instr, opt::IRContext* ir_context) {
+ opt::Instruction* instr_type =
+ ir_context->get_def_use_mgr()->GetDef(instr.type_id());
+
+ // It is invalid to apply OpPhi to void-typed values.
+ if (instr_type->opcode() == SpvOpTypeVoid) {
+ return false;
+ }
+
+ // Using pointers with OpPhi requires capability VariablePointers.
+ if (instr_type->opcode() == SpvOpTypePointer &&
+ !ir_context->get_feature_mgr()->HasCapability(
+ SpvCapabilityVariablePointers)) {
+ return false;
+ }
+
+ // OpTypeSampledImage cannot be the result type of an OpPhi instruction.
+ if (instr_type->opcode() == SpvOpTypeSampledImage) {
+ return false;
+ }
+ return true;
+}
+
} // namespace fuzz
} // namespace spvtools
diff --git a/source/fuzz/transformation_duplicate_region_with_selection.h b/source/fuzz/transformation_duplicate_region_with_selection.h
index d6f0ad9..a2b9a43 100644
--- a/source/fuzz/transformation_duplicate_region_with_selection.h
+++ b/source/fuzz/transformation_duplicate_region_with_selection.h
@@ -66,6 +66,17 @@
opt::IRContext* ir_context, opt::BasicBlock* entry_block,
opt::BasicBlock* exit_block);
+ // Returns true if and only if |instr| is available at the end of the region
+ // for which |exit_block| is the final block.
+ static bool AvailableAfterRegion(const opt::Instruction& instr,
+ opt::BasicBlock* exit_block,
+ opt::IRContext* ir_context);
+
+ // Returns true if and only if |instr| is valid as an argument to an OpPhi
+ // instruction.
+ static bool ValidOpPhiArgument(const opt::Instruction& instr,
+ opt::IRContext* ir_context);
+
std::unordered_set<uint32_t> GetFreshIds() const override;
protobufs::Transformation ToMessage() const override;
diff --git a/source/libspirv.cpp b/source/libspirv.cpp
index a1ed11d..0bc0935 100644
--- a/source/libspirv.cpp
+++ b/source/libspirv.cpp
@@ -14,8 +14,8 @@
#include "spirv-tools/libspirv.hpp"
+#include <cassert>
#include <iostream>
-
#include <string>
#include <utility>
#include <vector>
@@ -60,7 +60,9 @@
spv_context context; // C interface context object.
};
-SpirvTools::SpirvTools(spv_target_env env) : impl_(new Impl(env)) {}
+SpirvTools::SpirvTools(spv_target_env env) : impl_(new Impl(env)) {
+ assert(env != SPV_ENV_WEBGPU_0);
+}
SpirvTools::~SpirvTools() {}
diff --git a/source/link/linker.cpp b/source/link/linker.cpp
index da6f0a7..8da4a98 100644
--- a/source/link/linker.cpp
+++ b/source/link/linker.cpp
@@ -676,14 +676,15 @@
if (schema != 0u) {
position.index = 4u;
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
- << "Schema is non-zero for module " << i << ".";
+ << "Schema is non-zero for module " << i + 1 << ".";
}
std::unique_ptr<IRContext> ir_context = BuildModule(
c_context->target_env, consumer, binaries[i], binary_sizes[i]);
if (ir_context == nullptr)
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
- << "Failed to build a module out of " << ir_contexts.size() << ".";
+ << "Failed to build module " << i + 1 << " out of " << num_binaries
+ << ".";
modules.push_back(ir_context->module());
ir_contexts.push_back(std::move(ir_context));
}
diff --git a/source/opcode.cpp b/source/opcode.cpp
index c80e3a0..d87e828 100644
--- a/source/opcode.cpp
+++ b/source/opcode.cpp
@@ -444,15 +444,32 @@
}
}
+bool spvOpcodeIsAbort(SpvOp opcode) {
+ switch (opcode) {
+ case SpvOpKill:
+ case SpvOpUnreachable:
+ case SpvOpTerminateInvocation:
+ case SpvOpTerminateRayKHR:
+ case SpvOpIgnoreIntersectionKHR:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool spvOpcodeIsReturnOrAbort(SpvOp opcode) {
- return spvOpcodeIsReturn(opcode) || opcode == SpvOpKill ||
- opcode == SpvOpUnreachable || opcode == SpvOpTerminateInvocation;
+ return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode);
}
bool spvOpcodeIsBlockTerminator(SpvOp opcode) {
return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
}
+bool spvOpcodeTerminatesExecution(SpvOp opcode) {
+ return opcode == SpvOpKill || opcode == SpvOpTerminateInvocation ||
+ opcode == SpvOpTerminateRayKHR || opcode == SpvOpIgnoreIntersectionKHR;
+}
+
bool spvOpcodeIsBaseOpaqueType(SpvOp opcode) {
switch (opcode) {
case SpvOpTypeImage:
diff --git a/source/opcode.h b/source/opcode.h
index 3702cb3..c8525a2 100644
--- a/source/opcode.h
+++ b/source/opcode.h
@@ -110,10 +110,18 @@
// Returns true if the given opcode is a return instruction.
bool spvOpcodeIsReturn(SpvOp opcode);
+// Returns true if the given opcode aborts execution.
+bool spvOpcodeIsAbort(SpvOp opcode);
+
// Returns true if the given opcode is a return instruction or it aborts
// execution.
bool spvOpcodeIsReturnOrAbort(SpvOp opcode);
+// Returns true if the given opcode is a kill instruction or it terminates
+// execution. Note that branches, returns, and unreachables do not terminate
+// execution.
+bool spvOpcodeTerminatesExecution(SpvOp opcode);
+
// Returns true if the given opcode is a basic block terminator.
bool spvOpcodeIsBlockTerminator(SpvOp opcode);
diff --git a/source/operand.cpp b/source/operand.cpp
index d4b64a8..5a69fb2 100644
--- a/source/operand.cpp
+++ b/source/operand.cpp
@@ -24,6 +24,7 @@
#include "DebugInfo.h"
#include "OpenCLDebugInfo100.h"
#include "source/macro.h"
+#include "source/opcode.h"
#include "source/spirv_constant.h"
#include "source/spirv_target_env.h"
@@ -264,6 +265,11 @@
case SPV_OPERAND_TYPE_IMAGE_CHANNEL_DATA_TYPE:
return "image channel data type";
+ case SPV_OPERAND_TYPE_FPDENORM_MODE:
+ return "FP denorm mode";
+ case SPV_OPERAND_TYPE_FPOPERATION_MODE:
+ return "FP operation mode";
+
case SPV_OPERAND_TYPE_NONE:
return "NONE";
default:
@@ -347,6 +353,8 @@
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
+ case SPV_OPERAND_TYPE_FPDENORM_MODE:
+ case SPV_OPERAND_TYPE_FPOPERATION_MODE:
return true;
default:
break;
@@ -491,6 +499,11 @@
std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
SpvOp opcode) {
std::function<bool(unsigned index)> out;
+ if (spvOpcodeGeneratesType(opcode)) {
+ // All types can use forward pointers.
+ out = [](unsigned) { return true; };
+ return out;
+ }
switch (opcode) {
case SpvOpExecutionMode:
case SpvOpExecutionModeId:
@@ -503,7 +516,6 @@
case SpvOpDecorateId:
case SpvOpDecorateStringGOOGLE:
case SpvOpMemberDecorateStringGOOGLE:
- case SpvOpTypeStruct:
case SpvOpBranch:
case SpvOpLoopMerge:
out = [](unsigned) { return true; };
diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt
index f3ac590..14a6bee 100644
--- a/source/opt/CMakeLists.txt
+++ b/source/opt/CMakeLists.txt
@@ -32,7 +32,6 @@
dead_branch_elim_pass.h
dead_insert_elim_pass.h
dead_variable_elimination.h
- decompose_initialized_variables_pass.h
decoration_manager.h
debug_info_manager.h
def_use_manager.h
@@ -52,7 +51,6 @@
fold_spec_constant_op_and_composite_pass.h
freeze_spec_constant_value_pass.h
function.h
- generate_webgpu_initializers_pass.h
graphics_robust_access_pass.h
if_conversion.h
inline_exhaustive_pass.h
@@ -103,10 +101,8 @@
scalar_replacement_pass.h
set_spec_constant_default_value_pass.h
simplification_pass.h
- split_invalid_unreachable_pass.h
ssa_rewrite_pass.h
strength_reduction_pass.h
- strip_atomic_counter_memory_pass.h
strip_debug_info_pass.h
strip_reflect_info_pass.h
struct_cfg_analysis.h
@@ -140,7 +136,6 @@
dead_branch_elim_pass.cpp
dead_insert_elim_pass.cpp
dead_variable_elimination.cpp
- decompose_initialized_variables_pass.cpp
decoration_manager.cpp
debug_info_manager.cpp
def_use_manager.cpp
@@ -160,7 +155,6 @@
freeze_spec_constant_value_pass.cpp
function.cpp
graphics_robust_access_pass.cpp
- generate_webgpu_initializers_pass.cpp
if_conversion.cpp
inline_exhaustive_pass.cpp
inline_opaque_pass.cpp
@@ -173,7 +167,6 @@
instrument_pass.cpp
ir_context.cpp
ir_loader.cpp
- legalize_vector_shuffle_pass.cpp
licm_pass.cpp
local_access_chain_convert_pass.cpp
local_redundancy_elimination.cpp
@@ -208,10 +201,8 @@
scalar_replacement_pass.cpp
set_spec_constant_default_value_pass.cpp
simplification_pass.cpp
- split_invalid_unreachable_pass.cpp
ssa_rewrite_pass.cpp
strength_reduction_pass.cpp
- strip_atomic_counter_memory_pass.cpp
strip_debug_info_pass.cpp
strip_reflect_info_pass.cpp
struct_cfg_analysis.cpp
diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp
index 39d468f..81b2232 100644
--- a/source/opt/aggressive_dead_code_elim_pass.cpp
+++ b/source/opt/aggressive_dead_code_elim_pass.cpp
@@ -991,9 +991,11 @@
"SPV_NV_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_terminate_invocation",
+ "SPV_KHR_shader_clock",
});
}
diff --git a/source/opt/basic_block.cpp b/source/opt/basic_block.cpp
index b7e122c..e82a744 100644
--- a/source/opt/basic_block.cpp
+++ b/source/opt/basic_block.cpp
@@ -230,7 +230,7 @@
std::ostringstream str;
ForEachInst([&str, options](const Instruction* inst) {
str << inst->PrettyPrint(options);
- if (!IsTerminatorInst(inst->opcode())) {
+ if (!spvOpcodeIsBlockTerminator(inst->opcode())) {
str << std::endl;
}
});
diff --git a/source/opt/build_module.cpp b/source/opt/build_module.cpp
index fc76a3c..3b606dc 100644
--- a/source/opt/build_module.cpp
+++ b/source/opt/build_module.cpp
@@ -50,11 +50,20 @@
MessageConsumer consumer,
const uint32_t* binary,
const size_t size) {
+ return BuildModule(env, consumer, binary, size, true);
+}
+
+std::unique_ptr<opt::IRContext> BuildModule(spv_target_env env,
+ MessageConsumer consumer,
+ const uint32_t* binary,
+ const size_t size,
+ bool extra_line_tracking) {
auto context = spvContextCreate(env);
SetContextMessageConsumer(context, consumer);
auto irContext = MakeUnique<opt::IRContext>(env, consumer);
opt::IrLoader loader(consumer, irContext->module());
+ loader.SetExtraLineTracking(extra_line_tracking);
spv_result_t status = spvBinaryParse(context, &loader, binary, size,
SetSpvHeader, SetSpvInst, nullptr);
diff --git a/source/opt/build_module.h b/source/opt/build_module.h
index c9d1cf2..29eaf66 100644
--- a/source/opt/build_module.h
+++ b/source/opt/build_module.h
@@ -27,7 +27,15 @@
// Builds an Module returns the owning IRContext from the given SPIR-V
// |binary|. |size| specifies number of words in |binary|. The |binary| will be
// decoded according to the given target |env|. Returns nullptr if errors occur
-// and sends the errors to |consumer|.
+// and sends the errors to |consumer|. When |extra_line_tracking| is true,
+// extra OpLine instructions are injected to better presere line numbers while
+// later transforms mutate the module.
+std::unique_ptr<opt::IRContext> BuildModule(spv_target_env env,
+ MessageConsumer consumer,
+ const uint32_t* binary, size_t size,
+ bool extra_line_tracking);
+
+// Like above, with extra line tracking turned on.
std::unique_ptr<opt::IRContext> BuildModule(spv_target_env env,
MessageConsumer consumer,
const uint32_t* binary,
diff --git a/source/opt/decompose_initialized_variables_pass.cpp b/source/opt/decompose_initialized_variables_pass.cpp
deleted file mode 100644
index 875bf7e..0000000
--- a/source/opt/decompose_initialized_variables_pass.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "source/opt/decompose_initialized_variables_pass.h"
-
-#include "source/opt/ir_context.h"
-
-namespace spvtools {
-namespace opt {
-
-using inst_iterator = InstructionList::iterator;
-
-namespace {
-
-bool HasInitializer(Instruction* inst) {
- if (inst->opcode() != SpvOpVariable) return false;
- if (inst->NumOperands() < 4) return false;
-
- return true;
-}
-
-} // namespace
-
-Pass::Status DecomposeInitializedVariablesPass::Process() {
- auto* module = context()->module();
- std::unordered_set<Instruction*> changed;
-
- std::vector<std::tuple<uint32_t, uint32_t>> global_stores;
- for (auto iter = module->types_values_begin();
- iter != module->types_values_end(); ++iter) {
- Instruction* inst = &(*iter);
- if (!HasInitializer(inst)) continue;
-
- auto var_id = inst->result_id();
- auto val_id = inst->GetOperand(3).words[0];
- global_stores.push_back(std::make_tuple(var_id, val_id));
- iter->RemoveOperand(3);
- changed.insert(&*iter);
- }
-
- std::unordered_set<uint32_t> entry_ids;
- for (auto entry = module->entry_points().begin();
- entry != module->entry_points().end(); ++entry) {
- entry_ids.insert(entry->GetSingleWordInOperand(1));
- }
-
- for (auto func = module->begin(); func != module->end(); ++func) {
- std::vector<Instruction*> function_stores;
- auto first_block = func->entry().get();
- inst_iterator insert_point = first_block->begin();
- for (auto iter = first_block->begin();
- iter != first_block->end() && iter->opcode() == SpvOpVariable;
- ++iter) {
- // For valid SPIRV-V, there is guaranteed to be at least one instruction
- // after the OpVariable instructions.
- insert_point = (*iter).NextNode();
- Instruction* inst = &(*iter);
- if (!HasInitializer(inst)) continue;
-
- auto var_id = inst->result_id();
- auto val_id = inst->GetOperand(3).words[0];
- Instruction* store_inst = new Instruction(
- context(), SpvOpStore, 0, 0,
- {{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}});
- function_stores.push_back(store_inst);
- iter->RemoveOperand(3);
- changed.insert(&*iter);
- }
-
- if (entry_ids.find(func->result_id()) != entry_ids.end()) {
- for (auto store_ids : global_stores) {
- uint32_t var_id;
- uint32_t val_id;
- std::tie(var_id, val_id) = store_ids;
- auto* store_inst = new Instruction(
- context(), SpvOpStore, 0, 0,
- {{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}});
- context()->set_instr_block(store_inst, &*first_block);
- first_block->AddInstruction(std::unique_ptr<Instruction>(store_inst));
- store_inst->InsertBefore(&*insert_point);
- changed.insert(store_inst);
- }
- }
-
- for (auto store = function_stores.begin(); store != function_stores.end();
- ++store) {
- context()->set_instr_block(*store, first_block);
- (*store)->InsertBefore(&*insert_point);
- changed.insert(*store);
- }
- }
-
- auto* def_use_mgr = get_def_use_mgr();
- for (auto* inst : changed) def_use_mgr->UpdateDefUse(inst);
-
- return !changed.empty() ? Pass::Status::SuccessWithChange
- : Pass::Status::SuccessWithoutChange;
-}
-
-} // namespace opt
-} // namespace spvtools
diff --git a/source/opt/decompose_initialized_variables_pass.h b/source/opt/decompose_initialized_variables_pass.h
deleted file mode 100644
index c0bd35e..0000000
--- a/source/opt/decompose_initialized_variables_pass.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SOURCE_OPT_DECOMPOSE_INITALIZED_VAIRABLES_PASS_H_
-#define SOURCE_OPT_DECOMPOSE_INITALIZED_VAIRABLES_PASS_H_
-
-#include "source/opt/ir_context.h"
-#include "source/opt/module.h"
-#include "source/opt/pass.h"
-
-namespace spvtools {
-namespace opt {
-
-// Converts variable declartions with initializers into seperate declaration and
-// assignment statements. This is done due to known issues with some Vulkan
-// implementations' handling of initialized variables.
-//
-// Only decomposes variables with storage classes that are valid in Vulkan
-// execution environments; Output, Private, and Function.
-// Currently only Function is implemented.
-class DecomposeInitializedVariablesPass : public Pass {
- public:
- const char* name() const override {
- return "decompose-initialized-variables";
- }
- Status Process() override;
-
- IRContext::Analysis GetPreservedAnalyses() override {
- return IRContext::kAnalysisInstrToBlockMapping |
- IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
- IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis |
- IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
- IRContext::kAnalysisScalarEvolution |
- IRContext::kAnalysisRegisterPressure |
- IRContext::kAnalysisValueNumberTable |
- IRContext::kAnalysisStructuredCFG |
- IRContext::kAnalysisBuiltinVarId |
- IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes |
- IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants;
- }
-};
-
-} // namespace opt
-} // namespace spvtools
-
-#endif // SOURCE_OPT_DECOMPOSE_INITALIZED_VAIRABLES_PASS_H_
diff --git a/source/opt/desc_sroa.cpp b/source/opt/desc_sroa.cpp
index b68549a..5e95006 100644
--- a/source/opt/desc_sroa.cpp
+++ b/source/opt/desc_sroa.cpp
@@ -63,16 +63,7 @@
// All structures with descriptor assignments must be replaced by variables,
// one for each of their members - with the exceptions of buffers.
- // Buffers are represented as structures, but we shouldn't replace a buffer
- // with its elements. All buffers have offset decorations for members of their
- // structure types.
- bool has_offset_decoration = false;
- context()->get_decoration_mgr()->ForEachDecoration(
- var_type_inst->result_id(), SpvDecorationOffset,
- [&has_offset_decoration](const Instruction&) {
- has_offset_decoration = true;
- });
- if (has_offset_decoration) {
+ if (IsTypeOfStructuredBuffer(var_type_inst)) {
return false;
}
@@ -99,6 +90,23 @@
return true;
}
+bool DescriptorScalarReplacement::IsTypeOfStructuredBuffer(
+ const Instruction* type) const {
+ if (type->opcode() != SpvOpTypeStruct) {
+ return false;
+ }
+
+ // All buffers have offset decorations for members of their structure types.
+ // This is how we distinguish it from a structure of descriptors.
+ bool has_offset_decoration = false;
+ context()->get_decoration_mgr()->ForEachDecoration(
+ type->result_id(), SpvDecorationOffset,
+ [&has_offset_decoration](const Instruction&) {
+ has_offset_decoration = true;
+ });
+ return has_offset_decoration;
+}
+
bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
std::vector<Instruction*> access_chain_work_list;
std::vector<Instruction*> load_work_list;
@@ -368,7 +376,8 @@
// The number of bindings consumed by a structure is the sum of the bindings
// used by its members.
- if (type_inst->opcode() == SpvOpTypeStruct) {
+ if (type_inst->opcode() == SpvOpTypeStruct &&
+ !IsTypeOfStructuredBuffer(type_inst)) {
uint32_t sum = 0;
for (uint32_t i = 0; i < type_inst->NumInOperands(); i++)
sum += GetNumBindingsUsedByType(type_inst->GetSingleWordInOperand(i));
diff --git a/source/opt/desc_sroa.h b/source/opt/desc_sroa.h
index c3aa0ea..cd72fd3 100644
--- a/source/opt/desc_sroa.h
+++ b/source/opt/desc_sroa.h
@@ -93,6 +93,11 @@
// bindings used by its members.
uint32_t GetNumBindingsUsedByType(uint32_t type_id);
+ // Returns true if |type| is a type that could be used for a structured buffer
+ // as opposed to a type that would be used for a structure of resource
+ // descriptors.
+ bool IsTypeOfStructuredBuffer(const Instruction* type) const;
+
// A map from an OpVariable instruction to the set of variables that will be
// used to replace it. The entry |replacement_variables_[var][i]| is the id of
// a variable that will be used in the place of the the ith element of the
diff --git a/source/opt/eliminate_dead_members_pass.cpp b/source/opt/eliminate_dead_members_pass.cpp
index ab28932..173df62 100644
--- a/source/opt/eliminate_dead_members_pass.cpp
+++ b/source/opt/eliminate_dead_members_pass.cpp
@@ -228,15 +228,10 @@
const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
->AsIntConstant();
assert(member_idx);
- if (member_idx->type()->AsInteger()->width() == 32) {
- used_members_[type_id].insert(member_idx->GetU32());
- type_id = type_inst->GetSingleWordInOperand(member_idx->GetU32());
- } else {
- used_members_[type_id].insert(
- static_cast<uint32_t>(member_idx->GetU64()));
- type_id = type_inst->GetSingleWordInOperand(
- static_cast<uint32_t>(member_idx->GetU64()));
- }
+ uint32_t index =
+ static_cast<uint32_t>(member_idx->GetZeroExtendedValue());
+ used_members_[type_id].insert(index);
+ type_id = type_inst->GetSingleWordInOperand(index);
} break;
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
@@ -477,12 +472,8 @@
const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
->AsIntConstant();
assert(member_idx);
- uint32_t orig_member_idx;
- if (member_idx->type()->AsInteger()->width() == 32) {
- orig_member_idx = member_idx->GetU32();
- } else {
- orig_member_idx = static_cast<uint32_t>(member_idx->GetU64());
- }
+ uint32_t orig_member_idx =
+ static_cast<uint32_t>(member_idx->GetZeroExtendedValue());
uint32_t new_member_idx = GetNewMemberIndex(type_id, orig_member_idx);
assert(new_member_idx != kRemovedMember);
if (orig_member_idx != new_member_idx) {
diff --git a/source/opt/generate_webgpu_initializers_pass.cpp b/source/opt/generate_webgpu_initializers_pass.cpp
deleted file mode 100644
index eaed3c2..0000000
--- a/source/opt/generate_webgpu_initializers_pass.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "source/opt/generate_webgpu_initializers_pass.h"
-#include "source/opt/ir_context.h"
-
-namespace spvtools {
-namespace opt {
-
-using inst_iterator = InstructionList::iterator;
-
-namespace {
-
-bool NeedsWebGPUInitializer(Instruction* inst) {
- if (inst->opcode() != SpvOpVariable) return false;
-
- auto storage_class = inst->GetSingleWordOperand(2);
- if (storage_class != SpvStorageClassOutput &&
- storage_class != SpvStorageClassPrivate &&
- storage_class != SpvStorageClassFunction) {
- return false;
- }
-
- if (inst->NumOperands() > 3) return false;
-
- return true;
-}
-
-} // namespace
-
-Pass::Status GenerateWebGPUInitializersPass::Process() {
- auto* module = context()->module();
- bool changed = false;
-
- // Handle global/module scoped variables
- for (auto iter = module->types_values_begin();
- iter != module->types_values_end(); ++iter) {
- Instruction* inst = &(*iter);
-
- if (inst->opcode() == SpvOpConstantNull) {
- null_constant_type_map_[inst->type_id()] = inst;
- seen_null_constants_.insert(inst);
- continue;
- }
-
- if (!NeedsWebGPUInitializer(inst)) continue;
-
- changed = true;
-
- auto* constant_inst = GetNullConstantForVariable(inst);
- if (!constant_inst) return Status::Failure;
-
- if (seen_null_constants_.find(constant_inst) ==
- seen_null_constants_.end()) {
- constant_inst->InsertBefore(inst);
- null_constant_type_map_[inst->type_id()] = inst;
- seen_null_constants_.insert(inst);
- }
- AddNullInitializerToVariable(constant_inst, inst);
- }
-
- // Handle local/function scoped variables
- for (auto func = module->begin(); func != module->end(); ++func) {
- auto block = func->entry().get();
- for (auto iter = block->begin();
- iter != block->end() && iter->opcode() == SpvOpVariable; ++iter) {
- Instruction* inst = &(*iter);
- if (!NeedsWebGPUInitializer(inst)) continue;
-
- changed = true;
- auto* constant_inst = GetNullConstantForVariable(inst);
- if (!constant_inst) return Status::Failure;
-
- AddNullInitializerToVariable(constant_inst, inst);
- }
- }
-
- return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange;
-}
-
-Instruction* GenerateWebGPUInitializersPass::GetNullConstantForVariable(
- Instruction* variable_inst) {
- auto constant_mgr = context()->get_constant_mgr();
- auto* def_use_mgr = get_def_use_mgr();
-
- auto* ptr_inst = def_use_mgr->GetDef(variable_inst->type_id());
- auto type_id = ptr_inst->GetInOperand(1).words[0];
- if (null_constant_type_map_.find(type_id) == null_constant_type_map_.end()) {
- auto* constant_type = context()->get_type_mgr()->GetType(type_id);
- auto* constant = constant_mgr->GetConstant(constant_type, {});
- return constant_mgr->GetDefiningInstruction(constant, type_id);
- } else {
- return null_constant_type_map_[type_id];
- }
-}
-
-void GenerateWebGPUInitializersPass::AddNullInitializerToVariable(
- Instruction* constant_inst, Instruction* variable_inst) {
- auto constant_id = constant_inst->result_id();
- variable_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {constant_id}));
- get_def_use_mgr()->AnalyzeInstUse(variable_inst);
-}
-
-} // namespace opt
-} // namespace spvtools
diff --git a/source/opt/generate_webgpu_initializers_pass.h b/source/opt/generate_webgpu_initializers_pass.h
deleted file mode 100644
index f95e84c..0000000
--- a/source/opt/generate_webgpu_initializers_pass.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SOURCE_OPT_GENERATE_WEBGPU_INITIALIZERS_PASS_H_
-#define SOURCE_OPT_GENERATE_WEBGPU_INITIALIZERS_PASS_H_
-
-#include "source/opt/ir_context.h"
-#include "source/opt/module.h"
-#include "source/opt/pass.h"
-
-namespace spvtools {
-namespace opt {
-
-// Adds initializers to variables with storage classes Output, Private, and
-// Function if they are missing. In the WebGPU environment these storage classes
-// require that the variables are initialized. Currently they are initialized to
-// NULL, though in the future some of them may be initialized to the first value
-// that is stored in them, if that was a constant.
-class GenerateWebGPUInitializersPass : public Pass {
- public:
- const char* name() const override { return "generate-webgpu-initializers"; }
- Status Process() override;
-
- IRContext::Analysis GetPreservedAnalyses() override {
- return IRContext::kAnalysisInstrToBlockMapping |
- IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
- IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis |
- IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
- IRContext::kAnalysisScalarEvolution |
- IRContext::kAnalysisRegisterPressure |
- IRContext::kAnalysisValueNumberTable |
- IRContext::kAnalysisStructuredCFG |
- IRContext::kAnalysisBuiltinVarId |
- IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes |
- IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants;
- }
-
- private:
- using NullConstantTypeMap = std::unordered_map<uint32_t, Instruction*>;
- NullConstantTypeMap null_constant_type_map_;
- std::unordered_set<Instruction*> seen_null_constants_;
-
- Instruction* GetNullConstantForVariable(Instruction* variable_inst);
- void AddNullInitializerToVariable(Instruction* constant_inst,
- Instruction* variable_inst);
-};
-
-} // namespace opt
-} // namespace spvtools
-
-#endif // SOURCE_OPT_GENERATE_WEBGPU_INITIALIZERS_PASS_H_
diff --git a/source/opt/inline_exhaustive_pass.cpp b/source/opt/inline_exhaustive_pass.cpp
index 24f4e73..f24f744 100644
--- a/source/opt/inline_exhaustive_pass.cpp
+++ b/source/opt/inline_exhaustive_pass.cpp
@@ -38,11 +38,6 @@
if (newBlocks.size() > 1) UpdateSucceedingPhis(newBlocks);
// Replace old calling block with new block(s).
- // We need to kill the name and decorations for the call, which
- // will be deleted. Other instructions in the block will be moved to
- // newBlocks. We don't need to do anything with those.
- context()->KillNamesAndDecorates(&*ii);
-
bi = bi.Erase();
for (auto& bb : newBlocks) {
diff --git a/source/opt/inline_pass.cpp b/source/opt/inline_pass.cpp
index eaf29aa..8159ebf 100644
--- a/source/opt/inline_pass.cpp
+++ b/source/opt/inline_pass.cpp
@@ -383,9 +383,7 @@
uint32_t returnLabelId = 0;
for (auto callee_block_itr = calleeFn->begin();
callee_block_itr != calleeFn->end(); ++callee_block_itr) {
- if (callee_block_itr->tail()->opcode() == SpvOpUnreachable ||
- callee_block_itr->tail()->opcode() == SpvOpKill ||
- callee_block_itr->tail()->opcode() == SpvOpTerminateInvocation) {
+ if (spvOpcodeIsAbort(callee_block_itr->tail()->opcode())) {
returnLabelId = context()->TakeNextId();
break;
}
@@ -619,14 +617,6 @@
assert(resId != 0);
AddLoad(calleeTypeId, resId, returnVarId, &new_blk_ptr,
call_inst_itr->dbg_line_inst(), call_inst_itr->GetDebugScope());
- } else {
- // Even though it is very unlikely, it is possible that the result id of
- // the void-function call is used, so we need to generate an instruction
- // with that result id.
- std::unique_ptr<Instruction> undef_inst(
- new Instruction(context(), SpvOpUndef, call_inst_itr->type_id(),
- call_inst_itr->result_id(), {}));
- context()->AddGlobalValue(std::move(undef_inst));
}
// Move instructions of original caller block after call instruction.
@@ -645,6 +635,11 @@
for (auto& blk : *new_blocks) {
id2block_[blk->id()] = &*blk;
}
+
+ // We need to kill the name and decorations for the call, which will be
+ // deleted.
+ context()->KillNamesAndDecorates(&*call_inst_itr);
+
return true;
}
@@ -762,8 +757,7 @@
bool InlinePass::ContainsKillOrTerminateInvocation(Function* func) const {
return !func->WhileEachInst([](Instruction* inst) {
- const auto opcode = inst->opcode();
- return (opcode != SpvOpKill) && (opcode != SpvOpTerminateInvocation);
+ return !spvOpcodeTerminatesExecution(inst->opcode());
});
}
diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp
index 7eb2d1b..0085734 100644
--- a/source/opt/inst_bindless_check_pass.cpp
+++ b/source/opt/inst_bindless_check_pass.cpp
@@ -23,13 +23,17 @@
static const int kSpvSampledImageImageIdInIdx = 0;
static const int kSpvSampledImageSamplerIdInIdx = 1;
static const int kSpvImageSampledImageIdInIdx = 0;
+static const int kSpvCopyObjectOperandIdInIdx = 0;
static const int kSpvLoadPtrIdInIdx = 0;
static const int kSpvAccessChainBaseIdInIdx = 0;
static const int kSpvAccessChainIndex0IdInIdx = 1;
static const int kSpvTypeArrayLengthIdInIdx = 1;
static const int kSpvConstantValueInIdx = 0;
static const int kSpvVariableStorageClassInIdx = 0;
-
+static const int kSpvTypeImageDim = 1;
+static const int kSpvTypeImageDepth = 2;
+static const int kSpvTypeImageArrayed = 3;
+static const int kSpvTypeImageMS = 4;
} // anonymous namespace
// Avoid unused variable warning/error on Linux
@@ -75,42 +79,51 @@
}
}
+uint32_t InstBindlessCheckPass::CloneOriginalImage(
+ uint32_t old_image_id, InstructionBuilder* builder) {
+ Instruction* new_image_inst;
+ Instruction* old_image_inst = get_def_use_mgr()->GetDef(old_image_id);
+ if (old_image_inst->opcode() == SpvOpLoad) {
+ new_image_inst = builder->AddLoad(
+ old_image_inst->type_id(),
+ old_image_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
+ } else if (old_image_inst->opcode() == SpvOp::SpvOpSampledImage) {
+ uint32_t clone_id = CloneOriginalImage(
+ old_image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx),
+ builder);
+ new_image_inst = builder->AddBinaryOp(
+ old_image_inst->type_id(), SpvOpSampledImage, clone_id,
+ old_image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
+ } else if (old_image_inst->opcode() == SpvOp::SpvOpImage) {
+ uint32_t clone_id = CloneOriginalImage(
+ old_image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx),
+ builder);
+ new_image_inst =
+ builder->AddUnaryOp(old_image_inst->type_id(), SpvOpImage, clone_id);
+ } else {
+ assert(old_image_inst->opcode() == SpvOp::SpvOpCopyObject &&
+ "expecting OpCopyObject");
+ uint32_t clone_id = CloneOriginalImage(
+ old_image_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx),
+ builder);
+ // Since we are cloning, no need to create new copy
+ new_image_inst = get_def_use_mgr()->GetDef(clone_id);
+ }
+ uid2offset_[new_image_inst->unique_id()] =
+ uid2offset_[old_image_inst->unique_id()];
+ uint32_t new_image_id = new_image_inst->result_id();
+ get_decoration_mgr()->CloneDecorations(old_image_id, new_image_id);
+ return new_image_id;
+}
+
uint32_t InstBindlessCheckPass::CloneOriginalReference(
- ref_analysis* ref, InstructionBuilder* builder) {
+ RefAnalysis* ref, InstructionBuilder* builder) {
// If original is image based, start by cloning descriptor load
uint32_t new_image_id = 0;
if (ref->desc_load_id != 0) {
- Instruction* desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
- Instruction* new_load_inst = builder->AddLoad(
- desc_load_inst->type_id(),
- desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
- uid2offset_[new_load_inst->unique_id()] =
- uid2offset_[desc_load_inst->unique_id()];
- uint32_t new_load_id = new_load_inst->result_id();
- get_decoration_mgr()->CloneDecorations(desc_load_inst->result_id(),
- new_load_id);
- new_image_id = new_load_id;
- // Clone Image/SampledImage with new load, if needed
- if (ref->image_id != 0) {
- Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
- if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
- Instruction* new_image_inst = builder->AddBinaryOp(
- image_inst->type_id(), SpvOpSampledImage, new_load_id,
- image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
- uid2offset_[new_image_inst->unique_id()] =
- uid2offset_[image_inst->unique_id()];
- new_image_id = new_image_inst->result_id();
- } else {
- assert(image_inst->opcode() == SpvOp::SpvOpImage &&
- "expecting OpImage");
- Instruction* new_image_inst =
- builder->AddUnaryOp(image_inst->type_id(), SpvOpImage, new_load_id);
- uid2offset_[new_image_inst->unique_id()] =
- uid2offset_[image_inst->unique_id()];
- new_image_id = new_image_inst->result_id();
- }
- get_decoration_mgr()->CloneDecorations(ref->image_id, new_image_id);
- }
+ uint32_t old_image_id =
+ ref->ref_inst->GetSingleWordInOperand(kSpvImageSampleImageIdInIdx);
+ new_image_id = CloneOriginalImage(old_image_id, builder);
}
// Clone original reference
std::unique_ptr<Instruction> new_ref_inst(ref->ref_inst->Clone(context()));
@@ -179,7 +192,7 @@
}
bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
- ref_analysis* ref) {
+ RefAnalysis* ref) {
ref->ref_inst = ref_inst;
if (ref_inst->opcode() == SpvOpLoad || ref_inst->opcode() == SpvOpStore) {
ref->desc_load_id = 0;
@@ -220,25 +233,28 @@
// Reference is not load or store. If not an image-based reference, return.
ref->image_id = GetImageId(ref_inst);
if (ref->image_id == 0) return false;
- Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
- Instruction* desc_load_inst = nullptr;
- if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
- ref->desc_load_id =
- image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
- desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
- } else if (image_inst->opcode() == SpvOp::SpvOpImage) {
- ref->desc_load_id =
- image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
- desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
- } else {
- ref->desc_load_id = ref->image_id;
- desc_load_inst = image_inst;
- ref->image_id = 0;
+ // Search for descriptor load
+ uint32_t desc_load_id = ref->image_id;
+ Instruction* desc_load_inst;
+ for (;;) {
+ desc_load_inst = get_def_use_mgr()->GetDef(desc_load_id);
+ if (desc_load_inst->opcode() == SpvOp::SpvOpSampledImage)
+ desc_load_id =
+ desc_load_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
+ else if (desc_load_inst->opcode() == SpvOp::SpvOpImage)
+ desc_load_id =
+ desc_load_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
+ else if (desc_load_inst->opcode() == SpvOp::SpvOpCopyObject)
+ desc_load_id =
+ desc_load_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx);
+ else
+ break;
}
if (desc_load_inst->opcode() != SpvOp::SpvOpLoad) {
// TODO(greg-lunarg): Handle additional possibilities?
return false;
}
+ ref->desc_load_id = desc_load_id;
ref->ptr_id = desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx);
Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id);
if (ptr_inst->opcode() == SpvOp::SpvOpVariable) {
@@ -322,7 +338,7 @@
return size;
}
-uint32_t InstBindlessCheckPass::GenLastByteIdx(ref_analysis* ref,
+uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
InstructionBuilder* builder) {
// Find outermost buffer type and its access chain index
Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id);
@@ -474,7 +490,7 @@
void InstBindlessCheckPass::GenCheckCode(
uint32_t check_id, uint32_t error_id, uint32_t offset_id,
- uint32_t length_id, uint32_t stage_idx, ref_analysis* ref,
+ uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
BasicBlock* back_blk_ptr = &*new_blocks->back();
InstructionBuilder builder(
@@ -508,7 +524,7 @@
GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx,
{error_id, u_index_id, u_offset_id, u_length_id},
&builder);
- } else if (buffer_bounds_enabled_) {
+ } 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
uint32_t u_length_id = GenUintCastCode(length_id, &builder);
@@ -551,7 +567,7 @@
std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
// Look for reference through indexed descriptor. If found, analyze and
// save components. If not, return.
- ref_analysis ref;
+ RefAnalysis ref;
if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id);
if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return;
@@ -610,7 +626,7 @@
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.
- ref_analysis ref;
+ RefAnalysis ref;
if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
// Determine if we can only do initialization check
bool init_check = false;
@@ -661,12 +677,77 @@
MovePostludeCode(ref_block_itr, back_blk_ptr);
}
+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;
+ SpvOp op = ref_inst->opcode();
+ uint32_t num_in_oprnds = ref_inst->NumInOperands();
+ if (!((op == SpvOpImageRead && num_in_oprnds == 2) ||
+ (op == SpvOpImageFetch && num_in_oprnds == 2) ||
+ (op == SpvOpImageWrite && 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 (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim) != SpvDimBuffer)
+ 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
+ if (!get_feature_mgr()->HasCapability(SpvCapabilityImageQuery)) {
+ std::unique_ptr<Instruction> cap_image_query_inst(new Instruction(
+ context(), SpvOpCapability, 0, 0,
+ std::initializer_list<Operand>{
+ {SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityImageQuery}}}));
+ get_def_use_mgr()->AnalyzeInstDefUse(&*cap_image_query_inst);
+ context()->AddCapability(std::move(cap_image_query_inst));
+ }
+ // 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(), SpvOpImageQuerySize, 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
+ // for the referenced value.
+ Instruction* ult_inst =
+ builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, coord_id, size_id);
+ uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBuffOOB);
+ GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_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::InitializeInstBindlessCheck() {
// Initialize base class
InitializeInstrument();
- // If runtime array length support enabled, create variable mappings. Length
- // support is always enabled if descriptor init check is enabled.
- if (desc_idx_enabled_ || buffer_bounds_enabled_)
+ // 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() == SpvOpDecorate) {
if (anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet)
@@ -689,8 +770,8 @@
};
bool modified = InstProcessEntryPointCallTree(pfn);
if (desc_init_enabled_ || buffer_bounds_enabled_) {
- // Perform descriptor initialization check on each entry point function in
- // module
+ // 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,
@@ -700,6 +781,18 @@
};
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;
}
diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h
index 29da6f3..a7dff75 100644
--- a/source/opt/inst_bindless_check_pass.h
+++ b/source/opt/inst_bindless_check_pass.h
@@ -28,24 +28,16 @@
// external design may change as the layer evolves.
class InstBindlessCheckPass : public InstrumentPass {
public:
- // Old interface to support testing pre-buffer-overrun capability
- InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
- bool desc_idx_enable, bool desc_init_enable)
- : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, false),
- desc_idx_enabled_(desc_idx_enable),
- desc_init_enabled_(desc_init_enable),
- buffer_bounds_enabled_(false) {}
-
- // New interface supporting buffer overrun checking
InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
bool desc_idx_enable, bool desc_init_enable,
- bool buffer_bounds_enable)
- : InstrumentPass(
- desc_set, shader_id, kInstValidationIdBindless,
- desc_idx_enable || desc_init_enable || buffer_bounds_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) {}
+ buffer_bounds_enabled_(buffer_bounds_enable),
+ texel_buffer_enabled_(texel_buffer_enable) {}
~InstBindlessCheckPass() override = default;
@@ -63,6 +55,10 @@
// 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
@@ -109,6 +105,11 @@
UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
+ void GenTexBuffCheckCode(
+ BasicBlock::iterator ref_inst_itr,
+ UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
+ std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
+
// 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);
@@ -122,7 +123,7 @@
// Analysis data for descriptor reference components, generated by
// AnalyzeDescriptorReference. It is necessary and sufficient for further
// analysis and regeneration of the reference.
- typedef struct ref_analysis {
+ typedef struct RefAnalysis {
uint32_t desc_load_id;
uint32_t image_id;
uint32_t load_id;
@@ -130,7 +131,7 @@
uint32_t var_id;
uint32_t desc_idx_id;
Instruction* ref_inst;
- } ref_analysis;
+ } RefAnalysis;
// Return size of type |ty_id| in bytes. Use |matrix_stride| and |col_major|
// for matrix type, or for vector type if vector is |in_matrix|.
@@ -142,11 +143,15 @@
uint32_t FindStride(uint32_t ty_id, uint32_t stride_deco);
// Generate index of last byte referenced by buffer reference |ref|
- uint32_t GenLastByteIdx(ref_analysis* ref, InstructionBuilder* builder);
+ uint32_t GenLastByteIdx(RefAnalysis* ref, InstructionBuilder* builder);
+
+ // Clone original image computation starting at |image_id| into |builder|.
+ // This may generate more than one instruction if neccessary.
+ uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder);
// Clone original original reference encapsulated by |ref| into |builder|.
// This may generate more than one instruction if neccessary.
- uint32_t CloneOriginalReference(ref_analysis* ref,
+ uint32_t CloneOriginalReference(RefAnalysis* ref,
InstructionBuilder* builder);
// If |inst| references through an image, return the id of the image it
@@ -158,7 +163,7 @@
// Analyze descriptor reference |ref_inst| and save components into |ref|.
// Return true if |ref_inst| is a descriptor reference, false otherwise.
- bool AnalyzeDescriptorReference(Instruction* ref_inst, ref_analysis* ref);
+ bool AnalyzeDescriptorReference(Instruction* ref_inst, RefAnalysis* ref);
// Generate instrumentation code for generic test result |check_id|, starting
// with |builder| of block |new_blk_ptr|, adding new blocks to |new_blocks|.
@@ -168,7 +173,7 @@
// |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, ref_analysis* ref,
+ uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
// Initialize state for instrumenting bindless checking
@@ -184,9 +189,12 @@
// Enable instrumentation of descriptor initialization checking
bool desc_init_enabled_;
- // Enable instrumentation of buffer overrun checking
+ // 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_;
diff --git a/source/opt/instruction.h b/source/opt/instruction.h
index 252e8cb..4743221 100644
--- a/source/opt/instruction.h
+++ b/source/opt/instruction.h
@@ -97,10 +97,14 @@
assert(type == SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER);
assert(1 <= words.size());
assert(words.size() <= 2);
- // Load the low word.
- uint64_t result = uint64_t(words[0]);
+ uint64_t result = 0;
+ if (words.size() > 0) { // Needed to avoid maybe-uninitialized GCC warning
+ uint32_t low = words[0];
+ result = uint64_t(low);
+ }
if (words.size() > 1) {
- result = result | (uint64_t(words[1]) << 32);
+ uint32_t high = words[1];
+ result = result | (uint64_t(high) << 32);
}
return result;
}
diff --git a/source/opt/ir_loader.cpp b/source/opt/ir_loader.cpp
index 4a44309..e443ebb 100644
--- a/source/opt/ir_loader.cpp
+++ b/source/opt/ir_loader.cpp
@@ -41,6 +41,7 @@
++inst_index_;
const auto opcode = static_cast<SpvOp>(inst->opcode);
if (IsDebugLineInst(opcode)) {
+ module()->SetContainsDebugInfo();
last_line_inst_.reset();
dbg_line_info_.push_back(
Instruction(module()->context(), *inst, last_dbg_scope_));
@@ -61,12 +62,12 @@
inlined_at = inst->words[kInlinedAtIndex];
last_dbg_scope_ =
DebugScope(inst->words[kLexicalScopeIndex], inlined_at);
- module()->SetContainsDebugScope();
+ module()->SetContainsDebugInfo();
return true;
}
if (ext_inst_key == OpenCLDebugInfo100DebugNoScope) {
last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
- module()->SetContainsDebugScope();
+ module()->SetContainsDebugInfo();
return true;
}
} else {
@@ -78,12 +79,12 @@
inlined_at = inst->words[kInlinedAtIndex];
last_dbg_scope_ =
DebugScope(inst->words[kLexicalScopeIndex], inlined_at);
- module()->SetContainsDebugScope();
+ module()->SetContainsDebugInfo();
return true;
}
if (ext_inst_key == DebugInfoDebugNoScope) {
last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
- module()->SetContainsDebugScope();
+ module()->SetContainsDebugInfo();
return true;
}
}
@@ -92,7 +93,8 @@
std::unique_ptr<Instruction> spv_inst(
new Instruction(module()->context(), *inst, std::move(dbg_line_info_)));
if (!spv_inst->dbg_line_insts().empty()) {
- if (spv_inst->dbg_line_insts().back().opcode() != SpvOpNoLine) {
+ if (extra_line_tracking_ &&
+ (spv_inst->dbg_line_insts().back().opcode() != SpvOpNoLine)) {
last_line_inst_ = std::unique_ptr<Instruction>(
spv_inst->dbg_line_insts().back().Clone(module()->context()));
}
@@ -136,7 +138,7 @@
return false;
}
block_ = MakeUnique<BasicBlock>(std::move(spv_inst));
- } else if (IsTerminatorInst(opcode)) {
+ } else if (spvOpcodeIsBlockTerminator(opcode)) {
if (function_ == nullptr) {
Error(consumer_, src, loc, "terminator instruction outside function");
return false;
diff --git a/source/opt/ir_loader.h b/source/opt/ir_loader.h
index d0610f1..16bc2c7 100644
--- a/source/opt/ir_loader.h
+++ b/source/opt/ir_loader.h
@@ -63,6 +63,10 @@
// or a missing OpFunctionEnd. Resolves internal bookkeeping.
void EndModule();
+ // Sets whether extra OpLine instructions should be injected to better
+ // track line information.
+ void SetExtraLineTracking(bool flag) { extra_line_tracking_ = flag; }
+
private:
// Consumer for communicating messages to outside.
const MessageConsumer& consumer_;
@@ -78,11 +82,17 @@
std::unique_ptr<BasicBlock> block_;
// Line related debug instructions accumulated thus far.
std::vector<Instruction> dbg_line_info_;
- // Line instruction that should be applied to the next instruction.
+ // If doing extra line tracking, this is the line instruction that should be
+ // applied to the next instruction. Otherwise it always contains null.
std::unique_ptr<Instruction> last_line_inst_;
// The last DebugScope information that IrLoader::AddInstruction() handled.
DebugScope last_dbg_scope_;
+
+ // When true, do extra line information tracking: Additional OpLine
+ // instructions will be injected to help track line info more robustly during
+ // transformations.
+ bool extra_line_tracking_ = true;
};
} // namespace opt
diff --git a/source/opt/legalize_vector_shuffle_pass.cpp b/source/opt/legalize_vector_shuffle_pass.cpp
deleted file mode 100644
index b5d5d59..0000000
--- a/source/opt/legalize_vector_shuffle_pass.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "source/opt/legalize_vector_shuffle_pass.h"
-
-#include "source/opt/ir_context.h"
-
-namespace spvtools {
-namespace opt {
-
-Pass::Status LegalizeVectorShufflePass::Process() {
- bool changed = false;
- context()->module()->ForEachInst([&changed](Instruction* inst) {
- if (inst->opcode() != SpvOpVectorShuffle) return;
-
- for (uint32_t idx = 2; idx < inst->NumInOperands(); ++idx) {
- auto literal = inst->GetSingleWordInOperand(idx);
- if (literal != 0xFFFFFFFF) continue;
- changed = true;
- inst->SetInOperand(idx, {0});
- }
- });
-
- return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange;
-}
-
-} // namespace opt
-} // namespace spvtools
diff --git a/source/opt/legalize_vector_shuffle_pass.h b/source/opt/legalize_vector_shuffle_pass.h
deleted file mode 100644
index ca6e1df..0000000
--- a/source/opt/legalize_vector_shuffle_pass.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SOURCE_OPT_LEGALIZE_VECTOR_SHUFFLE_PASS_H_
-#define SOURCE_OPT_LEGALIZE_VECTOR_SHUFFLE_PASS_H_
-
-#include "source/opt/ir_context.h"
-#include "source/opt/module.h"
-#include "source/opt/pass.h"
-
-namespace spvtools {
-namespace opt {
-
-// Converts any usages of 0xFFFFFFFF for the literals in OpVectorShuffle to a
-// literal 0. This is needed because using OxFFFFFFFF is forbidden by the WebGPU
-// spec. 0xFFFFFFFF in the main spec indicates that the result for this
-// component has no source, thus is undefined. Since this is undefined
-// behaviour we are free to use 0.
-class LegalizeVectorShufflePass : public Pass {
- public:
- const char* name() const override { return "legalize-vector-shuffle"; }
- Status Process() override;
-
- IRContext::Analysis GetPreservedAnalyses() override {
- return IRContext::kAnalysisInstrToBlockMapping |
- IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
- IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis |
- IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
- IRContext::kAnalysisScalarEvolution |
- IRContext::kAnalysisRegisterPressure |
- IRContext::kAnalysisValueNumberTable |
- IRContext::kAnalysisStructuredCFG |
- IRContext::kAnalysisBuiltinVarId |
- IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes |
- IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants;
- }
-};
-
-} // namespace opt
-} // namespace spvtools
-
-#endif // SOURCE_OPT_LEGALIZE_VECTOR_SHUFFLE_PASS_H_
diff --git a/source/opt/module.cpp b/source/opt/module.cpp
index 9d3b0ed..0c88601 100644
--- a/source/opt/module.cpp
+++ b/source/opt/module.cpp
@@ -188,7 +188,7 @@
i->ToBinaryWithoutAttachedDebugInsts(binary);
}
// Update the last line instruction.
- if (IsTerminatorInst(opcode) || opcode == SpvOpNoLine) {
+ if (spvOpcodeIsBlockTerminator(opcode) || opcode == SpvOpNoLine) {
last_line_inst = nullptr;
} else if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge) {
between_merge_and_branch = true;
diff --git a/source/opt/module.h b/source/opt/module.h
index 75da870..d609b60 100644
--- a/source/opt/module.h
+++ b/source/opt/module.h
@@ -49,7 +49,7 @@
using const_inst_iterator = InstructionList::const_iterator;
// Creates an empty module with zero'd header.
- Module() : header_({}), contains_debug_scope_(false) {}
+ Module() : header_({}), contains_debug_info_(false) {}
// Sets the header to the given |header|.
void SetHeader(const ModuleHeader& header) { header_ = header; }
@@ -119,9 +119,9 @@
// Appends a function to this module.
inline void AddFunction(std::unique_ptr<Function> f);
- // Sets |contains_debug_scope_| as true.
- inline void SetContainsDebugScope();
- inline bool ContainsDebugScope() { return contains_debug_scope_; }
+ // Sets |contains_debug_info_| as true.
+ inline void SetContainsDebugInfo();
+ inline bool ContainsDebugInfo() { return contains_debug_info_; }
// Returns a vector of pointers to type-declaration instructions in this
// module.
@@ -246,12 +246,6 @@
// If |skip_nop| is true and this is a OpNop, do nothing.
void ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const;
- // Pushes the binary segments for this instruction into the back of *|binary|
- // including all OpLine and OpNoLine even if we can skip emitting some line
- // instructions. If |skip_nop| is true and this is a OpNop, do nothing.
- void ToBinaryWithAllOpLines(std::vector<uint32_t>* binary,
- bool skip_nop) const;
-
// Returns 1 more than the maximum Id value mentioned in the module.
uint32_t ComputeIdBound() const;
@@ -307,8 +301,8 @@
// any instruction. We record them here, so they will not be lost.
std::vector<Instruction> trailing_dbg_line_info_;
- // This module contains DebugScope or DebugNoScope.
- bool contains_debug_scope_;
+ // This module contains DebugScope/DebugNoScope or OpLine/OpNoLine.
+ bool contains_debug_info_;
};
// Pretty-prints |module| to |str|. Returns |str|.
@@ -370,7 +364,7 @@
functions_.emplace_back(std::move(f));
}
-inline void Module::SetContainsDebugScope() { contains_debug_scope_ = true; }
+inline void Module::SetContainsDebugInfo() { contains_debug_info_ = true; }
inline Module::inst_iterator Module::capability_begin() {
return capabilities_.begin();
diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp
index 1ded2ee..909442c 100644
--- a/source/opt/optimizer.cpp
+++ b/source/opt/optimizer.cpp
@@ -62,7 +62,9 @@
opt::PassManager pass_manager; // Internal implementation pass manager.
};
-Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {}
+Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {
+ assert(env != SPV_ENV_WEBGPU_0);
+}
Optimizer::~Optimizer() {}
@@ -239,23 +241,6 @@
.RegisterPass(CreateCFGCleanupPass());
}
-Optimizer& Optimizer::RegisterVulkanToWebGPUPasses() {
- return RegisterPass(CreateStripAtomicCounterMemoryPass())
- .RegisterPass(CreateGenerateWebGPUInitializersPass())
- .RegisterPass(CreateLegalizeVectorShufflePass())
- .RegisterPass(CreateSplitInvalidUnreachablePass())
- .RegisterPass(CreateEliminateDeadConstantPass())
- .RegisterPass(CreateFlattenDecorationPass())
- .RegisterPass(CreateAggressiveDCEPass())
- .RegisterPass(CreateDeadBranchElimPass())
- .RegisterPass(CreateCompactIdsPass());
-}
-
-Optimizer& Optimizer::RegisterWebGPUToVulkanPasses() {
- return RegisterPass(CreateDecomposeInitializedVariablesPass())
- .RegisterPass(CreateCompactIdsPass());
-}
-
bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags) {
for (const auto& flag : flags) {
if (!RegisterPassFromFlag(flag)) {
@@ -298,9 +283,7 @@
//
// Both Pass::name() and Pass::desc() should be static class members so they
// can be invoked without creating a pass instance.
- if (pass_name == "strip-atomic-counter-memory") {
- RegisterPass(CreateStripAtomicCounterMemoryPass());
- } else if (pass_name == "strip-debug") {
+ if (pass_name == "strip-debug") {
RegisterPass(CreateStripDebugInfoPass());
} else if (pass_name == "strip-reflect") {
RegisterPass(CreateStripReflectInfoPass());
@@ -425,7 +408,7 @@
RegisterPass(CreateBlockMergePass());
RegisterPass(CreateAggressiveDCEPass());
} else if (pass_name == "inst-buff-oob-check") {
- RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true));
+ RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true));
RegisterPass(CreateSimplificationPass());
RegisterPass(CreateDeadBranchElimPass());
RegisterPass(CreateBlockMergePass());
@@ -505,14 +488,6 @@
RegisterSizePasses();
} else if (pass_name == "legalize-hlsl") {
RegisterLegalizationPasses();
- } else if (pass_name == "generate-webgpu-initializers") {
- RegisterPass(CreateGenerateWebGPUInitializersPass());
- } else if (pass_name == "legalize-vector-shuffle") {
- RegisterPass(CreateLegalizeVectorShufflePass());
- } else if (pass_name == "split-invalid-unreachable") {
- RegisterPass(CreateSplitInvalidUnreachablePass());
- } else if (pass_name == "decompose-initialized-variables") {
- RegisterPass(CreateDecomposeInitializedVariablesPass());
} else if (pass_name == "graphics-robust-access") {
RegisterPass(CreateGraphicsRobustAccessPass());
} else if (pass_name == "wrap-opkill") {
@@ -583,10 +558,12 @@
#ifndef NDEBUG
// We do not keep the result id of DebugScope in struct DebugScope.
// Instead, we assign random ids for them, which results in integrity
+ // check failures. In addition, propagating the OpLine/OpNoLine to preserve
+ // the debug information through transformations results in integrity
// check failures. We want to skip the integrity check when the module
- // contains DebugScope instructions.
+ // contains DebugScope or OpLine/OpNoLine instructions.
if (status == opt::Pass::Status::SuccessWithoutChange &&
- !context->module()->ContainsDebugScope()) {
+ !context->module()->ContainsDebugInfo()) {
std::vector<uint32_t> optimized_binary_with_nop;
context->module()->ToBinary(&optimized_binary_with_nop,
/* skip_nop = */ false);
@@ -627,11 +604,6 @@
return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
}
-Optimizer::PassToken CreateStripAtomicCounterMemoryPass() {
- return MakeUnique<Optimizer::PassToken::Impl>(
- MakeUnique<opt::StripAtomicCounterMemoryPass>());
-}
-
Optimizer::PassToken CreateStripDebugInfoPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::StripDebugInfoPass>());
@@ -892,15 +864,14 @@
MakeUnique<opt::UpgradeMemoryModel>());
}
-Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set,
- uint32_t shader_id,
- bool input_length_enable,
- bool input_init_enable,
- bool input_buff_oob_enable) {
+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) {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::InstBindlessCheckPass>(
- desc_set, shader_id, input_length_enable, input_init_enable,
- input_buff_oob_enable));
+ 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));
}
Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
@@ -930,31 +901,11 @@
MakeUnique<opt::CodeSinkingPass>());
}
-Optimizer::PassToken CreateGenerateWebGPUInitializersPass() {
- return MakeUnique<Optimizer::PassToken::Impl>(
- MakeUnique<opt::GenerateWebGPUInitializersPass>());
-}
-
Optimizer::PassToken CreateFixStorageClassPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::FixStorageClass>());
}
-Optimizer::PassToken CreateLegalizeVectorShufflePass() {
- return MakeUnique<Optimizer::PassToken::Impl>(
- MakeUnique<opt::LegalizeVectorShufflePass>());
-}
-
-Optimizer::PassToken CreateDecomposeInitializedVariablesPass() {
- return MakeUnique<Optimizer::PassToken::Impl>(
- MakeUnique<opt::DecomposeInitializedVariablesPass>());
-}
-
-Optimizer::PassToken CreateSplitInvalidUnreachablePass() {
- return MakeUnique<Optimizer::PassToken::Impl>(
- MakeUnique<opt::SplitInvalidUnreachablePass>());
-}
-
Optimizer::PassToken CreateGraphicsRobustAccessPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::GraphicsRobustAccessPass>());
diff --git a/source/opt/passes.h b/source/opt/passes.h
index d47cc1c..1bc94c7 100644
--- a/source/opt/passes.h
+++ b/source/opt/passes.h
@@ -30,7 +30,6 @@
#include "source/opt/dead_branch_elim_pass.h"
#include "source/opt/dead_insert_elim_pass.h"
#include "source/opt/dead_variable_elimination.h"
-#include "source/opt/decompose_initialized_variables_pass.h"
#include "source/opt/desc_sroa.h"
#include "source/opt/eliminate_dead_constant_pass.h"
#include "source/opt/eliminate_dead_functions_pass.h"
@@ -40,7 +39,6 @@
#include "source/opt/flatten_decoration_pass.h"
#include "source/opt/fold_spec_constant_op_and_composite_pass.h"
#include "source/opt/freeze_spec_constant_value_pass.h"
-#include "source/opt/generate_webgpu_initializers_pass.h"
#include "source/opt/graphics_robust_access_pass.h"
#include "source/opt/if_conversion.h"
#include "source/opt/inline_exhaustive_pass.h"
@@ -48,7 +46,6 @@
#include "source/opt/inst_bindless_check_pass.h"
#include "source/opt/inst_buff_addr_check_pass.h"
#include "source/opt/inst_debug_printf_pass.h"
-#include "source/opt/legalize_vector_shuffle_pass.h"
#include "source/opt/licm_pass.h"
#include "source/opt/local_access_chain_convert_pass.h"
#include "source/opt/local_redundancy_elimination.h"
@@ -70,10 +67,8 @@
#include "source/opt/scalar_replacement_pass.h"
#include "source/opt/set_spec_constant_default_value_pass.h"
#include "source/opt/simplification_pass.h"
-#include "source/opt/split_invalid_unreachable_pass.h"
#include "source/opt/ssa_rewrite_pass.h"
#include "source/opt/strength_reduction_pass.h"
-#include "source/opt/strip_atomic_counter_memory_pass.h"
#include "source/opt/strip_debug_info_pass.h"
#include "source/opt/strip_reflect_info_pass.h"
#include "source/opt/unify_const_pass.h"
diff --git a/source/opt/reflect.h b/source/opt/reflect.h
index d374e68..c7d46df 100644
--- a/source/opt/reflect.h
+++ b/source/opt/reflect.h
@@ -59,10 +59,6 @@
inline bool IsSpecConstantInst(SpvOp opcode) {
return opcode >= SpvOpSpecConstantTrue && opcode <= SpvOpSpecConstantOp;
}
-inline bool IsTerminatorInst(SpvOp opcode) {
- return (opcode >= SpvOpBranch && opcode <= SpvOpUnreachable) ||
- (opcode == SpvOpTerminateInvocation);
-}
} // namespace opt
} // namespace spvtools
diff --git a/source/opt/split_invalid_unreachable_pass.cpp b/source/opt/split_invalid_unreachable_pass.cpp
deleted file mode 100644
index 31cfbc3..0000000
--- a/source/opt/split_invalid_unreachable_pass.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "source/opt/split_invalid_unreachable_pass.h"
-
-#include "source/opt/ir_builder.h"
-#include "source/opt/ir_context.h"
-
-namespace spvtools {
-namespace opt {
-
-Pass::Status SplitInvalidUnreachablePass::Process() {
- bool changed = false;
- std::unordered_set<uint32_t> entry_points;
- for (auto entry_point : context()->module()->entry_points()) {
- entry_points.insert(entry_point.GetSingleWordOperand(1));
- }
-
- for (auto func = context()->module()->begin();
- func != context()->module()->end(); ++func) {
- if (entry_points.find(func->result_id()) == entry_points.end()) continue;
- std::unordered_set<uint32_t> continue_targets;
- std::unordered_set<uint32_t> merge_blocks;
- std::unordered_set<BasicBlock*> unreachable_blocks;
- for (auto block = func->begin(); block != func->end(); ++block) {
- unreachable_blocks.insert(&*block);
- uint32_t continue_target = block->ContinueBlockIdIfAny();
- if (continue_target != 0) continue_targets.insert(continue_target);
- uint32_t merge_block = block->MergeBlockIdIfAny();
- if (merge_block != 0) merge_blocks.insert(merge_block);
- }
-
- cfg()->ForEachBlockInPostOrder(
- func->entry().get(), [&unreachable_blocks](BasicBlock* inner_block) {
- unreachable_blocks.erase(inner_block);
- });
-
- for (auto unreachable : unreachable_blocks) {
- uint32_t block_id = unreachable->id();
- if (continue_targets.find(block_id) == continue_targets.end() ||
- merge_blocks.find(block_id) == merge_blocks.end()) {
- continue;
- }
-
- std::vector<std::tuple<Instruction*, uint32_t>> usages;
- context()->get_def_use_mgr()->ForEachUse(
- unreachable->GetLabelInst(),
- [&usages](Instruction* use, uint32_t idx) {
- if ((use->opcode() == SpvOpLoopMerge && idx == 0) ||
- use->opcode() == SpvOpSelectionMerge) {
- usages.push_back(std::make_pair(use, idx));
- }
- });
-
- for (auto usage : usages) {
- Instruction* use;
- uint32_t idx;
- std::tie(use, idx) = usage;
- uint32_t new_id = context()->TakeNextId();
- std::unique_ptr<Instruction> new_label(
- new Instruction(context(), SpvOpLabel, 0, new_id, {}));
- get_def_use_mgr()->AnalyzeInstDefUse(new_label.get());
- std::unique_ptr<BasicBlock> new_block(
- new BasicBlock(std::move(new_label)));
- auto* block_ptr = new_block.get();
- InstructionBuilder builder(context(), new_block.get(),
- IRContext::kAnalysisDefUse |
- IRContext::kAnalysisInstrToBlockMapping);
- builder.AddUnreachable();
- cfg()->RegisterBlock(block_ptr);
- (&*func)->InsertBasicBlockBefore(std::move(new_block), unreachable);
- use->SetInOperand(0, {new_id});
- get_def_use_mgr()->UpdateDefUse(use);
- cfg()->AddEdges(block_ptr);
- changed = true;
- }
- }
- }
-
- return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange;
-}
-
-} // namespace opt
-} // namespace spvtools
diff --git a/source/opt/split_invalid_unreachable_pass.h b/source/opt/split_invalid_unreachable_pass.h
deleted file mode 100644
index a561344..0000000
--- a/source/opt/split_invalid_unreachable_pass.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SOURCE_OPT_SPLIT_INVALID_UNREACHABLE_PASS_H_
-#define SOURCE_OPT_SPLIT_INVALID_UNREACHABLE_PASS_H_
-
-#include "source/opt/ir_context.h"
-#include "source/opt/module.h"
-#include "source/opt/pass.h"
-
-namespace spvtools {
-namespace opt {
-
-// Attempts to legalize for WebGPU by splitting up invalid unreachable blocks.
-// Specifically, looking for cases of unreachable merge-blocks and
-// continue-targets that are used more then once, which is illegal in WebGPU.
-class SplitInvalidUnreachablePass : public Pass {
- public:
- const char* name() const override { return "split-invalid-unreachable"; }
- Status Process() override;
-
- IRContext::Analysis GetPreservedAnalyses() override {
- return IRContext::kAnalysisInstrToBlockMapping |
- IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
- IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis |
- IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
- IRContext::kAnalysisScalarEvolution |
- IRContext::kAnalysisRegisterPressure |
- IRContext::kAnalysisValueNumberTable |
- IRContext::kAnalysisStructuredCFG |
- IRContext::kAnalysisBuiltinVarId |
- IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes |
- IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants;
- }
-};
-
-} // namespace opt
-} // namespace spvtools
-
-#endif // SOURCE_OPT_SPLIT_INVALID_UNREACHABLE_PASS_H_
diff --git a/source/opt/strip_atomic_counter_memory_pass.cpp b/source/opt/strip_atomic_counter_memory_pass.cpp
deleted file mode 100644
index 47714b7..0000000
--- a/source/opt/strip_atomic_counter_memory_pass.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "source/opt/strip_atomic_counter_memory_pass.h"
-#include "source/opt/ir_context.h"
-
-namespace spvtools {
-namespace opt {
-
-Pass::Status StripAtomicCounterMemoryPass::Process() {
- bool changed = false;
- context()->module()->ForEachInst([this, &changed](Instruction* inst) {
- auto indices = spvOpcodeMemorySemanticsOperandIndices(inst->opcode());
- if (indices.empty()) return;
-
- for (auto idx : indices) {
- auto mem_sem_id = inst->GetSingleWordOperand(idx);
- const auto& mem_sem_inst =
- context()->get_def_use_mgr()->GetDef(mem_sem_id);
- // The spec explicitly says that this id must be an OpConstant
- auto mem_sem_val = mem_sem_inst->GetSingleWordOperand(2);
- if (!(mem_sem_val & SpvMemorySemanticsAtomicCounterMemoryMask)) {
- continue;
- }
- mem_sem_val &= ~SpvMemorySemanticsAtomicCounterMemoryMask;
-
- analysis::Integer int_type(32, false);
- const analysis::Type* uint32_type =
- context()->get_type_mgr()->GetRegisteredType(&int_type);
- auto* new_const = context()->get_constant_mgr()->GetConstant(
- uint32_type, {mem_sem_val});
- auto* new_const_inst =
- context()->get_constant_mgr()->GetDefiningInstruction(new_const);
- auto new_const_id = new_const_inst->result_id();
-
- inst->SetOperand(idx, {new_const_id});
- context()->UpdateDefUse(inst);
- changed = true;
- }
- });
-
- return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange;
-}
-
-} // namespace opt
-} // namespace spvtools
diff --git a/source/opt/strip_atomic_counter_memory_pass.h b/source/opt/strip_atomic_counter_memory_pass.h
deleted file mode 100644
index 62e274a..0000000
--- a/source/opt/strip_atomic_counter_memory_pass.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2019 Google LLC.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_
-#define SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_
-
-#include "source/opt/ir_context.h"
-#include "source/opt/module.h"
-#include "source/opt/pass.h"
-
-namespace spvtools {
-namespace opt {
-
-// Removes the AtomicCounterMemory bit from the value being passed into memory
-// semantics. This bit being set is ignored in Vulkan environments and
-// forbidden WebGPU ones.
-class StripAtomicCounterMemoryPass : public Pass {
- public:
- const char* name() const override { return "strip-atomic-counter-memory"; }
- Status Process() override;
-
- IRContext::Analysis GetPreservedAnalyses() override {
- return IRContext::kAnalysisInstrToBlockMapping |
- IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
- IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis |
- IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
- IRContext::kAnalysisScalarEvolution |
- IRContext::kAnalysisRegisterPressure |
- IRContext::kAnalysisValueNumberTable |
- IRContext::kAnalysisStructuredCFG |
- IRContext::kAnalysisBuiltinVarId |
- IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes |
- IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants;
- }
-};
-
-} // namespace opt
-} // namespace spvtools
-
-#endif // SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_
diff --git a/source/spirv_target_env.cpp b/source/spirv_target_env.cpp
index e2ff99c..f20ebb4 100644
--- a/source/spirv_target_env.cpp
+++ b/source/spirv_target_env.cpp
@@ -14,6 +14,7 @@
#include "source/spirv_target_env.h"
+#include <cassert>
#include <cstring>
#include <string>
@@ -61,7 +62,8 @@
case SPV_ENV_VULKAN_1_1:
return "SPIR-V 1.3 (under Vulkan 1.1 semantics)";
case SPV_ENV_WEBGPU_0:
- return "SPIR-V 1.3 (under WIP WebGPU semantics)";
+ assert(false);
+ break;
case SPV_ENV_UNIVERSAL_1_4:
return "SPIR-V 1.4";
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
@@ -98,8 +100,10 @@
return SPV_SPIRV_VERSION_WORD(1, 2);
case SPV_ENV_UNIVERSAL_1_3:
case SPV_ENV_VULKAN_1_1:
- case SPV_ENV_WEBGPU_0:
return SPV_SPIRV_VERSION_WORD(1, 3);
+ case SPV_ENV_WEBGPU_0:
+ assert(false);
+ break;
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
return SPV_SPIRV_VERSION_WORD(1, 4);
@@ -134,7 +138,6 @@
{"opengl4.2", SPV_ENV_OPENGL_4_2},
{"opengl4.3", SPV_ENV_OPENGL_4_3},
{"opengl4.5", SPV_ENV_OPENGL_4_5},
- {"webgpu0", SPV_ENV_WEBGPU_0},
};
bool spvParseTargetEnv(const char* s, spv_target_env* env) {
@@ -200,7 +203,6 @@
case SPV_ENV_OPENCL_2_2:
case SPV_ENV_OPENCL_EMBEDDED_2_2:
case SPV_ENV_UNIVERSAL_1_3:
- case SPV_ENV_WEBGPU_0:
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_UNIVERSAL_1_5:
return false;
@@ -209,6 +211,9 @@
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_VULKAN_1_2:
return true;
+ case SPV_ENV_WEBGPU_0:
+ assert(false);
+ break;
}
return false;
}
@@ -226,7 +231,6 @@
case SPV_ENV_UNIVERSAL_1_2:
case SPV_ENV_UNIVERSAL_1_3:
case SPV_ENV_VULKAN_1_1:
- case SPV_ENV_WEBGPU_0:
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_UNIVERSAL_1_5:
@@ -241,38 +245,9 @@
case SPV_ENV_OPENCL_2_1:
case SPV_ENV_OPENCL_2_2:
return true;
- }
- return false;
-}
-
-bool spvIsWebGPUEnv(spv_target_env env) {
- switch (env) {
- case SPV_ENV_UNIVERSAL_1_0:
- case SPV_ENV_VULKAN_1_0:
- case SPV_ENV_UNIVERSAL_1_1:
- case SPV_ENV_OPENGL_4_0:
- case SPV_ENV_OPENGL_4_1:
- case SPV_ENV_OPENGL_4_2:
- case SPV_ENV_OPENGL_4_3:
- case SPV_ENV_OPENGL_4_5:
- case SPV_ENV_UNIVERSAL_1_2:
- case SPV_ENV_UNIVERSAL_1_3:
- case SPV_ENV_VULKAN_1_1:
- case SPV_ENV_OPENCL_1_2:
- case SPV_ENV_OPENCL_EMBEDDED_1_2:
- case SPV_ENV_OPENCL_2_0:
- case SPV_ENV_OPENCL_EMBEDDED_2_0:
- case SPV_ENV_OPENCL_EMBEDDED_2_1:
- case SPV_ENV_OPENCL_EMBEDDED_2_2:
- case SPV_ENV_OPENCL_2_1:
- case SPV_ENV_OPENCL_2_2:
- case SPV_ENV_UNIVERSAL_1_4:
- case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
- case SPV_ENV_UNIVERSAL_1_5:
- case SPV_ENV_VULKAN_1_2:
- return false;
case SPV_ENV_WEBGPU_0:
- return true;
+ assert(false);
+ break;
}
return false;
}
@@ -293,7 +268,6 @@
case SPV_ENV_OPENCL_EMBEDDED_2_2:
case SPV_ENV_OPENCL_2_1:
case SPV_ENV_OPENCL_2_2:
- case SPV_ENV_WEBGPU_0:
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_UNIVERSAL_1_5:
@@ -305,14 +279,13 @@
case SPV_ENV_OPENGL_4_3:
case SPV_ENV_OPENGL_4_5:
return true;
+ case SPV_ENV_WEBGPU_0:
+ assert(false);
+ break;
}
return false;
}
-bool spvIsVulkanOrWebGPUEnv(spv_target_env env) {
- return spvIsVulkanEnv(env) || spvIsWebGPUEnv(env);
-}
-
std::string spvLogStringForEnv(spv_target_env env) {
switch (env) {
case SPV_ENV_OPENCL_1_2:
@@ -338,9 +311,6 @@
case SPV_ENV_VULKAN_1_2:
return "Vulkan";
}
- case SPV_ENV_WEBGPU_0: {
- return "WebGPU";
- }
case SPV_ENV_UNIVERSAL_1_0:
case SPV_ENV_UNIVERSAL_1_1:
case SPV_ENV_UNIVERSAL_1_2:
@@ -349,6 +319,9 @@
case SPV_ENV_UNIVERSAL_1_5: {
return "Universal";
}
+ case SPV_ENV_WEBGPU_0:
+ assert(false);
+ break;
}
return "Unknown";
}
diff --git a/source/spirv_target_env.h b/source/spirv_target_env.h
index 1bdedf9..a804d61 100644
--- a/source/spirv_target_env.h
+++ b/source/spirv_target_env.h
@@ -25,20 +25,14 @@
// Returns true if |env| is an OPENCL environment, false otherwise.
bool spvIsOpenCLEnv(spv_target_env env);
-// Returns true if |env| is an WEBGPU environment, false otherwise.
-bool spvIsWebGPUEnv(spv_target_env env);
-
// Returns true if |env| is an OPENGL environment, false otherwise.
bool spvIsOpenGLEnv(spv_target_env env);
-// Returns true if |env| is a VULKAN or WEBGPU environment, false otherwise.
-bool spvIsVulkanOrWebGPUEnv(spv_target_env env);
-
// Returns the version number for the given SPIR-V target environment.
uint32_t spvVersionForTargetEnv(spv_target_env env);
// Returns a string to use in logging messages that indicates the class of
-// environment, i.e. "Vulkan", "WebGPU", "OpenCL", etc.
+// environment, i.e. "Vulkan", "OpenCL", etc.
std::string spvLogStringForEnv(spv_target_env env);
// Returns a formatted list of all SPIR-V target environment names that
diff --git a/source/table.cpp b/source/table.cpp
index 8340e8e..d4a2d7e 100644
--- a/source/table.cpp
+++ b/source/table.cpp
@@ -38,7 +38,6 @@
case SPV_ENV_UNIVERSAL_1_3:
case SPV_ENV_VULKAN_1_1:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
- case SPV_ENV_WEBGPU_0:
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
diff --git a/source/val/validate.cpp b/source/val/validate.cpp
index d6e992b..a2e116b 100644
--- a/source/val/validate.cpp
+++ b/source/val/validate.cpp
@@ -111,57 +111,6 @@
<< id_str.substr(0, id_str.size() - 1);
}
-std::vector<std::string> CalculateNamesForEntryPoint(ValidationState_t& _,
- const uint32_t id) {
- auto id_descriptions = _.entry_point_descriptions(id);
- auto id_names = std::vector<std::string>();
- id_names.reserve((id_descriptions.size()));
-
- for (auto description : id_descriptions) id_names.push_back(description.name);
-
- return id_names;
-}
-
-spv_result_t ValidateEntryPointNameUnique(ValidationState_t& _,
- const uint32_t id) {
- auto id_names = CalculateNamesForEntryPoint(_, id);
- const auto names =
- std::unordered_set<std::string>(id_names.begin(), id_names.end());
-
- if (id_names.size() != names.size()) {
- std::sort(id_names.begin(), id_names.end());
- for (size_t i = 0; i < id_names.size() - 1; i++) {
- if (id_names[i] == id_names[i + 1]) {
- return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id))
- << "Entry point name \"" << id_names[i]
- << "\" is not unique, which is not allow in WebGPU env.";
- }
- }
- }
-
- for (const auto other_id : _.entry_points()) {
- if (other_id == id) continue;
- const auto other_id_names = CalculateNamesForEntryPoint(_, other_id);
- for (const auto& other_id_name : other_id_names) {
- if (names.find(other_id_name) != names.end()) {
- return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id))
- << "Entry point name \"" << other_id_name
- << "\" is not unique, which is not allow in WebGPU env.";
- }
- }
- }
-
- return SPV_SUCCESS;
-}
-
-spv_result_t ValidateEntryPointNamesUnique(ValidationState_t& _) {
- for (const auto id : _.entry_points()) {
- auto result = ValidateEntryPointNameUnique(_, id);
- if (result != SPV_SUCCESS) return result;
- }
- return SPV_SUCCESS;
-}
-
// Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the
// SPIRV spec:
// * There is at least one OpEntryPoint instruction, unless the Linkage
@@ -169,8 +118,7 @@
// * No function can be targeted by both an OpEntryPoint instruction and an
// OpFunctionCall instruction.
//
-// Additionally enforces that entry points for Vulkan and WebGPU should not have
-// recursion. And that entry names should be unique for WebGPU.
+// Additionally enforces that entry points for Vulkan should not have recursion.
spv_result_t ValidateEntryPoints(ValidationState_t& _) {
_.ComputeFunctionToEntryPointMapping();
_.ComputeRecursiveEntryPoints();
@@ -189,21 +137,15 @@
"an OpFunctionCall instruction.";
}
- // For Vulkan and WebGPU, the static function-call graph for an entry point
+ // For Vulkan, the static function-call graph for an entry point
// must not contain cycles.
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
if (_.recursive_entry_points().find(entry_point) !=
_.recursive_entry_points().end()) {
return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(entry_point))
<< "Entry points may not have a call graph with cycles.";
}
}
-
- // For WebGPU all entry point names must be unique.
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- const auto result = ValidateEntryPointNamesUnique(_);
- if (result != SPV_SUCCESS) return result;
- }
}
return SPV_SUCCESS;
@@ -223,12 +165,6 @@
<< "Invalid SPIR-V magic number.";
}
- if (spvIsWebGPUEnv(context.target_env) && endian != SPV_ENDIANNESS_LITTLE) {
- return DiagnosticStream(position, context.consumer, "",
- SPV_ERROR_INVALID_BINARY)
- << "WebGPU requires SPIR-V to be little endian.";
- }
-
spv_header_t header;
if (spvBinaryHeaderGet(binary.get(), endian, &header)) {
return DiagnosticStream(position, context.consumer, "",
@@ -321,13 +257,6 @@
}
const auto called_id = inst->GetOperandAs<uint32_t>(2);
- if (spvIsWebGPUEnv(context.target_env) &&
- !vstate->IsFunctionCallDefined(called_id)) {
- return vstate->diag(SPV_ERROR_INVALID_LAYOUT, &instruction)
- << "For WebGPU, functions need to be defined before being "
- "called.";
- }
-
vstate->AddFunctionCallTarget(called_id);
}
diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp
index df38f1b..85d2b75 100644
--- a/source/val/validate_annotation.cpp
+++ b/source/val/validate_annotation.cpp
@@ -22,36 +22,6 @@
namespace val {
namespace {
-bool IsValidWebGPUDecoration(uint32_t decoration) {
- switch (decoration) {
- case SpvDecorationSpecId:
- case SpvDecorationBlock:
- case SpvDecorationRowMajor:
- case SpvDecorationColMajor:
- case SpvDecorationArrayStride:
- case SpvDecorationMatrixStride:
- case SpvDecorationBuiltIn:
- case SpvDecorationNoPerspective:
- case SpvDecorationFlat:
- case SpvDecorationCentroid:
- case SpvDecorationRestrict:
- case SpvDecorationAliased:
- case SpvDecorationNonWritable:
- case SpvDecorationNonReadable:
- case SpvDecorationUniform:
- case SpvDecorationLocation:
- case SpvDecorationComponent:
- case SpvDecorationIndex:
- case SpvDecorationBinding:
- case SpvDecorationDescriptorSet:
- case SpvDecorationOffset:
- case SpvDecorationNoContraction:
- return true;
- default:
- return false;
- }
-}
-
std::string LogStringForDecoration(uint32_t decoration) {
switch (decoration) {
case SpvDecorationRelaxedPrecision:
@@ -212,11 +182,14 @@
}
}
- if (spvIsWebGPUEnv(_.context()->target_env) &&
- !IsValidWebGPUDecoration(decoration)) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpDecorate decoration '" << LogStringForDecoration(decoration)
- << "' is not valid for the WebGPU execution environment.";
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if ((decoration == SpvDecorationGLSLShared) ||
+ (decoration == SpvDecorationGLSLPacked)) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(4669) << "OpDecorate decoration '"
+ << LogStringForDecoration(decoration)
+ << "' is not valid for the Vulkan execution environment.";
+ }
}
if (DecorationTakesIdParameters(decoration)) {
@@ -261,25 +234,11 @@
<< " members. Largest valid index is " << member_count - 1 << ".";
}
- const auto decoration = inst->GetOperandAs<uint32_t>(2);
- if (spvIsWebGPUEnv(_.context()->target_env) &&
- !IsValidWebGPUDecoration(decoration)) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpMemberDecorate decoration '" << _.getIdName(decoration)
- << "' is not valid for the WebGPU execution environment.";
- }
-
return SPV_SUCCESS;
}
spv_result_t ValidateDecorationGroup(ValidationState_t& _,
const Instruction* inst) {
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- return _.diag(SPV_ERROR_INVALID_BINARY, inst)
- << "OpDecorationGroup is not allowed in the WebGPU execution "
- << "environment.";
- }
-
const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
const auto decoration_group = _.FindDef(decoration_group_id);
for (auto pair : decoration_group->uses()) {
@@ -299,12 +258,6 @@
spv_result_t ValidateGroupDecorate(ValidationState_t& _,
const Instruction* inst) {
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- return _.diag(SPV_ERROR_INVALID_BINARY, inst)
- << "OpGroupDecorate is not allowed in the WebGPU execution "
- << "environment.";
- }
-
const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
auto decoration_group = _.FindDef(decoration_group_id);
if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) {
@@ -327,12 +280,6 @@
spv_result_t ValidateGroupMemberDecorate(ValidationState_t& _,
const Instruction* inst) {
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- return _.diag(SPV_ERROR_INVALID_BINARY, inst)
- << "OpGroupMemberDecorate is not allowed in the WebGPU execution "
- << "environment.";
- }
-
const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
const auto decoration_group = _.FindDef(decoration_group_id);
if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) {
diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp
index 3f1f561..dd263a7 100644
--- a/source/val/validate_atomics.cpp
+++ b/source/val/validate_atomics.cpp
@@ -213,7 +213,19 @@
// Then Shader rules
if (_.HasCapability(SpvCapabilityShader)) {
- if (storage_class == SpvStorageClassFunction) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if ((storage_class != SpvStorageClassUniform) &&
+ (storage_class != SpvStorageClassStorageBuffer) &&
+ (storage_class != SpvStorageClassWorkgroup) &&
+ (storage_class != SpvStorageClassImage) &&
+ (storage_class != SpvStorageClassPhysicalStorageBuffer)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4686) << spvOpcodeString(opcode)
+ << ": Vulkan spec only allows storage classes for atomic to "
+ "be: Uniform, Workgroup, Image, StorageBuffer, or "
+ "PhysicalStorageBuffer.";
+ }
+ } else if (storage_class == SpvStorageClassFunction) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< spvOpcodeString(opcode)
<< ": Function storage class forbidden when the Shader "
diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp
index d9e0666..3c9df9f 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -16,6 +16,7 @@
// Validates correctness of built-in variables.
+#include <array>
#include <functional>
#include <list>
#include <map>
@@ -112,25 +113,128 @@
return SpvStorageClassMax;
}
-bool IsBuiltInValidForWebGPU(SpvBuiltIn label) {
- switch (label) {
- case SpvBuiltInPosition:
- case SpvBuiltInVertexIndex:
- case SpvBuiltInInstanceIndex:
- case SpvBuiltInFrontFacing:
- case SpvBuiltInFragCoord:
- case SpvBuiltInFragDepth:
- case SpvBuiltInNumWorkgroups:
- case SpvBuiltInWorkgroupSize:
- case SpvBuiltInLocalInvocationId:
- case SpvBuiltInGlobalInvocationId:
- case SpvBuiltInLocalInvocationIndex: {
- return true;
+typedef enum VUIDError_ {
+ VUIDErrorExecutionModel = 0,
+ VUIDErrorStorageClass = 1,
+ VUIDErrorType = 2,
+ VUIDErrorMax,
+} VUIDError;
+
+const static uint32_t NumVUIDBuiltins = 33;
+
+typedef struct {
+ SpvBuiltIn builtIn;
+ uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs
+} BuiltinVUIDMapping;
+
+std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
+ // clang-format off
+ {SpvBuiltInSubgroupEqMask, {0, 4370, 4371}},
+ {SpvBuiltInSubgroupGeMask, {0, 4372, 4373}},
+ {SpvBuiltInSubgroupGtMask, {0, 4374, 4375}},
+ {SpvBuiltInSubgroupLeMask, {0, 4376, 4377}},
+ {SpvBuiltInSubgroupLtMask, {0, 4378, 4379}},
+ {SpvBuiltInSubgroupLocalInvocationId, {0, 4380, 4381}},
+ {SpvBuiltInSubgroupSize, {0, 4382, 4383}},
+ {SpvBuiltInGlobalInvocationId, {4236, 4237, 4238}},
+ {SpvBuiltInLocalInvocationId, {4281, 4282, 4283}},
+ {SpvBuiltInNumWorkgroups, {4296, 4297, 4298}},
+ {SpvBuiltInNumSubgroups, {4293, 4294, 4295}},
+ {SpvBuiltInSubgroupId, {4367, 4368, 4369}},
+ {SpvBuiltInWorkgroupId, {4422, 4423, 4424}},
+ {SpvBuiltInHitKindKHR, {4242, 4243, 4244}},
+ {SpvBuiltInHitTNV, {4245, 4246, 4247}},
+ {SpvBuiltInInstanceCustomIndexKHR, {4251, 4252, 4253}},
+ {SpvBuiltInInstanceId, {4254, 4255, 4256}},
+ {SpvBuiltInRayGeometryIndexKHR, {4345, 4346, 4347}},
+ {SpvBuiltInObjectRayDirectionKHR, {4299, 4300, 4301}},
+ {SpvBuiltInObjectRayOriginKHR, {4302, 4303, 4304}},
+ {SpvBuiltInObjectToWorldKHR, {4305, 4306, 4307}},
+ {SpvBuiltInWorldToObjectKHR, {4434, 4435, 4436}},
+ {SpvBuiltInIncomingRayFlagsKHR, {4248, 4249, 4250}},
+ {SpvBuiltInRayTminKHR, {4351, 4352, 4353}},
+ {SpvBuiltInRayTmaxKHR, {4348, 4349, 4350}},
+ {SpvBuiltInWorldRayDirectionKHR, {4428, 4429, 4430}},
+ {SpvBuiltInWorldRayOriginKHR, {4431, 4432, 4433}},
+ {SpvBuiltInLaunchIdKHR, {4266, 4267, 4268}},
+ {SpvBuiltInLaunchSizeKHR, {4269, 4270, 4271}},
+ {SpvBuiltInFragInvocationCountEXT, {4217, 4218, 4219}},
+ {SpvBuiltInFragSizeEXT, {4220, 4221, 4222}},
+ {SpvBuiltInFragStencilRefEXT, {4223, 4224, 4225}},
+ {SpvBuiltInFullyCoveredEXT, {4232, 4233, 4234}},
+ // clang-format off
+} };
+
+uint32_t GetVUIDForBuiltin(SpvBuiltIn builtIn, VUIDError type) {
+ uint32_t vuid = 0;
+ for (const auto& iter: builtinVUIDInfo) {
+ if (iter.builtIn == builtIn) {
+ assert(type < VUIDErrorMax);
+ vuid = iter.vuid[type];
+ break;
}
+ }
+ return vuid;
+}
+
+bool IsExecutionModelValidForRtBuiltIn(SpvBuiltIn builtin,
+ SpvExecutionModel stage) {
+ switch (builtin) {
+ case SpvBuiltInHitKindKHR:
+ case SpvBuiltInHitTNV:
+ if (stage == SpvExecutionModelAnyHitKHR ||
+ stage == SpvExecutionModelClosestHitKHR) {
+ return true;
+ }
+ break;
+ case SpvBuiltInInstanceCustomIndexKHR:
+ case SpvBuiltInInstanceId:
+ case SpvBuiltInRayGeometryIndexKHR:
+ case SpvBuiltInObjectRayDirectionKHR:
+ case SpvBuiltInObjectRayOriginKHR:
+ case SpvBuiltInObjectToWorldKHR:
+ case SpvBuiltInWorldToObjectKHR:
+ switch (stage) {
+ case SpvExecutionModelIntersectionKHR:
+ case SpvExecutionModelAnyHitKHR:
+ case SpvExecutionModelClosestHitKHR:
+ return true;
+ default:
+ return false;
+ }
+ break;
+ case SpvBuiltInIncomingRayFlagsKHR:
+ case SpvBuiltInRayTminKHR:
+ case SpvBuiltInRayTmaxKHR:
+ case SpvBuiltInWorldRayDirectionKHR:
+ case SpvBuiltInWorldRayOriginKHR:
+ switch (stage) {
+ case SpvExecutionModelIntersectionKHR:
+ case SpvExecutionModelAnyHitKHR:
+ case SpvExecutionModelClosestHitKHR:
+ case SpvExecutionModelMissKHR:
+ return true;
+ default:
+ return false;
+ }
+ break;
+ case SpvBuiltInLaunchIdKHR:
+ case SpvBuiltInLaunchSizeKHR:
+ switch (stage) {
+ case SpvExecutionModelRayGenerationKHR:
+ case SpvExecutionModelIntersectionKHR:
+ case SpvExecutionModelAnyHitKHR:
+ case SpvExecutionModelClosestHitKHR:
+ case SpvExecutionModelMissKHR:
+ case SpvExecutionModelCallableKHR:
+ return true;
+ default:
+ return false;
+ }
+ break;
default:
break;
}
-
return false;
}
@@ -200,8 +304,8 @@
const Instruction& inst);
spv_result_t ValidateVertexIndexAtDefinition(const Decoration& decoration,
const Instruction& inst);
- spv_result_t ValidateVertexIdOrInstanceIdAtDefinition(
- const Decoration& decoration, const Instruction& inst);
+ spv_result_t ValidateVertexIdAtDefinition(const Decoration& decoration,
+ const Instruction& inst);
spv_result_t ValidateLocalInvocationIndexAtDefinition(
const Decoration& decoration, const Instruction& inst);
spv_result_t ValidateWorkgroupSizeAtDefinition(const Decoration& decoration,
@@ -214,6 +318,14 @@
const Instruction& inst);
spv_result_t ValidateDeviceIndexAtDefinition(const Decoration& decoration,
const Instruction& inst);
+ spv_result_t ValidateFragInvocationCountAtDefinition(const Decoration& decoration,
+ const Instruction& inst);
+ spv_result_t ValidateFragSizeAtDefinition(const Decoration& decoration,
+ const Instruction& inst);
+ spv_result_t ValidateFragStencilRefAtDefinition(const Decoration& decoration,
+ const Instruction& inst);
+ spv_result_t ValidateFullyCoveredAtDefinition(const Decoration& decoration,
+ const Instruction& inst);
// Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition(
const Decoration& decoration, const Instruction& inst);
@@ -237,6 +349,9 @@
spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration,
const Instruction& inst);
+ spv_result_t ValidateRayTracingBuiltinsAtDefinition(
+ 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|
@@ -269,11 +384,6 @@
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
- spv_result_t ValidateInstanceIdAtReference(
- const Decoration& decoration, const Instruction& built_in_inst,
- const Instruction& referenced_inst,
- const Instruction& referenced_from_inst);
-
spv_result_t ValidateInstanceIndexAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
@@ -374,6 +484,26 @@
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
+ spv_result_t ValidateFragInvocationCountAtReference(
+ const Decoration& decoration, const Instruction& built_in_inst,
+ const Instruction& referenced_inst,
+ const Instruction& referenced_from_inst);
+
+ spv_result_t ValidateFragSizeAtReference(
+ const Decoration& decoration, const Instruction& built_in_inst,
+ const Instruction& referenced_inst,
+ const Instruction& referenced_from_inst);
+
+ spv_result_t ValidateFragStencilRefAtReference(
+ const Decoration& decoration, const Instruction& built_in_inst,
+ const Instruction& referenced_inst,
+ const Instruction& referenced_from_inst);
+
+ spv_result_t ValidateFullyCoveredAtReference(
+ const Decoration& decoration, const Instruction& built_in_inst,
+ const Instruction& referenced_inst,
+ const Instruction& referenced_from_inst);
+
// Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
spv_result_t ValidateComputeShaderI32Vec3InputAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
@@ -400,6 +530,11 @@
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
+ spv_result_t ValidateRayTracingBuiltinsAtReference(
+ 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|.
//
@@ -422,6 +557,9 @@
spv_result_t ValidateBool(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
+ spv_result_t ValidateI(
+ const Decoration& decoration, const Instruction& inst,
+ const std::function<spv_result_t(const std::string& message)>& diag);
spv_result_t ValidateI32(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
@@ -476,6 +614,10 @@
uint32_t num_components,
const std::function<spv_result_t(const std::string& message)>& diag,
uint32_t underlying_type);
+ spv_result_t ValidateF32Mat(
+ const Decoration& decoration, const Instruction& inst,
+ uint32_t req_num_rows, uint32_t req_num_columns,
+ const std::function<spv_result_t(const std::string& message)>& diag);
// Generates strings like "Member #0 of struct ID <2>".
std::string GetDefinitionDesc(const Decoration& decoration,
@@ -610,6 +752,22 @@
return SPV_SUCCESS;
}
+spv_result_t BuiltInsValidator::ValidateI(
+ const Decoration& decoration, const Instruction& inst,
+ 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;
+ }
+
+ if (!_.IsIntScalarType(underlying_type)) {
+ return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar.");
+ }
+
+ return SPV_SUCCESS;
+}
+
spv_result_t BuiltInsValidator::ValidateI32(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag) {
@@ -909,6 +1067,32 @@
return SPV_SUCCESS;
}
+spv_result_t BuiltInsValidator::ValidateF32Mat(
+ const Decoration& decoration, const Instruction& inst,
+ uint32_t req_num_rows, uint32_t req_num_columns,
+ const std::function<spv_result_t(const std::string& message)>& diag) {
+ uint32_t underlying_type = 0;
+ uint32_t num_rows = 0;
+ uint32_t num_cols = 0;
+ uint32_t col_type = 0;
+ uint32_t component_type = 0;
+ if (spv_result_t error =
+ GetUnderlyingType(_, decoration, inst, &underlying_type)) {
+ return error;
+ }
+ if (!_.GetMatrixTypeInfo(underlying_type, &num_rows, &num_cols, &col_type,
+ &component_type) ||
+ num_rows != req_num_rows || num_cols != req_num_columns) {
+ std::ostringstream ss;
+ ss << GetDefinitionDesc(decoration, inst) << " has columns " << num_cols
+ << " and rows " << num_rows << " not equal to expected "
+ << req_num_columns << "x" << req_num_rows << ".";
+ return diag(ss.str());
+ }
+
+ return ValidateF32VecHelper(decoration, inst, req_num_rows, diag, col_type);
+}
+
spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel(
int vuid, const char* comment, SpvExecutionModel execution_model,
const Decoration& decoration, const Instruction& built_in_inst,
@@ -956,8 +1140,9 @@
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput &&
storage_class != SpvStorageClassOutput) {
+ uint32_t vuid = (decoration.params()[0] == SpvBuiltInClipDistance) ? 4190 : 4199;
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "Vulkan spec allows BuiltIn "
+ << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
operand)
<< " to be only used for variables with Input or Output storage "
@@ -969,19 +1154,28 @@
if (storage_class == SpvStorageClassInput) {
assert(function_id_ == 0);
+ uint32_t vuid = (decoration.params()[0] == SpvBuiltInClipDistance) ? 4188 : 4197;
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
- &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, -1,
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
"Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
"used for variables with Input storage class if execution model is "
"Vertex.",
SpvExecutionModelVertex, decoration, built_in_inst,
referenced_from_inst, std::placeholders::_1));
+ id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
+ "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
+ "used for variables with Input storage class if execution model is "
+ "Vertex.",
+ SpvExecutionModelMeshNV, decoration, built_in_inst,
+ referenced_from_inst, std::placeholders::_1));
}
if (storage_class == SpvStorageClassOutput) {
assert(function_id_ == 0);
+ uint32_t vuid = (decoration.params()[0] == SpvBuiltInClipDistance) ? 4189 : 4198;
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
- &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, -1,
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
"Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
"used for variables with Output storage class if execution model is "
"Fragment.",
@@ -1095,7 +1289,7 @@
spv_result_t BuiltInsValidator::ValidateFragCoordAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
if (spv_result_t error = ValidateF32Vec(
decoration, inst, 4,
[this, &inst](const std::string& message) -> spv_result_t {
@@ -1119,7 +1313,7 @@
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
@@ -1157,7 +1351,7 @@
spv_result_t BuiltInsValidator::ValidateFragDepthAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
if (spv_result_t error = ValidateF32(
decoration, inst,
[this, &inst](const std::string& message) -> spv_result_t {
@@ -1180,7 +1374,7 @@
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassOutput) {
@@ -1233,7 +1427,7 @@
spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
if (spv_result_t error = ValidateBool(
decoration, inst,
[this, &inst](const std::string& message) -> spv_result_t {
@@ -1256,7 +1450,7 @@
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
@@ -1414,7 +1608,7 @@
spv_result_t BuiltInsValidator::ValidateInstanceIndexAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
if (spv_result_t error = ValidateI32(
decoration, inst,
[this, &inst](const std::string& message) -> spv_result_t {
@@ -1437,7 +1631,7 @@
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
@@ -1727,7 +1921,7 @@
storage_class != SpvStorageClassInput &&
storage_class != SpvStorageClassOutput) {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "Vulkan spec allows BuiltIn Position to be only used for "
+ << _.VkErrorID(4320) << "Vulkan spec allows BuiltIn Position to be only used for "
"variables with Input or Output storage class. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst)
@@ -1737,12 +1931,19 @@
if (storage_class == SpvStorageClassInput) {
assert(function_id_ == 0);
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
- &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4320,
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
"Vulkan spec doesn't allow BuiltIn Position to be used "
"for variables "
"with Input storage class if execution model is Vertex.",
SpvExecutionModelVertex, decoration, built_in_inst,
referenced_from_inst, std::placeholders::_1));
+ id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
+ "Vulkan spec doesn't allow BuiltIn Position to be used "
+ "for variables "
+ "with Input storage class if execution model is MeshNV.",
+ SpvExecutionModelMeshNV, decoration, built_in_inst,
+ referenced_from_inst, std::placeholders::_1));
}
for (const SpvExecutionModel execution_model : execution_models_) {
@@ -1820,46 +2021,6 @@
}
}
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
- if (storage_class != SpvStorageClassMax &&
- storage_class != SpvStorageClassOutput) {
- return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "WebGPU spec allows BuiltIn Position 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 SpvExecutionModel execution_model : execution_models_) {
- switch (execution_model) {
- case SpvExecutionModelVertex: {
- if (spv_result_t error = ValidateF32Vec(
- decoration, built_in_inst, 4,
- [this, &referenced_from_inst](
- const std::string& message) -> spv_result_t {
- return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "According to the WebGPU spec BuiltIn Position "
- "variable needs to be a 4-component 32-bit float "
- "vector. "
- << message;
- })) {
- return error;
- }
- break;
- }
- default: {
- return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "WebGPU spec allows BuiltIn Position to be used only "
- "with the Vertex 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(
@@ -1947,6 +2108,27 @@
"Fragment.",
SpvExecutionModelFragment, decoration, built_in_inst,
referenced_from_inst, std::placeholders::_1));
+ id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
+ "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
+ "variables with Output storage class if execution model is "
+ "IntersectionKHR.",
+ SpvExecutionModelIntersectionKHR, decoration, built_in_inst,
+ referenced_from_inst, std::placeholders::_1));
+ id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
+ "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
+ "variables with Output storage class if execution model is "
+ "AnyHitKHR.",
+ SpvExecutionModelAnyHitKHR, decoration, built_in_inst,
+ referenced_from_inst, std::placeholders::_1));
+ id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
+ "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
+ "variables with Output storage class if execution model is "
+ "ClosestHitKHR.",
+ SpvExecutionModelClosestHitKHR, decoration, built_in_inst,
+ referenced_from_inst, std::placeholders::_1));
}
for (const SpvExecutionModel execution_model : execution_models_) {
@@ -1956,12 +2138,9 @@
case SpvExecutionModelTessellationEvaluation:
case SpvExecutionModelGeometry:
case SpvExecutionModelMeshNV:
- case SpvExecutionModelRayGenerationNV:
- case SpvExecutionModelIntersectionNV:
- case SpvExecutionModelAnyHitNV:
- case SpvExecutionModelClosestHitNV:
- case SpvExecutionModelMissNV:
- case SpvExecutionModelCallableNV: {
+ case SpvExecutionModelIntersectionKHR:
+ case SpvExecutionModelAnyHitKHR:
+ case SpvExecutionModelClosestHitKHR: {
// Ok.
break;
}
@@ -1971,7 +2150,9 @@
<< _.VkErrorID(4330)
<< "Vulkan spec allows BuiltIn PrimitiveId to be used only "
"with Fragment, TessellationControl, "
- "TessellationEvaluation or Geometry execution models. "
+ "TessellationEvaluation, Geometry, MeshNV, "
+ "IntersectionKHR, "
+ "AnyHitKHR, and ClosestHitKHR execution models. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst, execution_model);
}
@@ -2296,8 +2477,9 @@
if (storage_class == SpvStorageClassInput) {
assert(function_id_ == 0);
+ uint32_t vuid = (decoration.params()[0] == SpvBuiltInTessLevelOuter) ? 4391 : 4395;
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
- &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, -1,
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
"Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
"used "
"for variables with Input storage class if execution model is "
@@ -2308,8 +2490,9 @@
if (storage_class == SpvStorageClassOutput) {
assert(function_id_ == 0);
+ uint32_t vuid = (decoration.params()[0] == SpvBuiltInTessLevelOuter) ? 4392 : 4396;
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
- &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, -1,
+ &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
"Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
"used "
"for variables with Output storage class if execution model is "
@@ -2353,7 +2536,7 @@
spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
if (spv_result_t error = ValidateI32(
decoration, inst,
[this, &inst](const std::string& message) -> spv_result_t {
@@ -2372,54 +2555,13 @@
return ValidateVertexIndexAtReference(decoration, inst, inst, inst);
}
-spv_result_t BuiltInsValidator::ValidateVertexIdOrInstanceIdAtDefinition(
+spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
- bool allow_instance_id = (_.HasCapability(SpvCapabilityRayTracingNV) ||
- _.HasCapability(SpvCapabilityRayTracingKHR)) &&
- label == SpvBuiltInInstanceId;
-
- if (spvIsVulkanEnv(_.context()->target_env) && !allow_instance_id) {
- return _.diag(SPV_ERROR_INVALID_DATA, &inst)
- << "Vulkan spec doesn't allow BuiltIn VertexId/InstanceId "
- "to be used.";
- }
-
- if (label == SpvBuiltInInstanceId) {
- return ValidateInstanceIdAtReference(decoration, inst, inst, inst);
- }
- return SPV_SUCCESS;
-}
-
-spv_result_t BuiltInsValidator::ValidateInstanceIdAtReference(
- const Decoration& decoration, const Instruction& built_in_inst,
- const Instruction& referenced_inst,
- const Instruction& referenced_from_inst) {
+ (void)decoration;
if (spvIsVulkanEnv(_.context()->target_env)) {
- for (const SpvExecutionModel execution_model : execution_models_) {
- switch (execution_model) {
- case SpvExecutionModelIntersectionNV:
- case SpvExecutionModelClosestHitNV:
- case SpvExecutionModelAnyHitNV:
- // Do nothing, valid stages
- break;
- default:
- return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "Vulkan spec allows BuiltIn InstanceId to be used "
- "only with IntersectionNV, ClosestHitNV and AnyHitNV "
- "execution models. "
- << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
- referenced_from_inst);
- break;
- }
- }
- }
-
- 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::ValidateInstanceIdAtReference, this, decoration,
- built_in_inst, referenced_from_inst, std::placeholders::_1));
+ return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+ << "Vulkan spec doesn't allow BuiltIn VertexId "
+ "to be used.";
}
return SPV_SUCCESS;
@@ -2427,51 +2569,14 @@
spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- if (spv_result_t error = ValidateI32(
- decoration, inst,
- [this, &inst](const std::string& message) -> spv_result_t {
- return _.diag(SPV_ERROR_INVALID_DATA, &inst)
- << "According to the WebGPU spec BuiltIn "
- "LocalInvocationIndex variable needs to be a 32-bit "
- "int."
- << message;
- })) {
- return error;
- }
- }
-
// Seed at reference checks with this built-in.
return ValidateLocalInvocationIndexAtReference(decoration, inst, inst, inst);
}
spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
- const Instruction& referenced_inst,
+ const Instruction&,
const Instruction& referenced_from_inst) {
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
- if (storage_class != SpvStorageClassMax &&
- storage_class != SpvStorageClassInput) {
- return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "WebGPU spec allows BuiltIn LocalInvocationIndex to be only "
- "used for variables with Input storage class. "
- << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
- referenced_from_inst)
- << " " << GetStorageClassDesc(referenced_from_inst);
- }
-
- for (const SpvExecutionModel execution_model : execution_models_) {
- if (execution_model != SpvExecutionModelGLCompute) {
- return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "WebGPU spec allows BuiltIn VertexIndex to be used only "
- "with GLCompute 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(
@@ -2487,7 +2592,7 @@
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
@@ -2647,8 +2752,9 @@
if (operand == SpvBuiltInLayer)
capability = "ShaderViewportIndexLayerEXT or ShaderLayer";
+ uint32_t vuid = (operand == SpvBuiltInLayer) ? 4273 : 4405;
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "Using BuiltIn "
+ << _.VkErrorID(vuid) << "Using BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
operand)
<< " in Vertex or Tessellation execution model requires the "
@@ -2684,33 +2790,18 @@
spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
if (spv_result_t error = ValidateI32Vec(
decoration, inst, 3,
- [this, &decoration,
- &inst](const std::string& message) -> spv_result_t {
- uint32_t operand = decoration.params()[0];
- uint32_t vuid = 0;
- switch (operand) {
- case SpvBuiltInGlobalInvocationId:
- vuid = 4238;
- break;
- case SpvBuiltInLocalInvocationId:
- vuid = 4283;
- break;
- case SpvBuiltInNumWorkgroups:
- vuid = 4298;
- break;
- case SpvBuiltInWorkgroupId:
- vuid = 4424;
- break;
- };
+ [this, &inst, builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
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,
- operand)
+ builtin)
<< " variable needs to be a 3-component 32-bit int "
"vector. "
<< message;
@@ -2728,31 +2819,16 @@
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
- uint32_t operand = decoration.params()[0];
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
- uint32_t vuid = 0;
- switch (operand) {
- case SpvBuiltInGlobalInvocationId:
- vuid = 4237;
- break;
- case SpvBuiltInLocalInvocationId:
- vuid = 4282;
- break;
- case SpvBuiltInNumWorkgroups:
- vuid = 4297;
- break;
- case SpvBuiltInWorkgroupId:
- vuid = 4423;
- break;
- };
+ 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,
- decoration.params()[0])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " to be only used for variables with Input storage class. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst)
@@ -2763,30 +2839,13 @@
bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute ||
execution_model == SpvExecutionModelTaskNV ||
execution_model == SpvExecutionModelMeshNV;
- bool has_webgpu_model = execution_model == SpvExecutionModelGLCompute;
- if ((spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) ||
- (spvIsWebGPUEnv(_.context()->target_env) && !has_webgpu_model)) {
- uint32_t vuid = 0;
- switch (operand) {
- case SpvBuiltInGlobalInvocationId:
- vuid = 4236;
- break;
- case SpvBuiltInLocalInvocationId:
- vuid = 4281;
- break;
- case SpvBuiltInNumWorkgroups:
- vuid = 4296;
- break;
- case SpvBuiltInWorkgroupId:
- vuid = 4422;
- break;
- };
+ if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
+ 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,
- decoration.params()[0])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " to be used only with GLCompute execution model. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst, execution_model);
@@ -2808,23 +2867,23 @@
spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
if (decoration.struct_member_index() != Decoration::kInvalidMember) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "BuiltIn "
- << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
- decoration.params()[0])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " cannot be used as a member decoration ";
}
if (spv_result_t error = ValidateI32(
decoration, inst,
- [this, &decoration,
- &inst](const std::string& message) -> spv_result_t {
+ [this, &inst, builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
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])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " variable needs to be a 32-bit int "
"vector. "
<< message;
@@ -2842,14 +2901,16 @@
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
+ 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,
- decoration.params()[0])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " to be only used for variables with Input storage class. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst)
@@ -2861,11 +2922,12 @@
execution_model == SpvExecutionModelTaskNV ||
execution_model == SpvExecutionModelMeshNV;
if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
+ 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,
- decoration.params()[0])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " to be used only with GLCompute execution model. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst, execution_model);
@@ -2887,23 +2949,23 @@
spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
if (decoration.struct_member_index() != Decoration::kInvalidMember) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "BuiltIn "
- << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
- decoration.params()[0])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " cannot be used as a member decoration ";
}
if (spv_result_t error = ValidateI32(
decoration, inst,
- [this, &decoration,
- &inst](const std::string& message) -> spv_result_t {
+ [this, &inst, builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
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])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " variable needs to be a 32-bit int. " << message;
})) {
return error;
@@ -2912,11 +2974,12 @@
const SpvStorageClass storage_class = GetStorageClass(inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+ << _.VkErrorID(vuid)
<< spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
- << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
- decoration.params()[0])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " to be only used for variables with Input storage class. "
<< GetReferenceDesc(decoration, inst, inst, inst) << " "
<< GetStorageClassDesc(inst);
@@ -2929,23 +2992,23 @@
spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
if (decoration.struct_member_index() != Decoration::kInvalidMember) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "BuiltIn "
- << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
- decoration.params()[0])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " cannot be used as a member decoration ";
}
if (spv_result_t error = ValidateI32Vec(
decoration, inst, 4,
- [this, &decoration,
- &inst](const std::string& message) -> spv_result_t {
+ [this, &inst, builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
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])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " variable needs to be a 4-component 32-bit int "
"vector. "
<< message;
@@ -2956,11 +3019,12 @@
const SpvStorageClass storage_class = GetStorageClass(inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+ << _.VkErrorID(vuid)
<< spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
- << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
- decoration.params()[0])
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " to be only used for variables with Input storage class. "
<< GetReferenceDesc(decoration, inst, inst, inst) << " "
<< GetStorageClassDesc(inst);
@@ -2972,7 +3036,7 @@
spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
if (spvIsVulkanEnv(_.context()->target_env) &&
!spvOpcodeIsConstant(inst.opcode())) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
@@ -3004,7 +3068,7 @@
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
for (const SpvExecutionModel execution_model : execution_models_) {
if (execution_model != SpvExecutionModelGLCompute) {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
@@ -3283,6 +3347,287 @@
return SPV_SUCCESS;
}
+spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtDefinition(const Decoration& decoration,
+ const Instruction& inst) {
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ if (spv_result_t error = ValidateI32(
+ decoration, inst,
+ [this, &inst, &builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+ 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,
+ builtin)
+ << " variable needs to be a 32-bit int scalar. "
+ << message;
+ })) {
+ return error;
+ }
+ }
+
+ return ValidateFragInvocationCountAtReference(decoration, inst, inst, inst);
+}
+
+spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtReference(
+ const Decoration& decoration, const Instruction& built_in_inst,
+ const Instruction& referenced_inst,
+ const Instruction& referenced_from_inst) {
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
+ if (storage_class != SpvStorageClassMax &&
+ storage_class != SpvStorageClassInput) {
+ 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, builtin)
+ << " to be only used for variables with Input storage class. "
+ << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
+ referenced_from_inst)
+ << " " << GetStorageClassDesc(referenced_from_inst);
+ }
+
+ for (const SpvExecutionModel execution_model : execution_models_) {
+ if (execution_model != SpvExecutionModelFragment) {
+ 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, builtin)
+ << " to be used only with Fragment 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::ValidateFragInvocationCountAtReference, this, decoration,
+ built_in_inst, referenced_from_inst, std::placeholders::_1));
+ }
+
+ return SPV_SUCCESS;
+}
+
+spv_result_t BuiltInsValidator::ValidateFragSizeAtDefinition(const Decoration& decoration,
+ const Instruction& inst) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ if (spv_result_t error = ValidateI32Vec(
+ decoration, inst, 2,
+ [this, &inst, &builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+ 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,
+ builtin)
+ << " variable needs to be a 2-component 32-bit int vector. "
+ << message;
+ })) {
+ return error;
+ }
+ }
+
+ return ValidateFragSizeAtReference(decoration, inst, inst, inst);
+}
+
+spv_result_t BuiltInsValidator::ValidateFragSizeAtReference(
+ const Decoration& decoration, const Instruction& built_in_inst,
+ const Instruction& referenced_inst,
+ const Instruction& referenced_from_inst) {
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
+ if (storage_class != SpvStorageClassMax &&
+ storage_class != SpvStorageClassInput) {
+ 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, builtin)
+ << " to be only used for variables with Input storage class. "
+ << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
+ referenced_from_inst)
+ << " " << GetStorageClassDesc(referenced_from_inst);
+ }
+
+ for (const SpvExecutionModel execution_model : execution_models_) {
+ if (execution_model != SpvExecutionModelFragment) {
+ 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, builtin)
+ << " to be used only with Fragment 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::ValidateFragSizeAtReference, this, decoration,
+ built_in_inst, referenced_from_inst, std::placeholders::_1));
+ }
+
+ return SPV_SUCCESS;
+}
+
+spv_result_t BuiltInsValidator::ValidateFragStencilRefAtDefinition(const Decoration& decoration,
+ const Instruction& inst) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ if (spv_result_t error = ValidateI(
+ decoration, inst,
+ [this, &inst, &builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+ 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,
+ builtin)
+ << " variable needs to be a int scalar. "
+ << message;
+ })) {
+ return error;
+ }
+ }
+
+ return ValidateFragStencilRefAtReference(decoration, inst, inst, inst);
+}
+
+spv_result_t BuiltInsValidator::ValidateFragStencilRefAtReference(
+ const Decoration& decoration, const Instruction& built_in_inst,
+ const Instruction& referenced_inst,
+ const Instruction& referenced_from_inst) {
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
+ if (storage_class != SpvStorageClassMax &&
+ storage_class != SpvStorageClassOutput) {
+ 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, 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 SpvExecutionModel execution_model : execution_models_) {
+ if (execution_model != SpvExecutionModelFragment) {
+ 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, builtin)
+ << " to be used only with Fragment 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::ValidateFragStencilRefAtReference, this, decoration,
+ built_in_inst, referenced_from_inst, std::placeholders::_1));
+ }
+
+ return SPV_SUCCESS;
+}
+
+spv_result_t BuiltInsValidator::ValidateFullyCoveredAtDefinition(const Decoration& decoration,
+ const Instruction& inst) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ if (spv_result_t error = ValidateBool(
+ decoration, inst,
+ [this, &inst, &builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+ 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,
+ builtin)
+ << " variable needs to be a bool scalar. "
+ << message;
+ })) {
+ return error;
+ }
+ }
+
+ return ValidateFullyCoveredAtReference(decoration, inst, inst, inst);
+}
+
+spv_result_t BuiltInsValidator::ValidateFullyCoveredAtReference(
+ const Decoration& decoration, const Instruction& built_in_inst,
+ const Instruction& referenced_inst,
+ const Instruction& referenced_from_inst) {
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
+ if (storage_class != SpvStorageClassMax &&
+ storage_class != SpvStorageClassInput) {
+ 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, builtin)
+ << " to be only used for variables with Input storage class. "
+ << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
+ referenced_from_inst)
+ << " " << GetStorageClassDesc(referenced_from_inst);
+ }
+
+ for (const SpvExecutionModel execution_model : execution_models_) {
+ if (execution_model != SpvExecutionModelFragment) {
+ 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, builtin)
+ << " to be used only with Fragment 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::ValidateFullyCoveredAtReference, this, decoration,
+ built_in_inst, referenced_from_inst, std::placeholders::_1));
+ }
+
+ return SPV_SUCCESS;
+}
+
spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
@@ -3474,6 +3819,174 @@
return SPV_SUCCESS;
}
+spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
+ const Decoration& decoration, const Instruction& inst) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ switch (builtin) {
+ case SpvBuiltInHitTNV:
+ case SpvBuiltInRayTminKHR:
+ case SpvBuiltInRayTmaxKHR:
+ // f32 scalar
+ if (spv_result_t error = ValidateF32(
+ decoration, inst,
+ [this, &inst,
+ builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+ return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+ << _.VkErrorID(vuid)
+ << "According to the Vulkan spec BuiltIn "
+ << _.grammar().lookupOperandName(
+ SPV_OPERAND_TYPE_BUILT_IN, builtin)
+ << " variable needs to be a 32-bit float scalar. "
+ << message;
+ })) {
+ return error;
+ }
+ break;
+ case SpvBuiltInHitKindKHR:
+ case SpvBuiltInInstanceCustomIndexKHR:
+ case SpvBuiltInInstanceId:
+ case SpvBuiltInRayGeometryIndexKHR:
+ case SpvBuiltInIncomingRayFlagsKHR:
+ // i32 scalar
+ if (spv_result_t error = ValidateI32(
+ decoration, inst,
+ [this, &inst,
+ builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+ return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+ << _.VkErrorID(vuid)
+ << "According to the Vulkan spec BuiltIn "
+ << _.grammar().lookupOperandName(
+ SPV_OPERAND_TYPE_BUILT_IN, builtin)
+ << " variable needs to be a 32-bit int scalar. "
+ << message;
+ })) {
+ return error;
+ }
+ break;
+ case SpvBuiltInObjectRayDirectionKHR:
+ case SpvBuiltInObjectRayOriginKHR:
+ case SpvBuiltInWorldRayDirectionKHR:
+ case SpvBuiltInWorldRayOriginKHR:
+ // f32 vec3
+ if (spv_result_t error = ValidateF32Vec(
+ decoration, inst, 3,
+ [this, &inst,
+ builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+ return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+ << _.VkErrorID(vuid)
+ << "According to the Vulkan spec BuiltIn "
+ << _.grammar().lookupOperandName(
+ SPV_OPERAND_TYPE_BUILT_IN, builtin)
+ << " variable needs to be a 3-component 32-bit float "
+ "vector. "
+ << message;
+ })) {
+ return error;
+ }
+ break;
+ case SpvBuiltInLaunchIdKHR:
+ case SpvBuiltInLaunchSizeKHR:
+ // i32 vec3
+ if (spv_result_t error = ValidateI32Vec(
+ decoration, inst, 3,
+ [this, &inst,
+ builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+ return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+ << _.VkErrorID(vuid)
+ << "According to the Vulkan spec BuiltIn "
+ << _.grammar().lookupOperandName(
+ SPV_OPERAND_TYPE_BUILT_IN, builtin)
+ << " variable needs to be a 3-component 32-bit int "
+ "vector. "
+ << message;
+ })) {
+ return error;
+ }
+ break;
+ case SpvBuiltInObjectToWorldKHR:
+ case SpvBuiltInWorldToObjectKHR:
+ // f32 mat4x3
+ if (spv_result_t error = ValidateF32Mat(
+ decoration, inst, 3, 4,
+ [this, &inst,
+ builtin](const std::string& message) -> spv_result_t {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+ return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+ << _.VkErrorID(vuid)
+ << "According to the Vulkan spec BuiltIn "
+ << _.grammar().lookupOperandName(
+ SPV_OPERAND_TYPE_BUILT_IN, builtin)
+ << " variable needs to be a matrix with"
+ << " 4 columns of 3-component vectors of 32-bit "
+ "floats. "
+ << message;
+ })) {
+ return error;
+ }
+ break;
+ default:
+ assert(0 && "Unexpected ray tracing builtin");
+ break;
+ }
+ }
+
+ // Seed at reference checks with this built-in.
+ return ValidateRayTracingBuiltinsAtReference(decoration, inst, inst, inst);
+}
+
+spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
+ const Decoration& decoration, const Instruction& built_in_inst,
+ const Instruction& referenced_inst,
+ const Instruction& referenced_from_inst) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+ const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
+ if (storage_class != SpvStorageClassMax &&
+ storage_class != SpvStorageClassInput) {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
+ return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
+ << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+ decoration.params()[0])
+ << " to be only used for variables with Input storage class. "
+ << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
+ referenced_from_inst)
+ << " " << GetStorageClassDesc(referenced_from_inst);
+ }
+
+ for (const SpvExecutionModel execution_model : execution_models_) {
+ if (!IsExecutionModelValidForRtBuiltIn(builtin, execution_model)) {
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
+ return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
+ << _.VkErrorID(vuid) << "Vulkan spec does not allow BuiltIn "
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+ decoration.params()[0])
+ << " to be used with the execution model "
+ << _.grammar().lookupOperandName(
+ SPV_OPERAND_TYPE_EXECUTION_MODEL, execution_model)
+ << ".\n"
+ << 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::ValidateRayTracingBuiltinsAtReference,
+ 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 SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
@@ -3486,26 +3999,17 @@
<< "BuiltIns can only target variables, structs or constants";
}
- if (!spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
- // Early return. All currently implemented rules are based on Vulkan or
- // WebGPU spec.
+ if (!spvIsVulkanEnv(_.context()->target_env)) {
+ // Early return. All currently implemented rules are based on Vulkan spec.
//
// TODO: If you are adding validation rules for environments other than
- // Vulkan or WebGPU (or general rules which are not environment
- // independent), then you need to modify or remove this condition. Consider
- // also adding early returns into BuiltIn-specific rules, so that the system
- // doesn't spawn new rules which don't do anything.
+ // Vulkan (or general rules which are not environment independent), then
+ // you need to modify or remove this condition. Consider also adding early
+ // returns into BuiltIn-specific rules, so that the system doesn't spawn new
+ // rules which don't do anything.
return SPV_SUCCESS;
}
- if (spvIsWebGPUEnv(_.context()->target_env) &&
- !IsBuiltInValidForWebGPU(label)) {
- return _.diag(SPV_ERROR_INVALID_DATA, &inst)
- << "WebGPU does not allow BuiltIn "
- << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
- decoration.params()[0]);
- }
-
// If you are adding a new BuiltIn enum, please register it here.
// If the newly added enum has validation rules associated with it
// consider leaving a TODO and/or creating an issue.
@@ -3596,9 +4100,8 @@
case SpvBuiltInWorkgroupSize: {
return ValidateWorkgroupSizeAtDefinition(decoration, inst);
}
- case SpvBuiltInVertexId:
- case SpvBuiltInInstanceId: {
- return ValidateVertexIdOrInstanceIdAtDefinition(decoration, inst);
+ case SpvBuiltInVertexId: {
+ return ValidateVertexIdAtDefinition(decoration, inst);
}
case SpvBuiltInLocalInvocationIndex: {
return ValidateLocalInvocationIndexAtDefinition(decoration, inst);
@@ -3622,6 +4125,41 @@
case SpvBuiltInDeviceIndex: {
return ValidateDeviceIndexAtDefinition(decoration, inst);
}
+ case SpvBuiltInFragInvocationCountEXT: {
+ // alias SpvBuiltInInvocationsPerPixelNV
+ return ValidateFragInvocationCountAtDefinition(decoration, inst);
+ }
+ case SpvBuiltInFragSizeEXT: {
+ // alias SpvBuiltInFragmentSizeNV
+ return ValidateFragSizeAtDefinition(decoration, inst);
+ }
+ case SpvBuiltInFragStencilRefEXT: {
+ return ValidateFragStencilRefAtDefinition(decoration, inst);
+ }
+ case SpvBuiltInFullyCoveredEXT:{
+ return ValidateFullyCoveredAtDefinition(decoration, inst);
+ }
+ // Ray tracing builtins
+ case SpvBuiltInHitKindKHR: // alias SpvBuiltInHitKindNV
+ case SpvBuiltInHitTNV: // NOT present in KHR
+ case SpvBuiltInInstanceId:
+ case SpvBuiltInLaunchIdKHR: // alias SpvBuiltInLaunchIdNV
+ case SpvBuiltInLaunchSizeKHR: // alias SpvBuiltInLaunchSizeNV
+ case SpvBuiltInWorldRayOriginKHR: // alias SpvBuiltInWorldRayOriginNV
+ case SpvBuiltInWorldRayDirectionKHR: // alias SpvBuiltInWorldRayDirectionNV
+ case SpvBuiltInObjectRayOriginKHR: // alias SpvBuiltInObjectRayOriginNV
+ case SpvBuiltInObjectRayDirectionKHR: // alias
+ // SpvBuiltInObjectRayDirectionNV
+ case SpvBuiltInRayTminKHR: // alias SpvBuiltInRayTminNV
+ case SpvBuiltInRayTmaxKHR: // alias SpvBuiltInRayTmaxNV
+ case SpvBuiltInInstanceCustomIndexKHR: // alias
+ // SpvBuiltInInstanceCustomIndexNV
+ case SpvBuiltInObjectToWorldKHR: // alias SpvBuiltInObjectToWorldNV
+ case SpvBuiltInWorldToObjectKHR: // alias SpvBuiltInWorldToObjectNV
+ case SpvBuiltInIncomingRayFlagsKHR: // alias SpvBuiltInIncomingRayFlagsNV
+ case SpvBuiltInRayGeometryIndexKHR: { // NOT present in NV
+ return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
+ }
case SpvBuiltInWorkDim:
case SpvBuiltInGlobalSize:
case SpvBuiltInEnqueuedWorkgroupSize:
@@ -3636,13 +4174,11 @@
case SpvBuiltInBaryCoordSmoothCentroidAMD:
case SpvBuiltInBaryCoordSmoothSampleAMD:
case SpvBuiltInBaryCoordPullModelAMD:
- case SpvBuiltInFragStencilRefEXT:
case SpvBuiltInViewportMaskNV:
case SpvBuiltInSecondaryPositionNV:
case SpvBuiltInSecondaryViewportMaskNV:
case SpvBuiltInPositionPerViewNV:
case SpvBuiltInViewportMaskPerViewNV:
- case SpvBuiltInFullyCoveredEXT:
case SpvBuiltInMax:
case SpvBuiltInTaskCountNV:
case SpvBuiltInPrimitiveCountNV:
@@ -3654,31 +4190,14 @@
case SpvBuiltInMeshViewIndicesNV:
case SpvBuiltInBaryCoordNV:
case SpvBuiltInBaryCoordNoPerspNV:
- case SpvBuiltInFragmentSizeNV: // alias SpvBuiltInFragSizeEXT
- case SpvBuiltInInvocationsPerPixelNV: // alias
- // SpvBuiltInFragInvocationCountEXT
- case SpvBuiltInLaunchIdNV:
- case SpvBuiltInLaunchSizeNV:
- case SpvBuiltInWorldRayOriginNV:
- case SpvBuiltInWorldRayDirectionNV:
- case SpvBuiltInObjectRayOriginNV:
- case SpvBuiltInObjectRayDirectionNV:
- case SpvBuiltInRayTminNV:
- case SpvBuiltInRayTmaxNV:
- case SpvBuiltInInstanceCustomIndexNV:
- case SpvBuiltInObjectToWorldNV:
- case SpvBuiltInWorldToObjectNV:
- case SpvBuiltInHitTNV:
- case SpvBuiltInHitKindNV:
- case SpvBuiltInIncomingRayFlagsNV:
- case SpvBuiltInRayGeometryIndexKHR: {
// No validation rules (for the moment).
break;
- case SpvBuiltInPrimitiveShadingRateKHR:
- return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
- case SpvBuiltInShadingRateKHR:
- return ValidateShadingRateAtDefinition(decoration, inst);
+ case SpvBuiltInPrimitiveShadingRateKHR: {
+ return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
+ }
+ case SpvBuiltInShadingRateKHR: {
+ return ValidateShadingRateAtDefinition(decoration, inst);
}
}
return SPV_SUCCESS;
diff --git a/source/val/validate_capability.cpp b/source/val/validate_capability.cpp
index 4b98bc1..8efd554 100644
--- a/source/val/validate_capability.cpp
+++ b/source/val/validate_capability.cpp
@@ -260,19 +260,6 @@
return false;
}
-bool IsSupportGuaranteedWebGPU(uint32_t capability) {
- switch (capability) {
- case SpvCapabilityMatrix:
- case SpvCapabilityShader:
- case SpvCapabilitySampled1D:
- case SpvCapabilityImage1D:
- case SpvCapabilityDerivativeControl:
- case SpvCapabilityImageQuery:
- return true;
- }
- return false;
-}
-
} // namespace
// Validates that capability declarations use operands allowed in the current
@@ -365,14 +352,6 @@
<< " Profile specification"
<< " (or requires extension or capability)";
}
- } else if (env == SPV_ENV_WEBGPU_0) {
- if (!IsSupportGuaranteedWebGPU(capability) &&
- !IsEnabledByExtension(_, capability)) {
- return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
- << "Capability " << capability_str()
- << " is not allowed by WebGPU specification"
- << " (or requires extension)";
- }
}
return SPV_SUCCESS;
diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp
index 45edd0c..a5f6e6a 100644
--- a/source/val/validate_cfg.cpp
+++ b/source/val/validate_cfg.cpp
@@ -48,11 +48,11 @@
"basic blocks.";
}
- const Instruction* type_inst = _.FindDef(inst->type_id());
- assert(type_inst);
-
- const SpvOp type_opcode = type_inst->opcode();
- if (type_opcode == SpvOpTypePointer &&
+ if (_.IsVoidType(inst->type_id())) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "OpPhi must not have void result type";
+ }
+ if (_.IsPointerType(inst->type_id()) &&
_.addressing_model() == SpvAddressingModelLogical) {
if (!_.features().variable_pointers &&
!_.features().variable_pointers_storage_buffer) {
@@ -62,6 +62,10 @@
}
}
+ const Instruction* type_inst = _.FindDef(inst->type_id());
+ assert(type_inst);
+ const SpvOp type_opcode = type_inst->opcode();
+
if (!_.options()->before_hlsl_legalization) {
if (type_opcode == SpvOpTypeSampledImage ||
(_.HasCapability(SpvCapabilityShader) &&
@@ -816,120 +820,6 @@
return SPV_SUCCESS;
}
-spv_result_t PerformWebGPUCfgChecks(ValidationState_t& _, Function* function) {
- for (auto& block : function->ordered_blocks()) {
- if (block->reachable()) continue;
- if (block->is_type(kBlockTypeMerge)) {
- // 1. Find the referencing merge and confirm that it is reachable.
- BasicBlock* merge_header = function->GetMergeHeader(block);
- assert(merge_header != nullptr);
- if (!merge_header->reachable()) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable merge-blocks must be referenced by "
- "a reachable merge instruction.";
- }
-
- // 2. Check that the only instructions are OpLabel and OpUnreachable.
- auto* label_inst = block->label();
- auto* terminator_inst = block->terminator();
- assert(label_inst != nullptr);
- assert(terminator_inst != nullptr);
-
- if (terminator_inst->opcode() != SpvOpUnreachable) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable merge-blocks must terminate with "
- "OpUnreachable.";
- }
-
- auto label_idx = label_inst - &_.ordered_instructions()[0];
- auto terminator_idx = terminator_inst - &_.ordered_instructions()[0];
- if (label_idx + 1 != terminator_idx) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable merge-blocks must only contain an "
- "OpLabel and OpUnreachable instruction.";
- }
-
- // 3. Use label instruction to confirm there is no uses by branches.
- for (auto use : label_inst->uses()) {
- const auto* use_inst = use.first;
- if (spvOpcodeIsBranch(use_inst->opcode())) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable merge-blocks cannot be the target "
- "of a branch.";
- }
- }
- } else if (block->is_type(kBlockTypeContinue)) {
- // 1. Find referencing loop and confirm that it is reachable.
- std::vector<BasicBlock*> continue_headers =
- function->GetContinueHeaders(block);
- if (continue_headers.empty()) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable continue-target must be referenced "
- "by a loop instruction.";
- }
-
- std::vector<BasicBlock*> reachable_headers(continue_headers.size());
- auto iter =
- std::copy_if(continue_headers.begin(), continue_headers.end(),
- reachable_headers.begin(),
- [](BasicBlock* header) { return header->reachable(); });
- reachable_headers.resize(std::distance(reachable_headers.begin(), iter));
-
- if (reachable_headers.empty()) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable continue-target must be referenced "
- "by a reachable loop instruction.";
- }
-
- // 2. Check that the only instructions are OpLabel and OpBranch.
- auto* label_inst = block->label();
- auto* terminator_inst = block->terminator();
- assert(label_inst != nullptr);
- assert(terminator_inst != nullptr);
-
- if (terminator_inst->opcode() != SpvOpBranch) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable continue-target must terminate with "
- "OpBranch.";
- }
-
- auto label_idx = label_inst - &_.ordered_instructions()[0];
- auto terminator_idx = terminator_inst - &_.ordered_instructions()[0];
- if (label_idx + 1 != terminator_idx) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable continue-target must only contain "
- "an OpLabel and an OpBranch instruction.";
- }
-
- // 3. Use label instruction to confirm there is no uses by branches.
- for (auto use : label_inst->uses()) {
- const auto* use_inst = use.first;
- if (spvOpcodeIsBranch(use_inst->opcode())) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable continue-target cannot be the "
- "target of a branch.";
- }
- }
-
- // 4. Confirm that continue-target has a back edge to a reachable loop
- // header block.
- auto branch_target = terminator_inst->GetOperandAs<uint32_t>(0);
- for (auto* continue_header : reachable_headers) {
- if (branch_target != continue_header->id()) {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, unreachable continue-target must only have a "
- "back edge to a single reachable loop instruction.";
- }
- }
- } else {
- return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id()))
- << "For WebGPU, all blocks must be reachable, unless they are "
- << "degenerate cases of merge-block or continue-target.";
- }
- }
- return SPV_SUCCESS;
-}
-
spv_result_t PerformCfgChecks(ValidationState_t& _) {
for (auto& function : _.functions()) {
// Check all referenced blocks are defined within a function
@@ -1010,13 +900,6 @@
<< _.getIdName(idom->id());
}
}
-
- // For WebGPU check that all unreachable blocks are degenerate cases for
- // merge-block or continue-target.
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- spv_result_t result = PerformWebGPUCfgChecks(_, &function);
- if (result != SPV_SUCCESS) return result;
- }
}
// If we have structed control flow, check that no block has a control
// flow nesting depth larger than the limit.
diff --git a/source/val/validate_composites.cpp b/source/val/validate_composites.cpp
index eb8a324..5d6c5e3 100644
--- a/source/val/validate_composites.cpp
+++ b/source/val/validate_composites.cpp
@@ -437,6 +437,10 @@
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Result Type and Operand type to be the same";
}
+ if (_.IsVoidType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "OpCopyObject cannot have void result type";
+ }
return SPV_SUCCESS;
}
@@ -531,12 +535,10 @@
}
// All Component literals must either be FFFFFFFF or in [0, N - 1].
- // For WebGPU specifically, Component literals cannot be FFFFFFFF.
auto vector1ComponentCount = vector1Type->GetOperandAs<uint32_t>(2);
auto vector2ComponentCount = vector2Type->GetOperandAs<uint32_t>(2);
auto N = vector1ComponentCount + vector2ComponentCount;
auto firstLiteralIndex = 4;
- const auto is_webgpu_env = spvIsWebGPUEnv(_.context()->target_env);
for (size_t i = firstLiteralIndex; i < inst->operands().size(); ++i) {
auto literal = inst->GetOperandAs<uint32_t>(i);
if (literal != 0xFFFFFFFF && literal >= N) {
@@ -544,12 +546,6 @@
<< "Component index " << literal << " is out of bounds for "
<< "combined (Vector1 + Vector2) size of " << N << ".";
}
-
- if (is_webgpu_env && literal == 0xFFFFFFFF) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "Component literal at operand " << i - firstLiteralIndex
- << " cannot be 0xFFFFFFFF in WebGPU execution environment.";
- }
}
if (_.HasCapability(SpvCapabilityShader) &&
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index d381276..01b0eca 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -1260,7 +1260,8 @@
// decorations. Otherwise emits a diagnostic and returns something other than
// SPV_SUCCESS.
spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate,
- const Instruction& inst) {
+ const Instruction& inst,
+ const Decoration& decoration) {
// Validates width-only conversion instruction for floating-point object
// i.e., OpFConvert
if (inst.opcode() != SpvOpFConvert) {
@@ -1270,6 +1271,15 @@
"object.";
}
+ if (spvIsVulkanEnv(vstate.context()->target_env)) {
+ const auto mode = decoration.params()[0];
+ if ((mode != SpvFPRoundingModeRTE) && (mode != SpvFPRoundingModeRTZ)) {
+ return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
+ << vstate.VkErrorID(4675)
+ << "In Vulkan, the FPRoundingMode mode must only by RTE or RTZ.";
+ }
+ }
+
// Validates Object operand of an OpStore
for (const auto& use : inst.uses()) {
const auto store = use.first;
@@ -1588,7 +1598,8 @@
break;
case SpvDecorationFPRoundingMode:
if (is_shader)
- PASS_OR_BAIL(CheckFPRoundingModeForShaders(vstate, *inst));
+ PASS_OR_BAIL(
+ CheckFPRoundingModeForShaders(vstate, *inst, decoration));
break;
case SpvDecorationNonWritable:
PASS_OR_BAIL(CheckNonWritableDecoration(vstate, *inst, decoration));
diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp
index 17b0446..af6ae2b 100644
--- a/source/val/validate_extensions.cpp
+++ b/source/val/validate_extensions.cpp
@@ -685,34 +685,9 @@
} // anonymous namespace
-spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- std::string extension = GetExtensionString(&(inst->c_inst()));
-
- if (extension != ExtensionToString(kSPV_KHR_vulkan_memory_model)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "For WebGPU, the only valid parameter to OpExtension is "
- << "\"" << ExtensionToString(kSPV_KHR_vulkan_memory_model)
- << "\".";
- }
- }
-
- return SPV_SUCCESS;
-}
-
spv_result_t ValidateExtInstImport(ValidationState_t& _,
const Instruction* inst) {
const auto name_id = 1;
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- const std::string name(reinterpret_cast<const char*>(
- inst->words().data() + inst->operands()[name_id].offset));
- if (name != "GLSL.std.450") {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "For WebGPU, the only valid parameter to OpExtInstImport is "
- "\"GLSL.std.450\".";
- }
- }
-
if (!_.HasExtension(kSPV_KHR_non_semantic_info)) {
const std::string name(reinterpret_cast<const char*>(
inst->words().data() + inst->operands()[name_id].offset));
@@ -3149,7 +3124,6 @@
spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) {
const SpvOp opcode = inst->opcode();
- if (opcode == SpvOpExtension) return ValidateExtension(_, inst);
if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst);
if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst);
diff --git a/source/val/validate_id.cpp b/source/val/validate_id.cpp
index e1a775a..2bab203 100644
--- a/source/val/validate_id.cpp
+++ b/source/val/validate_id.cpp
@@ -201,7 +201,7 @@
ret = SPV_SUCCESS;
}
} else if (can_have_forward_declared_ids(i)) {
- if (inst->opcode() == SpvOpTypeStruct &&
+ if (spvOpcodeGeneratesType(inst->opcode()) &&
!_.IsForwardPointer(operand_word)) {
ret = _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Operand " << _.getIdName(operand_word)
diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp
index 299a3ef..fc37f08 100644
--- a/source/val/validate_image.cpp
+++ b/source/val/validate_image.cpp
@@ -16,8 +16,6 @@
// Validates correctness of image instructions.
-#include "source/val/validate.h"
-
#include <string>
#include "source/diagnostic.h"
@@ -25,6 +23,7 @@
#include "source/spirv_target_env.h"
#include "source/util/bitutils.h"
#include "source/val/instruction.h"
+#include "source/val/validate.h"
#include "source/val/validate_scopes.h"
#include "source/val/validation_state.h"
@@ -234,9 +233,10 @@
}
// Checks ImageOperand bitfield and respective operands.
+// word_index is the index of the first word after the image-operand mask word.
spv_result_t ValidateImageOperands(ValidationState_t& _,
const Instruction* inst,
- const ImageTypeInfo& info, uint32_t mask,
+ const ImageTypeInfo& info,
uint32_t word_index) {
static const bool kAllImageOperandsHandled = CheckAllImageOperandsHandled();
(void)kAllImageOperandsHandled;
@@ -244,24 +244,43 @@
const SpvOp opcode = inst->opcode();
const size_t num_words = inst->words().size();
- // NonPrivate, Volatile, SignExtend, ZeroExtend take no operand words.
- const uint32_t mask_bits_having_operands =
- mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask |
- SpvImageOperandsVolatileTexelKHRMask |
- SpvImageOperandsSignExtendMask |
- SpvImageOperandsZeroExtendMask);
- size_t expected_num_image_operand_words =
- spvtools::utils::CountSetBits(mask_bits_having_operands);
- if (mask & SpvImageOperandsGradMask) {
- // Grad uses two words.
- ++expected_num_image_operand_words;
- }
+ const bool have_explicit_mask = (word_index - 1 < num_words);
+ const uint32_t mask = have_explicit_mask ? inst->word(word_index - 1) : 0u;
- if (expected_num_image_operand_words != num_words - word_index) {
+ if (have_explicit_mask) {
+ // NonPrivate, Volatile, SignExtend, ZeroExtend take no operand words.
+ const uint32_t mask_bits_having_operands =
+ mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask |
+ SpvImageOperandsVolatileTexelKHRMask |
+ SpvImageOperandsSignExtendMask |
+ SpvImageOperandsZeroExtendMask);
+ size_t expected_num_image_operand_words =
+ spvtools::utils::CountSetBits(mask_bits_having_operands);
+ if (mask & SpvImageOperandsGradMask) {
+ // Grad uses two words.
+ ++expected_num_image_operand_words;
+ }
+
+ if (expected_num_image_operand_words != num_words - word_index) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Number of image operand ids doesn't correspond to the bit "
+ "mask";
+ }
+ } else if (num_words != word_index - 1) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Number of image operand ids doesn't correspond to the bit mask";
}
+ if (info.multisampled & (0 == (mask & SpvImageOperandsSampleMask))) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Image Operand Sample is required for operation on "
+ "multi-sampled image";
+ }
+
+ // After this point, only set bits in the image operands mask can cause
+ // the module to be invalid.
+ if (mask == 0) return SPV_SUCCESS;
+
if (spvtools::utils::CountSetBits(
mask & (SpvImageOperandsOffsetMask | SpvImageOperandsConstOffsetMask |
SpvImageOperandsConstOffsetsMask)) > 1) {
@@ -296,10 +315,7 @@
"or Cube";
}
- if (info.multisampled != 0) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Image Operand Bias requires 'MS' parameter to be 0";
- }
+ // Multisampled is already checked.
}
if (mask & SpvImageOperandsLodMask) {
@@ -338,10 +354,7 @@
"or Cube";
}
- if (info.multisampled != 0) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Image Operand Lod requires 'MS' parameter to be 0";
- }
+ // Multisampled is already checked.
}
if (mask & SpvImageOperandsGradMask) {
@@ -374,10 +387,7 @@
<< " components, but given " << dy_size;
}
- if (info.multisampled != 0) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Image Operand Grad requires 'MS' parameter to be 0";
- }
+ // Multisampled is already checked.
}
if (mask & SpvImageOperandsConstOffsetMask) {
@@ -613,12 +623,12 @@
if (info.multisampled != 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Image Image 'MS' parameter to be 0";
+ << "Expected Image 'MS' parameter to be 0";
}
if (info.arrayed != 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Image Image 'arrayed' parameter to be 0";
+ << "Expected Image 'arrayed' parameter to be 0";
}
}
@@ -736,17 +746,28 @@
<< "Corrupt image type definition";
}
- if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (_.IsIntScalarType(info.sampled_type) &&
+ (64 == _.GetBitWidth(info.sampled_type)) &&
+ !_.HasCapability(SpvCapabilityInt64ImageEXT)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Capability Int64ImageEXT is required when using Sampled Type of "
+ "64-bit int";
+ }
+
+ const auto target_env = _.context()->target_env;
+ if (spvIsVulkanEnv(target_env)) {
if ((!_.IsFloatScalarType(info.sampled_type) &&
!_.IsIntScalarType(info.sampled_type)) ||
- (32 != _.GetBitWidth(info.sampled_type) &&
- (64 != _.GetBitWidth(info.sampled_type) ||
- !_.HasCapability(SpvCapabilityInt64ImageEXT)))) {
+ ((32 != _.GetBitWidth(info.sampled_type)) &&
+ (64 != _.GetBitWidth(info.sampled_type))) ||
+ ((64 == _.GetBitWidth(info.sampled_type)) &&
+ _.IsFloatScalarType(info.sampled_type))) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected Sampled Type to be a 32-bit int or float "
- "scalar type for Vulkan environment";
+ << _.VkErrorID(4656)
+ << "Expected Sampled Type to be a 32-bit int, 64-bit int or "
+ "32-bit float scalar type for Vulkan environment";
}
- } else if (spvIsOpenCLEnv(_.context()->target_env)) {
+ } else if (spvIsOpenCLEnv(target_env)) {
if (!_.IsVoidType(info.sampled_type)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Sampled Type must be OpTypeVoid in the OpenCL environment.";
@@ -774,7 +795,7 @@
<< "Invalid Arrayed " << info.arrayed << " (must be 0 or 1)";
}
- if (spvIsOpenCLEnv(_.context()->target_env)) {
+ if (spvIsOpenCLEnv(target_env)) {
if ((info.arrayed == 1) && (info.dim != SpvDim1D) &&
(info.dim != SpvDim2D)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -788,10 +809,10 @@
<< "Invalid MS " << info.multisampled << " (must be 0 or 1)";
}
- if (spvIsOpenCLEnv(_.context()->target_env)) {
+ if (spvIsOpenCLEnv(target_env)) {
if (info.multisampled != 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "MS must be 0 in the OpenCL environement.";
+ << "MS must be 0 in the OpenCL environment.";
}
}
@@ -800,6 +821,14 @@
<< "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)";
}
+ if (spvIsVulkanEnv(target_env)) {
+ if (info.sampled == 0) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4657)
+ << "Sampled must be 1 or 2 in the Vulkan environment.";
+ }
+ }
+
if (spvIsOpenCLEnv(_.context()->target_env)) {
if (info.sampled != 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -829,6 +858,15 @@
}
}
+ if (info.multisampled && (info.sampled == 2) &&
+ (info.dim != SpvDimSubpassData)) {
+ if (!_.HasCapability(SpvCapabilityStorageImageMultisample)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Capability StorageImageMultisample is required when using "
+ "multisampled storage image";
+ }
+ }
+
return SPV_SUCCESS;
}
@@ -839,6 +877,20 @@
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Image to be of type OpTypeImage";
}
+
+ ImageTypeInfo info;
+ if (!GetImageTypeInfo(_, image_type, &info)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Corrupt image type definition";
+ }
+ // OpenCL requires Sampled=0, checked elsewhere.
+ // Vulkan uses the Sampled=1 case.
+ if ((info.sampled != 0) && (info.sampled != 1)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Sampled image type requires an image type with \"Sampled\" "
+ "operand set to 0 or 1";
+ }
+
return SPV_SUCCESS;
}
@@ -1066,6 +1118,20 @@
"the value 0";
}
}
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if ((info.format != SpvImageFormatR64i) &&
+ (info.format != SpvImageFormatR64ui) &&
+ (info.format != SpvImageFormatR32f) &&
+ (info.format != SpvImageFormatR32i) &&
+ (info.format != SpvImageFormatR32ui)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4658)
+ << "Expected the Image Format in Image to be R64i, R64ui, R32f, "
+ "R32i, or R32ui for Vulkan environment";
+ }
+ }
+
return SPV_SUCCESS;
}
@@ -1103,6 +1169,14 @@
if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
+ if (info.multisampled) {
+ // When using image operands, the Sample image operand is required if and
+ // only if the image is multisampled (MS=1). The Sample image operand is
+ // only allowed for fetch, read, and write.
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Sampling operation is invalid for multisample image";
+ }
+
if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
const uint32_t texel_component_type =
_.GetComponentType(actual_result_type);
@@ -1137,16 +1211,11 @@
<< " components, but given only " << actual_coord_size;
}
- if (inst->words().size() <= 5) {
- assert(IsImplicitLod(opcode));
- return SPV_SUCCESS;
- }
+ const uint32_t mask = inst->words().size() <= 5 ? 0 : inst->word(5);
- const uint32_t mask = inst->word(5);
-
- if (spvIsOpenCLEnv(_.context()->target_env)) {
- if (opcode == SpvOpImageSampleExplicitLod) {
- if (mask & SpvImageOperandsConstOffsetMask) {
+ if (mask & SpvImageOperandsConstOffsetMask) {
+ if (spvIsOpenCLEnv(_.context()->target_env)) {
+ if (opcode == SpvOpImageSampleExplicitLod) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "ConstOffset image operand not allowed "
<< "in the OpenCL environment.";
@@ -1155,7 +1224,7 @@
}
if (spv_result_t result =
- ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6))
+ ValidateImageOperands(_, inst, info, /* word_index = */ 6))
return result;
return SPV_SUCCESS;
@@ -1190,6 +1259,14 @@
if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
+ if (info.multisampled) {
+ // When using image operands, the Sample image operand is required if and
+ // only if the image is multisampled (MS=1). The Sample image operand is
+ // only allowed for fetch, read, and write.
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Dref sampling operation is invalid for multisample image";
+ }
+
if (actual_result_type != info.sampled_type) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Image 'Sampled Type' to be the same as "
@@ -1216,14 +1293,8 @@
<< "Expected Dref to be of 32-bit float type";
}
- if (inst->words().size() <= 6) {
- assert(IsImplicitLod(opcode));
- return SPV_SUCCESS;
- }
-
- const uint32_t mask = inst->word(6);
if (spv_result_t result =
- ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7))
+ ValidateImageOperands(_, inst, info, /* word_index = */ 7))
return result;
return SPV_SUCCESS;
@@ -1294,11 +1365,8 @@
<< " components, but given only " << actual_coord_size;
}
- if (inst->words().size() <= 5) return SPV_SUCCESS;
-
- const uint32_t mask = inst->word(5);
if (spv_result_t result =
- ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6))
+ ValidateImageOperands(_, inst, info, /* word_index = */ 6))
return result;
return SPV_SUCCESS;
@@ -1336,6 +1404,14 @@
<< "Corrupt image type definition";
}
+ if (info.multisampled) {
+ // When using image operands, the Sample image operand is required if and
+ // only if the image is multisampled (MS=1). The Sample image operand is
+ // only allowed for fetch, read, and write.
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Gather operation is invalid for multisample image";
+ }
+
if (opcode == SpvOpImageDrefGather || opcode == SpvOpImageSparseDrefGather ||
_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
const uint32_t result_component_type =
@@ -1384,11 +1460,8 @@
}
}
- if (inst->words().size() <= 6) return SPV_SUCCESS;
-
- const uint32_t mask = inst->word(6);
if (spv_result_t result =
- ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7))
+ ValidateImageOperands(_, inst, info, /* word_index = */ 7))
return result;
return SPV_SUCCESS;
@@ -1408,14 +1481,16 @@
<< " to be int or float scalar or vector type";
}
-#if 0
- // TODO(atgoo@github.com) Disabled until the spec is clarified.
- if (_.GetDimension(actual_result_type) != 4) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected " << GetActualResultTypeStr(opcode)
- << " to have 4 components";
- }
-#endif
+ const auto target_env = _.context()->target_env;
+ // Vulkan requires the result to be a 4-element int or float
+ // vector.
+ if (spvIsVulkanEnv(target_env)) {
+ if (_.GetDimension(actual_result_type) != 4) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected " << GetActualResultTypeStr(opcode)
+ << " to have 4 components";
+ }
+ } // Check OpenCL below, after we get the image info.
const uint32_t image_type = _.GetOperandTypeId(inst, 2);
if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
@@ -1429,6 +1504,29 @@
<< "Corrupt image type definition";
}
+ if (spvIsOpenCLEnv(target_env)) {
+ // In OpenCL, a read from a depth image returns a scalar float. In other
+ // cases, the result is always a 4-element vector.
+ // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_Env.html#_data_format_for_reading_and_writing_images
+ // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_C.html#image-read-and-write-functions
+ // The builtins for reading depth images are:
+ // float read_imagef(aQual image2d_depth_t image, int2 coord)
+ // float read_imagef(aQual image2d_array_depth_t image, int4 coord)
+ if (info.depth) {
+ if (!_.IsFloatScalarType(actual_result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected " << GetActualResultTypeStr(opcode)
+ << " from a depth image read to result in a scalar float value";
+ }
+ } else {
+ if (_.GetDimension(actual_result_type) != 4) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected " << GetActualResultTypeStr(opcode)
+ << " to have 4 components";
+ }
+ }
+ }
+
if (info.dim == SpvDimSubpassData) {
if (opcode == SpvOpImageSparseRead) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -1477,12 +1575,10 @@
}
}
- if (inst->words().size() <= 5) return SPV_SUCCESS;
+ const uint32_t mask = inst->words().size() <= 5 ? 0 : inst->word(5);
- const uint32_t mask = inst->word(5);
-
- if (spvIsOpenCLEnv(_.context()->target_env)) {
- if (mask & SpvImageOperandsConstOffsetMask) {
+ if (mask & SpvImageOperandsConstOffsetMask) {
+ if (spvIsOpenCLEnv(_.context()->target_env)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "ConstOffset image operand not allowed "
<< "in the OpenCL environment.";
@@ -1490,7 +1586,7 @@
}
if (spv_result_t result =
- ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6))
+ ValidateImageOperands(_, inst, info, /* word_index = */ 6))
return result;
return SPV_SUCCESS;
@@ -1566,9 +1662,7 @@
}
}
- if (inst->words().size() <= 4) {
- return SPV_SUCCESS;
- } else {
+ if (inst->words().size() > 4) {
if (spvIsOpenCLEnv(_.context()->target_env)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Optional Image Operands are not allowed in the OpenCL "
@@ -1576,9 +1670,8 @@
}
}
- const uint32_t mask = inst->word(4);
if (spv_result_t result =
- ValidateImageOperands(_, inst, info, mask, /* word_index = */ 5))
+ ValidateImageOperands(_, inst, info, /* word_index = */ 5))
return result;
return SPV_SUCCESS;
@@ -1649,6 +1742,16 @@
return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'MS' must be 0";
}
+ const auto target_env = _.context()->target_env;
+ if (spvIsVulkanEnv(target_env)) {
+ if (info.sampled != 1) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4659)
+ << "OpImageQuerySizeLod must only consume an \"Image\" operand "
+ "whose type has its \"Sampled\" operand set to 1";
+ }
+ }
+
uint32_t result_num_components = _.GetDimension(result_type);
if (result_num_components != expected_num_components) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -1823,6 +1926,13 @@
<< "Expected Coordinate to have at least " << min_coord_size
<< " components, but given only " << actual_coord_size;
}
+
+ // The operad is a sampled image.
+ // The sampled image type is already checked to be parameterized by an image
+ // type with Sampled=0 or Sampled=1. Vulkan bans Sampled=0, and so we have
+ // Sampled=1. So the validator already enforces Vulkan VUID 4659:
+ // OpImageQuerySizeLod must only consume an “Image” operand whose type has
+ // its "Sampled" operand set to 1
return SPV_SUCCESS;
}
@@ -1859,6 +1969,15 @@
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Image 'Dim' must be 1D, 2D, 3D or Cube";
}
+ const auto target_env = _.context()->target_env;
+ if (spvIsVulkanEnv(target_env)) {
+ if (info.sampled != 1) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4659)
+ << "OpImageQueryLevels must only consume an \"Image\" operand "
+ "whose type has its \"Sampled\" operand set to 1";
+ }
+ }
} else {
assert(opcode == SpvOpImageQuerySamples);
if (info.dim != SpvDim2D) {
diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp
index d9f8b99..45a232d 100644
--- a/source/val/validate_memory.cpp
+++ b/source/val/validate_memory.cpp
@@ -578,14 +578,15 @@
}
}
- // WebGPU & Vulkan Appendix A: Check that if contains initializer, then
+ // Vulkan Appendix A: Check that if contains initializer, then
// storage class is Output, Private, or Function.
if (inst->operands().size() > 3 && storage_class != SpvStorageClassOutput &&
storage_class != SpvStorageClassPrivate &&
storage_class != SpvStorageClassFunction) {
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
+ if (spvIsVulkanEnv(_.context()->target_env)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpVariable, <id> '" << _.getIdName(inst->id())
+ << _.VkErrorID(4651) << "OpVariable, <id> '"
+ << _.getIdName(inst->id())
<< "', has a disallowed initializer & storage class "
<< "combination.\n"
<< "From " << spvLogStringForEnv(_.context()->target_env)
@@ -596,20 +597,6 @@
}
}
- // WebGPU: All variables with storage class Output, Private, or Function MUST
- // have an initializer.
- if (spvIsWebGPUEnv(_.context()->target_env) && inst->operands().size() <= 3 &&
- (storage_class == SpvStorageClassOutput ||
- storage_class == SpvStorageClassPrivate ||
- storage_class == SpvStorageClassFunction)) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpVariable, <id> '" << _.getIdName(inst->id())
- << "', must have an initializer.\n"
- << "From WebGPU execution environment spec:\n"
- << "All variables in the following storage classes must have an "
- << "initializer: Output, Private, or Function";
- }
-
if (storage_class == SpvStorageClassPhysicalStorageBufferEXT) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "PhysicalStorageBufferEXT must not be used with OpVariable.";
@@ -702,41 +689,6 @@
}
}
- // WebGPU specific validation rules for OpTypeRuntimeArray
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- // OpTypeRuntimeArray should only ever be in an OpTypeStruct,
- // so should never appear as a bare variable.
- if (value_type && value_type->opcode() == SpvOpTypeRuntimeArray) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpVariable, <id> '" << _.getIdName(inst->id())
- << "', is attempting to create memory for an illegal type, "
- << "OpTypeRuntimeArray.\nFor WebGPU OpTypeRuntimeArray can only "
- << "appear as the final member of an OpTypeStruct, thus cannot "
- << "be instantiated via OpVariable";
- }
-
- // If an OpStruct has an OpTypeRuntimeArray somewhere within it, then it
- // must have the storage class StorageBuffer and be decorated
- // with Block.
- if (value_type && value_type->opcode() == SpvOpTypeStruct) {
- if (DoesStructContainRTA(_, value_type)) {
- if (storage_class == SpvStorageClassStorageBuffer) {
- if (!_.HasDecoration(value_id, SpvDecorationBlock)) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "For WebGPU, an OpTypeStruct variable containing an "
- << "OpTypeRuntimeArray must be decorated with Block if it "
- << "has storage class StorageBuffer.";
- }
- } else {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "For WebGPU, OpTypeStruct variables containing "
- << "OpTypeRuntimeArray must have storage class of "
- << "StorageBuffer";
- }
- }
- }
- }
-
// Cooperative matrix types can only be allocated in Function or Private
if ((storage_class != SpvStorageClassFunction &&
storage_class != SpvStorageClassPrivate) &&
diff --git a/source/val/validate_memory_semantics.cpp b/source/val/validate_memory_semantics.cpp
index 4c582f0..8e47f8a 100644
--- a/source/val/validate_memory_semantics.cpp
+++ b/source/val/validate_memory_semantics.cpp
@@ -56,55 +56,6 @@
return SPV_SUCCESS;
}
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- uint32_t valid_bits;
- switch (inst->opcode()) {
- case SpvOpControlBarrier:
- if (!(value & SpvMemorySemanticsAcquireReleaseMask)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "For WebGPU, AcquireRelease must be set for Memory "
- "Semantics of OpControlBarrier.";
- }
-
- if (!(value & SpvMemorySemanticsWorkgroupMemoryMask)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "For WebGPU, WorkgroupMemory must be set for Memory "
- "Semantics of OpControlBarrier.";
- }
-
- valid_bits = SpvMemorySemanticsAcquireReleaseMask |
- SpvMemorySemanticsWorkgroupMemoryMask;
- if (value & ~valid_bits) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "For WebGPU only WorkgroupMemory and AcquireRelease may be "
- "set for Memory Semantics of OpControlBarrier.";
- }
- break;
- case SpvOpMemoryBarrier:
- if (!(value & SpvMemorySemanticsImageMemoryMask)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "For WebGPU, ImageMemory must be set for Memory Semantics "
- "of OpMemoryBarrier.";
- }
- valid_bits = SpvMemorySemanticsImageMemoryMask;
- if (value & ~valid_bits) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "For WebGPU only ImageMemory may be set for Memory "
- "Semantics of OpMemoryBarrier.";
- }
- break;
- default:
- if (spvOpcodeIsAtomicOp(inst->opcode())) {
- if (value != 0) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "For WebGPU Memory no bits may be set for Memory "
- "Semantics of OpAtomic* instructions.";
- }
- }
- break;
- }
- }
-
const size_t num_memory_order_set_bits = spvtools::utils::CountSetBits(
value & (SpvMemorySemanticsAcquireMask | SpvMemorySemanticsReleaseMask |
SpvMemorySemanticsAcquireReleaseMask |
@@ -221,7 +172,7 @@
if (opcode == SpvOpMemoryBarrier && !num_memory_order_set_bits) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4649) << spvOpcodeString(opcode)
<< ": Vulkan specification requires Memory Semantics to have "
"one "
"of the following bits set: Acquire, Release, "
@@ -231,7 +182,7 @@
if (opcode == SpvOpMemoryBarrier && !includes_storage_class) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4649) << spvOpcodeString(opcode)
<< ": expected Memory Semantics to include a Vulkan-supported "
"storage class";
}
diff --git a/source/val/validate_misc.cpp b/source/val/validate_misc.cpp
index f0deedf..0c30f3c 100644
--- a/source/val/validate_misc.cpp
+++ b/source/val/validate_misc.cpp
@@ -26,6 +26,10 @@
namespace {
spv_result_t ValidateUndef(ValidationState_t& _, const Instruction* inst) {
+ if (_.IsVoidType(inst->type_id())) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "Cannot create undefined values with void type";
+ }
if (_.HasCapability(SpvCapabilityShader) &&
_.ContainsLimitedUseIntOrFloatType(inst->type_id()) &&
!_.IsPointerType(inst->type_id())) {
@@ -33,10 +37,6 @@
<< "Cannot create undefined values with 8- or 16-bit types";
}
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- return _.diag(SPV_ERROR_INVALID_BINARY, inst) << "OpUndef is disallowed";
- }
-
return SPV_SUCCESS;
}
@@ -52,7 +52,7 @@
std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope);
if (is_const_int32 && value != SpvScopeSubgroup && value != SpvScopeDevice) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Scope must be Subgroup or Device";
+ << _.VkErrorID(4652) << "Scope must be Subgroup or Device";
}
// Result Type must be a 64 - bit unsigned integer type or
diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp
index a7f8d33..c816b75 100644
--- a/source/val/validate_mode_setting.cpp
+++ b/source/val/validate_mode_setting.cpp
@@ -42,7 +42,8 @@
const auto entry_point_type = _.FindDef(entry_point_type_id);
if (!entry_point_type || 3 != entry_point_type->words().size()) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpEntryPoint Entry Point <id> '" << _.getIdName(entry_point_id)
+ << _.VkErrorID(4633) << "OpEntryPoint Entry Point <id> '"
+ << _.getIdName(entry_point_id)
<< "'s function parameter count is not zero.";
}
}
@@ -50,7 +51,8 @@
auto return_type = _.FindDef(entry_point->type_id());
if (!return_type || SpvOpTypeVoid != return_type->opcode()) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpEntryPoint Entry Point <id> '" << _.getIdName(entry_point_id)
+ << _.VkErrorID(4633) << "OpEntryPoint Entry Point <id> '"
+ << _.getIdName(entry_point_id)
<< "'s function return type is not void.";
}
@@ -457,31 +459,18 @@
if (spvIsVulkanEnv(_.context()->target_env)) {
if (mode == SpvExecutionModeOriginLowerLeft) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4653)
<< "In the Vulkan environment, the OriginLowerLeft execution mode "
"must not be used.";
}
if (mode == SpvExecutionModePixelCenterInteger) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4654)
<< "In the Vulkan environment, the PixelCenterInteger execution "
"mode must not be used.";
}
}
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- if (mode != SpvExecutionModeOriginUpperLeft &&
- mode != SpvExecutionModeDepthReplacing &&
- mode != SpvExecutionModeDepthGreater &&
- mode != SpvExecutionModeDepthLess &&
- mode != SpvExecutionModeDepthUnchanged &&
- mode != SpvExecutionModeLocalSize &&
- mode != SpvExecutionModeLocalSizeHint) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Execution mode must be one of OriginUpperLeft, "
- "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, "
- "LocalSize, or LocalSizeHint for WebGPU environment.";
- }
- }
-
return SPV_SUCCESS;
}
@@ -496,13 +485,6 @@
"the VulkanKHR memory model is used.";
}
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- if (_.addressing_model() != SpvAddressingModelLogical) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Addressing model must be Logical for WebGPU environment.";
- }
- }
-
if (spvIsOpenCLEnv(_.context()->target_env)) {
if ((_.addressing_model() != SpvAddressingModelPhysical32) &&
(_.addressing_model() != SpvAddressingModelPhysical64)) {
@@ -516,6 +498,15 @@
}
}
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if ((_.addressing_model() != SpvAddressingModelLogical) &&
+ (_.addressing_model() != SpvAddressingModelPhysicalStorageBuffer64)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4635)
+ << "Addressing model must be Logical or PhysicalStorageBuffer64 "
+ << "in the Vulkan environment.";
+ }
+ }
return SPV_SUCCESS;
}
diff --git a/source/val/validate_non_uniform.cpp b/source/val/validate_non_uniform.cpp
index 8dcf974..2b6eb8b 100644
--- a/source/val/validate_non_uniform.cpp
+++ b/source/val/validate_non_uniform.cpp
@@ -47,6 +47,19 @@
"vector of four components "
"of integer type scalar";
}
+
+ const auto group = inst->GetOperandAs<uint32_t>(3);
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if ((group != SpvGroupOperationReduce) &&
+ (group != SpvGroupOperationInclusiveScan) &&
+ (group != SpvGroupOperationExclusiveScan)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4685)
+ << "In Vulkan: The OpGroupNonUniformBallotBitCount group "
+ "operation must be only: Reduce, InclusiveScan, or "
+ "ExclusiveScan.";
+ }
+ }
return SPV_SUCCESS;
}
diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp
index a6fb26d..a92f7fd 100644
--- a/source/val/validate_scopes.cpp
+++ b/source/val/validate_scopes.cpp
@@ -99,7 +99,7 @@
if (spvOpcodeIsNonUniformGroupOperation(opcode) &&
value != SpvScopeSubgroup) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4642) << spvOpcodeString(opcode)
<< ": in Vulkan environment Execution scope is limited to "
<< "Subgroup";
}
@@ -137,30 +137,6 @@
}
}
- // WebGPU Specific rules
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- if (value != SpvScopeWorkgroup) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
- << ": in WebGPU environment Execution Scope is limited to "
- << "Workgroup";
- } else {
- _.function(inst->function()->id())
- ->RegisterExecutionModelLimitation(
- [](SpvExecutionModel model, std::string* message) {
- if (model != SpvExecutionModelGLCompute) {
- if (message) {
- *message =
- ": in WebGPU environment, Workgroup Execution Scope is "
- "limited to GLCompute execution model";
- }
- return false;
- }
- return true;
- });
- }
- }
-
// TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments.
// General SPIRV rules
@@ -214,7 +190,7 @@
if (spvIsVulkanEnv(_.context()->target_env)) {
if (value == SpvScopeCrossDevice) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4638) << spvOpcodeString(opcode)
<< ": in Vulkan environment, Memory Scope cannot be CrossDevice";
}
// Vulkan 1.0 specifc rules
@@ -222,7 +198,7 @@
value != SpvScopeDevice && value != SpvScopeWorkgroup &&
value != SpvScopeInvocation) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4638) << spvOpcodeString(opcode)
<< ": in Vulkan 1.0 environment Memory Scope is limited to "
<< "Device, Workgroup and Invocation";
}
@@ -233,15 +209,16 @@
value != SpvScopeSubgroup && value != SpvScopeInvocation &&
value != SpvScopeShaderCallKHR) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4638) << spvOpcodeString(opcode)
<< ": in Vulkan 1.1 and 1.2 environment Memory Scope is limited "
<< "to Device, Workgroup, Invocation, and ShaderCall";
}
if (value == SpvScopeShaderCallKHR) {
+ std::string errorVUID = _.VkErrorID(4640);
_.function(inst->function()->id())
->RegisterExecutionModelLimitation(
- [](SpvExecutionModel model, std::string* message) {
+ [errorVUID](SpvExecutionModel model, std::string* message) {
if (model != SpvExecutionModelRayGenerationKHR &&
model != SpvExecutionModelIntersectionKHR &&
model != SpvExecutionModelAnyHitKHR &&
@@ -250,6 +227,7 @@
model != SpvExecutionModelCallableKHR) {
if (message) {
*message =
+ errorVUID +
"ShaderCallKHR Memory Scope requires a ray tracing "
"execution model";
}
@@ -258,56 +236,19 @@
return true;
});
}
- }
-
- // WebGPU specific rules
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- switch (inst->opcode()) {
- case SpvOpControlBarrier:
- if (value != SpvScopeWorkgroup) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
- << ": in WebGPU environment Memory Scope is limited to "
- << "Workgroup for OpControlBarrier";
- }
- break;
- case SpvOpMemoryBarrier:
- if (value != SpvScopeWorkgroup) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
- << ": in WebGPU environment Memory Scope is limited to "
- << "Workgroup for OpMemoryBarrier";
- }
- break;
- default:
- if (spvOpcodeIsAtomicOp(inst->opcode())) {
- if (value != SpvScopeQueueFamilyKHR) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
- << ": in WebGPU environment Memory Scope is limited to "
- << "QueueFamilyKHR for OpAtomic* operations";
- }
- }
-
- if (value != SpvScopeWorkgroup && value != SpvScopeInvocation &&
- value != SpvScopeQueueFamilyKHR) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
- << ": in WebGPU environment Memory Scope is limited to "
- << "Workgroup, Invocation, and QueueFamilyKHR";
- }
- break;
- }
if (value == SpvScopeWorkgroup) {
+ std::string errorVUID = _.VkErrorID(4639);
_.function(inst->function()->id())
->RegisterExecutionModelLimitation(
- [](SpvExecutionModel model, std::string* message) {
- if (model != SpvExecutionModelGLCompute) {
+ [errorVUID](SpvExecutionModel model, std::string* message) {
+ if (model != SpvExecutionModelGLCompute &&
+ model != SpvExecutionModelTaskNV &&
+ model != SpvExecutionModelMeshNV) {
if (message) {
- *message =
- ": in WebGPU environment, Workgroup Memory Scope is "
- "limited to GLCompute execution model";
+ *message = errorVUID +
+ "Workgroup Memory Scope is limited to MeshNV, "
+ "TaskNV, and GLCompute execution model";
}
return false;
}
diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp
index 5924c69..6a5ea3c 100644
--- a/source/val/validate_type.cpp
+++ b/source/val/validate_type.cpp
@@ -40,21 +40,6 @@
return static_cast<int64_t>(uint64_t(lo_word) | uint64_t(hi_word) << 32);
}
-// Returns, as an uint64_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 ConstantLiteralAsUint64(uint32_t width,
- const std::vector<uint32_t>& const_words) {
- const uint32_t lo_word = const_words[3];
- if (width <= 32) return lo_word;
- assert(width <= 64);
- assert(const_words.size() > 4);
- const uint32_t hi_word = const_words[4]; // Must exist, per spec.
- return (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)
@@ -240,7 +225,7 @@
<< "' is a void type.";
}
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) &&
+ if (spvIsVulkanEnv(_.context()->target_env) &&
element_type->opcode() == SpvOpTypeRuntimeArray) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpTypeArray Element Type <id> '" << _.getIdName(element_type_id)
@@ -279,18 +264,6 @@
<< "OpTypeArray Length <id> '" << _.getIdName(length_id)
<< "' default value must be at least 1: found " << ivalue;
}
- if (spvIsWebGPUEnv(_.context()->target_env)) {
- // WebGPU has maximum integer width of 32 bits, and max array size
- // is one more than the max signed integer representation.
- const uint64_t max_permitted = (uint64_t(1) << 31);
- const uint64_t uvalue = ConstantLiteralAsUint64(width, length->words());
- if (uvalue > max_permitted) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpTypeArray Length <id> '" << _.getIdName(length_id)
- << "' size exceeds max value " << max_permitted
- << " permitted by WebGPU: got " << uvalue;
- }
- }
} break;
case SpvOpConstantNull:
return _.diag(SPV_ERROR_INVALID_ID, inst)
@@ -322,7 +295,7 @@
<< _.getIdName(element_id) << "' is a void type.";
}
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) &&
+ if (spvIsVulkanEnv(_.context()->target_env) &&
element_type->opcode() == SpvOpTypeRuntimeArray) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpTypeRuntimeArray Element Type <id> '"
@@ -394,7 +367,7 @@
<< ".";
}
- if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) &&
+ if (spvIsVulkanEnv(_.context()->target_env) &&
member_type->opcode() == SpvOpTypeRuntimeArray) {
const bool is_last_member =
member_type_index == inst->operands().size() - 1;
@@ -555,8 +528,8 @@
<< "Pointer type in OpTypeForwardPointer is not a pointer type.";
}
- if (inst->GetOperandAs<uint32_t>(1) !=
- pointer_type_inst->GetOperandAs<uint32_t>(1)) {
+ const auto storage_class = inst->GetOperandAs<SpvStorageClass>(1);
+ if (storage_class != pointer_type_inst->GetOperandAs<uint32_t>(1)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Storage class in OpTypeForwardPointer does not match the "
<< "pointer definition.";
@@ -569,6 +542,15 @@
<< "Forward pointers must point to a structure";
}
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (storage_class != SpvStorageClassPhysicalStorageBuffer) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(4711)
+ << "In Vulkan, OpTypeForwardPointer must have "
+ << "a storage class of PhysicalStorageBuffer.";
+ }
+ }
+
return SPV_SUCCESS;
}
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index cb69dda..b9269db 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -1240,23 +1240,6 @@
bool ValidationState_t::IsValidStorageClass(
SpvStorageClass storage_class) const {
- if (spvIsWebGPUEnv(context()->target_env)) {
- switch (storage_class) {
- case SpvStorageClassUniformConstant:
- case SpvStorageClassUniform:
- case SpvStorageClassStorageBuffer:
- case SpvStorageClassInput:
- case SpvStorageClassOutput:
- case SpvStorageClassImage:
- case SpvStorageClassWorkgroup:
- case SpvStorageClassPrivate:
- case SpvStorageClassFunction:
- return true;
- default:
- return false;
- }
- }
-
if (spvIsVulkanEnv(context()->target_env)) {
switch (storage_class) {
case SpvStorageClassUniformConstant:
@@ -1315,10 +1298,22 @@
return VUID_WRAP(VUID-BaseVertex-BaseVertex-04186);
case 4187:
return VUID_WRAP(VUID-ClipDistance-ClipDistance-04187);
+ case 4188:
+ return VUID_WRAP(VUID-ClipDistance-ClipDistance-04188);
+ case 4189:
+ return VUID_WRAP(VUID-ClipDistance-ClipDistance-04189);
+ case 4190:
+ return VUID_WRAP(VUID-ClipDistance-ClipDistance-04190);
case 4191:
return VUID_WRAP(VUID-ClipDistance-ClipDistance-04191);
case 4196:
return VUID_WRAP(VUID-CullDistance-CullDistance-04196);
+ case 4197:
+ return VUID_WRAP(VUID-CullDistance-CullDistance-04197);
+ case 4198:
+ return VUID_WRAP(VUID-CullDistance-CullDistance-04198);
+ case 4199:
+ return VUID_WRAP(VUID-CullDistance-CullDistance-04199);
case 4200:
return VUID_WRAP(VUID-CullDistance-CullDistance-04200);
case 4205:
@@ -1345,12 +1340,36 @@
return VUID_WRAP(VUID-FragDepth-FragDepth-04215);
case 4216:
return VUID_WRAP(VUID-FragDepth-FragDepth-04216);
+ case 4217:
+ return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217);
+ case 4218:
+ return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218);
+ case 4219:
+ return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219);
+ case 4220:
+ return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04220);
+ case 4221:
+ return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04221);
+ case 4222:
+ return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04222);
+ case 4223:
+ return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04223);
+ case 4224:
+ return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04224);
+ case 4225:
+ return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04225);
case 4229:
return VUID_WRAP(VUID-FrontFacing-FrontFacing-04229);
case 4230:
return VUID_WRAP(VUID-FrontFacing-FrontFacing-04230);
case 4231:
return VUID_WRAP(VUID-FrontFacing-FrontFacing-04231);
+ case 4232:
+ return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04232);
+ case 4233:
+ return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04233);
+ case 4234:
+ return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04234);
case 4236:
return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04236);
case 4237:
@@ -1363,6 +1382,36 @@
return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04240);
case 4241:
return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04241);
+ case 4242:
+ return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04242);
+ case 4243:
+ return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04243);
+ case 4244:
+ return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04244);
+ case 4245:
+ return VUID_WRAP(VUID-HitTNV-HitTNV-04245);
+ case 4246:
+ return VUID_WRAP(VUID-HitTNV-HitTNV-04246);
+ case 4247:
+ return VUID_WRAP(VUID-HitTNV-HitTNV-04247);
+ case 4248:
+ return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248);
+ case 4249:
+ return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249);
+ case 4250:
+ return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250);
+ case 4251:
+ return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04251);
+ case 4252:
+ return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04252);
+ case 4253:
+ return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04253);
+ case 4254:
+ return VUID_WRAP(VUID-InstanceId-InstanceId-04254);
+ case 4255:
+ return VUID_WRAP(VUID-InstanceId-InstanceId-04255);
+ case 4256:
+ return VUID_WRAP(VUID-InstanceId-InstanceId-04256);
case 4257:
return VUID_WRAP(VUID-InvocationId-InvocationId-04257);
case 4258:
@@ -1375,8 +1424,22 @@
return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04264);
case 4265:
return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04265);
+ case 4266:
+ return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04266);
+ case 4267:
+ return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04267);
+ case 4268:
+ return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04268);
+ case 4269:
+ return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04269);
+ case 4270:
+ return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04270);
+ case 4271:
+ return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04271);
case 4272:
return VUID_WRAP(VUID-Layer-Layer-04272);
+ case 4273:
+ return VUID_WRAP(VUID-Layer-Layer-04273);
case 4274:
return VUID_WRAP(VUID-Layer-Layer-04274);
case 4275:
@@ -1389,12 +1452,36 @@
return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04282);
case 4283:
return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04283);
+ case 4293:
+ return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04293);
+ case 4294:
+ return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04294);
+ case 4295:
+ return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04295);
case 4296:
return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04296);
case 4297:
return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04297);
case 4298:
return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04298);
+ case 4299:
+ return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04299);
+ case 4300:
+ return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04300);
+ case 4301:
+ return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04301);
+ case 4302:
+ return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04302);
+ case 4303:
+ return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04303);
+ case 4304:
+ return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04304);
+ case 4305:
+ return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04305);
+ case 4306:
+ return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04306);
+ case 4307:
+ return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04307);
case 4308:
return VUID_WRAP(VUID-PatchVertices-PatchVertices-04308);
case 4309:
@@ -1417,6 +1504,8 @@
return VUID_WRAP(VUID-PointSize-PointSize-04317);
case 4318:
return VUID_WRAP(VUID-Position-Position-04318);
+ case 4319:
+ return VUID_WRAP(VUID-Position-Position-04319);
case 4320:
return VUID_WRAP(VUID-Position-Position-04320);
case 4321:
@@ -1427,6 +1516,24 @@
return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334);
case 4337:
return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04337);
+ case 4345:
+ return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04345);
+ case 4346:
+ return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04346);
+ case 4347:
+ return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04347);
+ case 4348:
+ return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04348);
+ case 4349:
+ return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04349);
+ case 4350:
+ return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04350);
+ case 4351:
+ return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04351);
+ case 4352:
+ return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04352);
+ case 4353:
+ return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04353);
case 4354:
return VUID_WRAP(VUID-SampleId-SampleId-04354);
case 4355:
@@ -1445,6 +1552,40 @@
return VUID_WRAP(VUID-SamplePosition-SamplePosition-04361);
case 4362:
return VUID_WRAP(VUID-SamplePosition-SamplePosition-04362);
+ case 4367:
+ return VUID_WRAP(VUID-SubgroupId-SubgroupId-04367);
+ case 4368:
+ return VUID_WRAP(VUID-SubgroupId-SubgroupId-04368);
+ case 4369:
+ return VUID_WRAP(VUID-SubgroupId-SubgroupId-04369);
+ case 4370:
+ return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04370);
+ case 4371:
+ return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04371);
+ case 4372:
+ return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04372);
+ case 4373:
+ return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04373);
+ case 4374:
+ return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04374);
+ case 4375:
+ return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04375);
+ case 4376:
+ return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04376);
+ case 4377:
+ return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04377);
+ case 4378:
+ return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04378);
+ case 4379:
+ return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04379);
+ case 4380:
+ return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04380);
+ case 4381:
+ return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04381);
+ case 4382:
+ return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04382);
+ case 4383:
+ return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04383);
case 4387:
return VUID_WRAP(VUID-TessCoord-TessCoord-04387);
case 4388:
@@ -1453,10 +1594,18 @@
return VUID_WRAP(VUID-TessCoord-TessCoord-04389);
case 4390:
return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04390);
+ case 4391:
+ return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04391);
+ case 4392:
+ return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04392);
case 4393:
return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04393);
case 4394:
return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04394);
+ case 4395:
+ return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04395);
+ case 4396:
+ return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04396);
case 4397:
return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04397);
case 4398:
@@ -1473,6 +1622,8 @@
return VUID_WRAP(VUID-ViewIndex-ViewIndex-04403);
case 4404:
return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04404);
+ case 4405:
+ return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04405);
case 4406:
return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04406);
case 4407:
@@ -1491,6 +1642,24 @@
return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04426);
case 4427:
return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04427);
+ case 4428:
+ return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04428);
+ case 4429:
+ return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04429);
+ case 4430:
+ return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04430);
+ case 4431:
+ return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04431);
+ case 4432:
+ return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04432);
+ case 4433:
+ return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04433);
+ case 4434:
+ return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04434);
+ case 4435:
+ return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04435);
+ case 4436:
+ return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04436);
case 4484:
return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04484);
case 4485:
@@ -1503,6 +1672,44 @@
return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04491);
case 4492:
return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492);
+ case 4633:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04633);
+ case 4635:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04635);
+ case 4638:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04638);
+ case 4639:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04639);
+ case 4640:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04640);
+ case 4642:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04642);
+ case 4649:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04649);
+ case 4651:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651);
+ case 4652:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpReadClockKHR-04652);
+ case 4653:
+ return VUID_WRAP(VUID-StandaloneSpirv-OriginLowerLeft-04653);
+ case 4654:
+ return VUID_WRAP(VUID-StandaloneSpirv-PixelCenterInteger-04654);
+ case 4656:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656);
+ case 4657:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657);
+ case 4658:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658);
+ case 4669:
+ return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669);
+ case 4675:
+ return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
+ case 4685:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
+ case 4686:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
+ case 4711:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711);
default:
return ""; // unknown id
};
diff --git a/test/fuzz/transformation_duplicate_region_with_selection_test.cpp b/test/fuzz/transformation_duplicate_region_with_selection_test.cpp
index f3738e7..31fb9a2 100644
--- a/test/fuzz/transformation_duplicate_region_with_selection_test.cpp
+++ b/test/fuzz/transformation_duplicate_region_with_selection_test.cpp
@@ -1334,6 +1334,9 @@
OpBranch %50
%50 = OpLabel
%51 = OpCopyObject %7 %12
+ OpBranch %52
+ %52 = OpLabel
+ %53 = OpCopyObject %7 %51
OpReturn
OpFunctionEnd
)";
@@ -2275,6 +2278,207 @@
.IsApplicable(context.get(), transformation_context));
}
+TEST(TransformationDuplicateRegionWithSelectionTest,
+ DoNotProduceOpPhiWithVoidType) {
+ std::string reference_shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantTrue %10
+ %4 = OpFunction %2 None %3
+ %12 = OpLabel
+ OpBranch %5
+ %5 = OpLabel
+ %8 = OpFunctionCall %2 %6
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_4;
+ const auto consumer = nullptr;
+ const auto context =
+ BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
+ spvtools::ValidatorOptions validator_options;
+ ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+ kConsoleMessageConsumer));
+ TransformationContext transformation_context(
+ MakeUnique<FactManager>(context.get()), validator_options);
+
+ TransformationDuplicateRegionWithSelection transformation(
+ 100, 11, 101, 5, 5, {{5, 102}}, {{8, 103}}, {});
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
+ ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+ kConsoleMessageConsumer));
+
+ std::string expected_shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantTrue %10
+ %4 = OpFunction %2 None %3
+ %12 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpSelectionMerge %101 None
+ OpBranchConditional %11 %5 %102
+ %5 = OpLabel
+ %8 = OpFunctionCall %2 %6
+ OpBranch %101
+ %102 = OpLabel
+ %103 = OpFunctionCall %2 %6
+ OpBranch %101
+ %101 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
+}
+
+TEST(TransformationDuplicateRegionWithSelectionTest,
+ DoNotProduceOpPhiWithDisallowedType) {
+ std::string reference_shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ OpDecorate %13 DescriptorSet 0
+ OpDecorate %13 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 2
+ %8 = OpTypePointer Function %7
+ %10 = OpTypeImage %6 2D 0 0 0 1 Unknown
+ %11 = OpTypeSampledImage %10
+ %12 = OpTypePointer UniformConstant %11
+ %13 = OpVariable %12 UniformConstant
+ %15 = OpConstant %6 1
+ %16 = OpConstantComposite %7 %15 %15
+ %17 = OpTypeVector %6 4
+ %19 = OpTypeInt 32 0
+ %20 = OpConstant %19 0
+ %22 = OpTypePointer Function %6
+ %90 = OpTypeBool
+ %91 = OpConstantTrue %90
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %9 = OpVariable %8 Function
+ OpBranch %81
+ %81 = OpLabel
+ %14 = OpLoad %11 %13
+ %18 = OpImageSampleImplicitLod %17 %14 %16
+ %21 = OpCompositeExtract %6 %18 0
+ %23 = OpAccessChain %22 %9 %20
+ OpStore %23 %21
+ OpBranch %80
+ %80 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context =
+ BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
+ spvtools::ValidatorOptions validator_options;
+ ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+ kConsoleMessageConsumer));
+ TransformationContext transformation_context(
+ MakeUnique<FactManager>(context.get()), validator_options);
+
+ TransformationDuplicateRegionWithSelection transformation(
+ 100, 91, 101, 81, 81, {{81, 102}},
+ {{14, 103}, {18, 104}, {21, 105}, {23, 106}}, {{18, 107}, {21, 108}});
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
+ ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+ kConsoleMessageConsumer));
+
+ std::string expected_shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ OpDecorate %13 DescriptorSet 0
+ OpDecorate %13 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 2
+ %8 = OpTypePointer Function %7
+ %10 = OpTypeImage %6 2D 0 0 0 1 Unknown
+ %11 = OpTypeSampledImage %10
+ %12 = OpTypePointer UniformConstant %11
+ %13 = OpVariable %12 UniformConstant
+ %15 = OpConstant %6 1
+ %16 = OpConstantComposite %7 %15 %15
+ %17 = OpTypeVector %6 4
+ %19 = OpTypeInt 32 0
+ %20 = OpConstant %19 0
+ %22 = OpTypePointer Function %6
+ %90 = OpTypeBool
+ %91 = OpConstantTrue %90
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %9 = OpVariable %8 Function
+ OpBranch %100
+ %100 = OpLabel
+ OpSelectionMerge %101 None
+ OpBranchConditional %91 %81 %102
+ %81 = OpLabel
+ %14 = OpLoad %11 %13
+ %18 = OpImageSampleImplicitLod %17 %14 %16
+ %21 = OpCompositeExtract %6 %18 0
+ %23 = OpAccessChain %22 %9 %20
+ OpStore %23 %21
+ OpBranch %101
+ %102 = OpLabel
+ %103 = OpLoad %11 %13
+ %104 = OpImageSampleImplicitLod %17 %103 %16
+ %105 = OpCompositeExtract %6 %104 0
+ %106 = OpAccessChain %22 %9 %20
+ OpStore %106 %105
+ OpBranch %101
+ %101 = OpLabel
+ %107 = OpPhi %17 %18 %81 %104 %102
+ %108 = OpPhi %6 %21 %81 %105 %102
+ OpBranch %80
+ %80 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools
diff --git a/test/fuzz/transformation_flatten_conditional_branch_test.cpp b/test/fuzz/transformation_flatten_conditional_branch_test.cpp
index 540275a..1a0ff6a 100644
--- a/test/fuzz/transformation_flatten_conditional_branch_test.cpp
+++ b/test/fuzz/transformation_flatten_conditional_branch_test.cpp
@@ -666,7 +666,6 @@
OpBranchConditional %5 %13 %12
%13 = OpLabel
%14 = OpFunctionCall %3 %11
- %15 = OpCopyObject %3 %14
OpBranch %12
%12 = OpLabel
OpReturn
@@ -774,7 +773,6 @@
OpBranchConditional %5 %13 %12
%13 = OpLabel
%14 = OpFunctionCall %3 %11
- %15 = OpCopyObject %3 %14
OpBranch %12
%12 = OpLabel
OpReturn
diff --git a/test/fuzz/transformation_outline_function_test.cpp b/test/fuzz/transformation_outline_function_test.cpp
index 6c0bff4..c567680 100644
--- a/test/fuzz/transformation_outline_function_test.cpp
+++ b/test/fuzz/transformation_outline_function_test.cpp
@@ -2531,98 +2531,6 @@
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
}
-TEST(TransformationOutlineFunctionTest, SkipVoidOutputId) {
- std::string shader = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %6 "main"
- OpExecutionMode %6 OriginUpperLeft
- OpSource ESSL 310
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %21 = OpTypeBool
- %81 = OpConstantTrue %21
- %6 = OpFunction %2 None %3
- %7 = OpLabel
- OpBranch %80
- %80 = OpLabel
- %84 = OpFunctionCall %2 %87
- OpBranch %90
- %90 = OpLabel
- %86 = OpPhi %2 %84 %80
- OpReturn
- OpFunctionEnd
- %87 = OpFunction %2 None %3
- %88 = OpLabel
- OpReturn
- OpFunctionEnd
- )";
-
- const auto env = SPV_ENV_UNIVERSAL_1_5;
- const auto consumer = nullptr;
- const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
- spvtools::ValidatorOptions validator_options;
- ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
- kConsoleMessageConsumer));
- TransformationContext transformation_context(
- MakeUnique<FactManager>(context.get()), validator_options);
- TransformationOutlineFunction transformation(
- /*entry_block*/ 80,
- /*exit_block*/ 80,
- /*new_function_struct_return_type_id*/ 300,
- /*new_function_type_id*/ 301,
- /*new_function_id*/ 302,
- /*new_function_region_entry_block*/ 304,
- /*new_caller_result_id*/ 305,
- /*new_callee_result_id*/ 306,
- /*input_id_to_fresh_id*/ {},
- /*output_id_to_fresh_id*/ {{84, 307}});
-
- ASSERT_TRUE(
- transformation.IsApplicable(context.get(), transformation_context));
- ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
- ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
- kConsoleMessageConsumer));
-
- std::string after_transformation = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %6 "main"
- OpExecutionMode %6 OriginUpperLeft
- OpSource ESSL 310
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %21 = OpTypeBool
- %81 = OpConstantTrue %21
- %300 = OpTypeStruct
- %301 = OpTypeFunction %300
- %6 = OpFunction %2 None %3
- %7 = OpLabel
- OpBranch %80
- %80 = OpLabel
- %305 = OpFunctionCall %300 %302
- %84 = OpUndef %2
- OpBranch %90
- %90 = OpLabel
- %86 = OpPhi %2 %84 %80
- OpReturn
- OpFunctionEnd
- %87 = OpFunction %2 None %3
- %88 = OpLabel
- OpReturn
- OpFunctionEnd
- %302 = OpFunction %300 None %301
- %304 = OpLabel
- %307 = OpFunctionCall %2 %87
- %306 = OpCompositeConstruct %300
- OpReturnValue %306
- OpFunctionEnd
- )";
- ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
-}
-
TEST(TransformationOutlineFunctionTest, Miscellaneous1) {
// This tests outlining of some non-trivial code, and also tests the way
// overflow ids are used by the transformation.
diff --git a/test/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn
index be1258a..ec09b2b 100644
--- a/test/fuzzers/BUILD.gn
+++ b/test/fuzzers/BUILD.gn
@@ -39,10 +39,7 @@
":spvtools_opt_legalization_fuzzer",
":spvtools_opt_performance_fuzzer",
":spvtools_opt_size_fuzzer",
- ":spvtools_opt_webgputovulkan_fuzzer",
- ":spvtools_opt_vulkantowebgpu_fuzzer",
":spvtools_val_fuzzer",
- ":spvtools_val_webgpu_fuzzer",
]
}
}
@@ -104,31 +101,12 @@
]
}
-
-spvtools_fuzzer("spvtools_opt_webgputovulkan_fuzzer_src") {
- sources = [
- "spvtools_opt_webgputovulkan_fuzzer.cpp",
- ]
-}
-
-spvtools_fuzzer("spvtools_opt_vulkantowebgpu_fuzzer_src") {
- sources = [
- "spvtools_opt_vulkantowebgpu_fuzzer.cpp",
- ]
-}
-
spvtools_fuzzer("spvtools_val_fuzzer_src") {
sources = [
"spvtools_val_fuzzer.cpp",
]
}
-spvtools_fuzzer("spvtools_val_webgpu_fuzzer_src") {
- sources = [
- "spvtools_val_webgpu_fuzzer.cpp",
- ]
-}
-
if (!build_with_chromium || use_fuzzing_engine) {
fuzzer_test("spvtools_as_fuzzer") {
sources = []
@@ -181,22 +159,6 @@
seed_corpus = "corpora/spv"
}
- fuzzer_test("spvtools_opt_webgputovulkan_fuzzer") {
- sources = []
- deps = [
- ":spvtools_opt_webgputovulkan_fuzzer_src",
- ]
- seed_corpus = "corpora/spv"
- }
-
- fuzzer_test("spvtools_opt_vulkantowebgpu_fuzzer") {
- sources = []
- deps = [
- ":spvtools_opt_vulkantowebgpu_fuzzer_src",
- ]
- seed_corpus = "corpora/spv"
- }
-
fuzzer_test("spvtools_val_fuzzer") {
sources = []
deps = [
@@ -204,12 +166,4 @@
]
seed_corpus = "corpora/spv"
}
-
- fuzzer_test("spvtools_val_webgpu_fuzzer") {
- sources = []
- deps = [
- ":spvtools_val_webgpu_fuzzer_src",
- ]
- seed_corpus = "corpora/spv"
- }
}
diff --git a/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp b/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp
deleted file mode 100644
index 9371c0d..0000000
--- a/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2019 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 <cstdint>
-#include <vector>
-
-#include "spirv-tools/optimizer.hpp"
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1);
- optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
- const spv_position_t&, const char*) {});
-
- std::vector<uint32_t> input;
- input.resize(size >> 2);
-
- size_t count = 0;
- for (size_t i = 0; (i + 3) < size; i += 4) {
- input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
- (data[i + 3]) << 24;
- }
-
- optimizer.RegisterVulkanToWebGPUPasses();
- optimizer.Run(input.data(), input.size(), &input);
-
- return 0;
-}
diff --git a/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp b/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp
deleted file mode 100644
index 78ddbb7..0000000
--- a/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2019 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 <cstdint>
-#include <vector>
-
-#include "spirv-tools/optimizer.hpp"
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0);
- optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
- const spv_position_t&, const char*) {});
-
- std::vector<uint32_t> input;
- input.resize(size >> 2);
-
- size_t count = 0;
- for (size_t i = 0; (i + 3) < size; i += 4) {
- input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
- (data[i + 3]) << 24;
- }
-
- optimizer.RegisterWebGPUToVulkanPasses();
- optimizer.Run(input.data(), input.size(), &input);
-
- return 0;
-}
diff --git a/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp b/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp
deleted file mode 100644
index bed6e1a..0000000
--- a/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2019 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 <cstdint>
-#include <vector>
-
-#include "spirv-tools/libspirv.hpp"
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- spvtools::SpirvTools tools(SPV_ENV_WEBGPU_0);
- tools.SetMessageConsumer([](spv_message_level_t, const char*,
- const spv_position_t&, const char*) {});
-
- std::vector<uint32_t> input;
- input.resize(size >> 2);
-
- size_t count = 0;
- for (size_t i = 0; (i + 3) < size; i += 4) {
- input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
- (data[i + 3]) << 24;
- }
-
- tools.Validate(input);
- return 0;
-}
diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt
index 3426958..79cb3fc 100644
--- a/test/opt/CMakeLists.txt
+++ b/test/opt/CMakeLists.txt
@@ -34,7 +34,6 @@
dead_insert_elim_test.cpp
dead_variable_elim_test.cpp
debug_info_manager_test.cpp
- decompose_initialized_variables_test.cpp
decoration_manager_test.cpp
def_use_test.cpp
desc_sroa_test.cpp
@@ -48,7 +47,6 @@
fold_test.cpp
freeze_spec_const_test.cpp
function_test.cpp
- generate_webgpu_initializers_test.cpp
graphics_robust_access_test.cpp
if_conversion_test.cpp
inline_opaque_test.cpp
@@ -63,7 +61,6 @@
ir_context_test.cpp
ir_loader_test.cpp
iterator_test.cpp
- legalize_vector_shuffle_test.cpp
line_debug_info_test.cpp
local_access_chain_convert_test.cpp
local_redundancy_elimination_test.cpp
@@ -88,9 +85,7 @@
scalar_replacement_test.cpp
set_spec_const_default_value_test.cpp
simplification_test.cpp
- split_invalid_unreachable_test.cpp
strength_reduction_test.cpp
- strip_atomic_counter_memory_test.cpp
strip_debug_info_test.cpp
strip_reflect_info_test.cpp
struct_cfg_analysis_test.cpp
diff --git a/test/opt/decompose_initialized_variables_test.cpp b/test/opt/decompose_initialized_variables_test.cpp
deleted file mode 100644
index 06ba59a..0000000
--- a/test/opt/decompose_initialized_variables_test.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright (c) 2019 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 <vector>
-
-#include "test/opt/pass_fixture.h"
-#include "test/opt/pass_utils.h"
-
-namespace spvtools {
-namespace opt {
-namespace {
-
-using DecomposeInitializedVariablesTest = PassTest<::testing::Test>;
-
-std::string single_entry_header = R"(OpCapability Shader
-OpCapability VulkanMemoryModel
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical Vulkan
-OpEntryPoint Vertex %1 "shader"
-%uint = OpTypeInt 32 0
-%uint_1 = OpConstant %uint 1
-%4 = OpConstantNull %uint
-%void = OpTypeVoid
-%6 = OpTypeFunction %void
-)";
-
-std::string GetFunctionTest(std::string body) {
- auto result = single_entry_header;
- result += "%_ptr_Function_uint = OpTypePointer Function %uint\n";
- result += "%1 = OpFunction %void None %6\n";
- result += "%8 = OpLabel\n";
- result += body + "\n";
- result += "OpReturn\n";
- result += "OpFunctionEnd\n";
- return result;
-}
-
-TEST_F(DecomposeInitializedVariablesTest, FunctionChanged) {
- std::string input = "%9 = OpVariable %_ptr_Function_uint Function %uint_1";
- std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function
-OpStore %9 %uint_1)";
-
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- GetFunctionTest(input), GetFunctionTest(expected),
- /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, FunctionUnchanged) {
- std::string input = "%9 = OpVariable %_ptr_Function_uint Function";
-
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- GetFunctionTest(input), GetFunctionTest(input), /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, FunctionMultipleVariables) {
- std::string input = R"(%9 = OpVariable %_ptr_Function_uint Function %uint_1
-%10 = OpVariable %_ptr_Function_uint Function %4)";
- std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function
-%10 = OpVariable %_ptr_Function_uint Function
-OpStore %9 %uint_1
-OpStore %10 %4)";
-
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- GetFunctionTest(input), GetFunctionTest(expected),
- /* skip_nop = */ false);
-}
-
-std::string GetGlobalTest(std::string storage_class, bool initialized,
- bool decomposed) {
- auto result = single_entry_header;
-
- result += "%_ptr_" + storage_class + "_uint = OpTypePointer " +
- storage_class + " %uint\n";
- if (initialized) {
- result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
- storage_class + " %4\n";
- } else {
- result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
- storage_class + "\n";
- }
- result += R"(%1 = OpFunction %void None %9
-%9 = OpLabel
-)";
- if (decomposed) result += "OpStore %8 %4\n";
- result += R"(OpReturn
-OpFunctionEnd
-)";
- return result;
-}
-
-TEST_F(DecomposeInitializedVariablesTest, PrivateChanged) {
- std::string input = GetGlobalTest("Private", true, false);
- std::string expected = GetGlobalTest("Private", false, true);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, expected, /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, PrivateUnchanged) {
- std::string input = GetGlobalTest("Private", false, false);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, input, /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, OutputChanged) {
- std::string input = GetGlobalTest("Output", true, false);
- std::string expected = GetGlobalTest("Output", false, true);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, expected, /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, OutputUnchanged) {
- std::string input = GetGlobalTest("Output", false, false);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, input, /* skip_nop = */ false);
-}
-
-std::string multiple_entry_header = R"(OpCapability Shader
-OpCapability VulkanMemoryModel
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical Vulkan
-OpEntryPoint Vertex %1 "vertex"
-OpEntryPoint Fragment %2 "fragment"
-%uint = OpTypeInt 32 0
-%4 = OpConstantNull %uint
-%void = OpTypeVoid
-%6 = OpTypeFunction %void
-)";
-
-std::string GetGlobalMultipleEntryTest(std::string storage_class,
- bool initialized, bool decomposed) {
- auto result = multiple_entry_header;
- result += "%_ptr_" + storage_class + "_uint = OpTypePointer " +
- storage_class + " %uint\n";
- if (initialized) {
- result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
- storage_class + " %4\n";
- } else {
- result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
- storage_class + "\n";
- }
- result += R"(%1 = OpFunction %void None %9
-%9 = OpLabel
-)";
- if (decomposed) result += "OpStore %8 %4\n";
- result += R"(OpReturn
-OpFunctionEnd
-%2 = OpFunction %void None %10
-%10 = OpLabel
-)";
- if (decomposed) result += "OpStore %8 %4\n";
- result += R"(OpReturn
-OpFunctionEnd
-)";
-
- return result;
-}
-
-TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryChanged) {
- std::string input = GetGlobalMultipleEntryTest("Private", true, false);
- std::string expected = GetGlobalMultipleEntryTest("Private", false, true);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, expected, /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryUnchanged) {
- std::string input = GetGlobalMultipleEntryTest("Private", false, false);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, input, /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryChanged) {
- std::string input = GetGlobalMultipleEntryTest("Output", true, false);
- std::string expected = GetGlobalMultipleEntryTest("Output", false, true);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, expected, /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryUnchanged) {
- std::string input = GetGlobalMultipleEntryTest("Output", false, false);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, input, /* skip_nop = */ false);
-}
-
-std::string GetGlobalWithNonEntryPointTest(std::string storage_class,
- bool initialized, bool decomposed) {
- auto result = single_entry_header;
- result += "%_ptr_" + storage_class + "_uint = OpTypePointer " +
- storage_class + " %uint\n";
- if (initialized) {
- result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
- storage_class + " %4\n";
- } else {
- result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
- storage_class + "\n";
- }
- result += R"(%1 = OpFunction %void None %9
-%9 = OpLabel
-)";
- if (decomposed) result += "OpStore %8 %4\n";
- result += R"(OpReturn
-OpFunctionEnd
-%10 = OpFunction %void None %11
-%11 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- return result;
-}
-
-TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointChanged) {
- std::string input = GetGlobalWithNonEntryPointTest("Private", true, false);
- std::string expected = GetGlobalWithNonEntryPointTest("Private", false, true);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, expected, /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointUnchanged) {
- std::string input = GetGlobalWithNonEntryPointTest("Private", false, false);
- // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, input, /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointChanged) {
- std::string input = GetGlobalWithNonEntryPointTest("Output", true, false);
- std::string expected = GetGlobalWithNonEntryPointTest("Output", false, true);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, expected, /* skip_nop = */ false);
-}
-
-TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointUnchanged) {
- std::string input = GetGlobalWithNonEntryPointTest("Output", false, false);
- // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
- SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
- input, input, /* skip_nop = */ false);
-}
-
-} // namespace
-} // namespace opt
-} // namespace spvtools
diff --git a/test/opt/desc_sroa_test.cpp b/test/opt/desc_sroa_test.cpp
index cdcc9a8..b35ad47 100644
--- a/test/opt/desc_sroa_test.cpp
+++ b/test/opt/desc_sroa_test.cpp
@@ -729,6 +729,47 @@
SinglePassRunAndMatch<DescriptorScalarReplacement>(checks + shader, true);
}
+TEST_F(DescriptorScalarReplacementTest, BindingForResourceArrayOfStructs) {
+ // Check that correct binding numbers are given to an array of descriptors
+ // to structs.
+
+ const std::string shader = R"(
+; CHECK: OpDecorate {{%\w+}} Binding 0
+; CHECK: OpDecorate {{%\w+}} Binding 1
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %2 "psmain"
+ OpExecutionMode %2 OriginUpperLeft
+ OpDecorate %5 DescriptorSet 0
+ OpDecorate %5 Binding 0
+ OpMemberDecorate %_struct_4 0 Offset 0
+ OpMemberDecorate %_struct_4 1 Offset 4
+ OpDecorate %_struct_4 Block
+ %float = OpTypeFloat 32
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %int_1 = OpConstant %int 1
+ %uint = OpTypeInt 32 0
+ %uint_2 = OpConstant %uint 2
+ %_struct_4 = OpTypeStruct %float %int
+%_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2
+%_ptr_Uniform__arr__struct_4_uint_2 = OpTypePointer Uniform %_arr__struct_4_uint_2
+ %void = OpTypeVoid
+ %25 = OpTypeFunction %void
+%_ptr_Uniform_int = OpTypePointer Uniform %int
+ %5 = OpVariable %_ptr_Uniform__arr__struct_4_uint_2 Uniform
+ %2 = OpFunction %void None %25
+ %29 = OpLabel
+ %40 = OpAccessChain %_ptr_Uniform_int %5 %int_0 %int_1
+ %41 = OpAccessChain %_ptr_Uniform_int %5 %int_1 %int_1
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<DescriptorScalarReplacement>(shader, true);
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/eliminate_dead_member_test.cpp b/test/opt/eliminate_dead_member_test.cpp
index a9b0f28..7728782 100644
--- a/test/opt/eliminate_dead_member_test.cpp
+++ b/test/opt/eliminate_dead_member_test.cpp
@@ -1184,4 +1184,86 @@
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
}
+TEST_F(EliminateDeadMemberTest, 8BitIndexNoChange) {
+ // Test that the pass does not crash when an 8 bit index is used in an
+ // OpAccessChain. No change is expected.
+ const std::string text = R"(
+ OpCapability ImageQuery
+ OpCapability Int8
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "OpnSeman/" %2
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %_struct_7 = OpTypeStruct %v4float
+%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %10 = OpTypeFunction %v4float %_ptr_Function__struct_7
+ %char = OpTypeInt 8 1
+ %char_0 = OpConstant %char 0
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %2 = OpVariable %_ptr_Output_v4float Output
+ %1 = OpFunction %void None %4
+ %14 = OpLabel
+ %15 = OpVariable %_ptr_Function__struct_7 Function
+ %16 = OpFunctionCall %v4float %17 %15
+ OpReturn
+ OpFunctionEnd
+ %17 = OpFunction %v4float DontInline %10
+ %18 = OpFunctionParameter %_ptr_Function__struct_7
+ %19 = OpLabel
+ %20 = OpAccessChain %_ptr_Function_v4float %18 %char_0
+ %21 = OpLoad %v4float %20
+ OpReturnValue %21
+ OpFunctionEnd
+)";
+
+ auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
+ text, /* skip_nop = */ true, /* do_validation = */ true);
+ EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
+}
+
+TEST_F(EliminateDeadMemberTest, 8BitIndexWithChange) {
+ // Test that the pass does not crash when an 8 bit index is used in an
+ // OpAccessChain. The index in the access change should be changed to 0.
+ const std::string text = R"(
+ OpCapability ImageQuery
+ OpCapability Int8
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "OpnSeman/" %2
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %_struct_7 = OpTypeStruct %v4float %v4float
+%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %10 = OpTypeFunction %v4float %_ptr_Function__struct_7
+ %char = OpTypeInt 8 1
+ %char_1 = OpConstant %char 1
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %2 = OpVariable %_ptr_Output_v4float Output
+ %1 = OpFunction %void None %4
+ %14 = OpLabel
+ %15 = OpVariable %_ptr_Function__struct_7 Function
+ %16 = OpFunctionCall %v4float %17 %15
+ OpReturn
+ OpFunctionEnd
+ %17 = OpFunction %v4float DontInline %10
+; CHECK: [[param:%\w+]] = OpFunctionParameter
+ %18 = OpFunctionParameter %_ptr_Function__struct_7
+ %19 = OpLabel
+; CHECK: OpAccessChain %_ptr_Function_v4float [[param]] %uint_0
+ %20 = OpAccessChain %_ptr_Function_v4float %18 %char_1
+ %21 = OpLoad %v4float %20
+ OpReturnValue %21
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
+}
+
} // namespace
diff --git a/test/opt/generate_webgpu_initializers_test.cpp b/test/opt/generate_webgpu_initializers_test.cpp
deleted file mode 100644
index 4aab2ce..0000000
--- a/test/opt/generate_webgpu_initializers_test.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-// Copyright (c) 2019 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 <vector>
-
-#include "test/opt/pass_fixture.h"
-#include "test/opt/pass_utils.h"
-
-namespace spvtools {
-namespace opt {
-namespace {
-
-typedef std::tuple<std::string, bool> GenerateWebGPUInitializersParam;
-
-using GlobalVariableTest =
- PassTest<::testing::TestWithParam<GenerateWebGPUInitializersParam>>;
-using LocalVariableTest =
- PassTest<::testing::TestWithParam<GenerateWebGPUInitializersParam>>;
-
-using GenerateWebGPUInitializersTest = PassTest<::testing::Test>;
-
-void operator+=(std::vector<const char*>& lhs, const char* rhs) {
- lhs.push_back(rhs);
-}
-
-void operator+=(std::vector<const char*>& lhs,
- const std::vector<const char*>& rhs) {
- lhs.reserve(lhs.size() + rhs.size());
- for (auto* c : rhs) lhs.push_back(c);
-}
-
-std::string GetGlobalVariableTestString(std::string ptr_str,
- std::string var_str,
- std::string const_str = "") {
- std::vector<const char*> result = {
- // clang-format off
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
- ptr_str.c_str()};
- // clang-format on
-
- if (!const_str.empty()) result += const_str.c_str();
-
- result += {
- // clang-format off
- var_str.c_str(),
- "%uint_0 = OpConstant %uint 0",
- "%void = OpTypeVoid",
- "%7 = OpTypeFunction %void",
- "%1 = OpFunction %void None %7",
- "%8 = OpLabel",
- "OpStore %4 %uint_0",
- "OpReturn",
- "OpFunctionEnd"
- // clang-format on
- };
- return JoinAllInsts(result);
-}
-
-std::string GetPointerString(std::string storage_type) {
- std::string result = "%_ptr_";
- result += storage_type + "_uint = OpTypePointer ";
- result += storage_type + " %uint";
- return result;
-}
-
-std::string GetGlobalVariableString(std::string storage_type,
- bool initialized) {
- std::string result = "%4 = OpVariable %_ptr_";
- result += storage_type + "_uint ";
- result += storage_type;
- if (initialized) result += " %9";
- return result;
-}
-
-std::string GetUninitializedGlobalVariableTestString(std::string storage_type) {
- return GetGlobalVariableTestString(
- GetPointerString(storage_type),
- GetGlobalVariableString(storage_type, false));
-}
-
-std::string GetNullConstantString() { return "%9 = OpConstantNull %uint"; }
-
-std::string GetInitializedGlobalVariableTestString(std::string storage_type) {
- return GetGlobalVariableTestString(
- GetPointerString(storage_type),
- GetGlobalVariableString(storage_type, true), GetNullConstantString());
-}
-
-TEST_P(GlobalVariableTest, Check) {
- std::string storage_class = std::get<0>(GetParam());
- bool changed = std::get<1>(GetParam());
- std::string input = GetUninitializedGlobalVariableTestString(storage_class);
- std::string expected =
- changed ? GetInitializedGlobalVariableTestString(storage_class) : input;
-
- SinglePassRunAndCheck<GenerateWebGPUInitializersPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-// clang-format off
-INSTANTIATE_TEST_SUITE_P(
- GenerateWebGPUInitializers, GlobalVariableTest,
- ::testing::ValuesIn(std::vector<GenerateWebGPUInitializersParam>({
- std::make_tuple("Private", true),
- std::make_tuple("Output", true),
- std::make_tuple("Function", true),
- std::make_tuple("UniformConstant", false),
- std::make_tuple("Input", false),
- std::make_tuple("Uniform", false),
- std::make_tuple("Workgroup", false)
- })));
-// clang-format on
-
-std::string GetLocalVariableTestString(std::string ptr_str, std::string var_str,
- std::string const_str = "") {
- std::vector<const char*> result = {
- // clang-format off
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
- ptr_str.c_str(),
- "%uint_0 = OpConstant %uint 0",
- "%void = OpTypeVoid",
- "%6 = OpTypeFunction %void"};
- // clang-format on
-
- if (!const_str.empty()) result += const_str.c_str();
-
- result += {
- // clang-format off
- "%1 = OpFunction %void None %6",
- "%7 = OpLabel",
- var_str.c_str(),
- "OpStore %8 %uint_0"
- // clang-format on
- };
- return JoinAllInsts(result);
-}
-
-std::string GetLocalVariableString(std::string storage_type, bool initialized) {
- std::string result = "%8 = OpVariable %_ptr_";
- result += storage_type + "_uint ";
- result += storage_type;
- if (initialized) result += " %9";
- return result;
-}
-
-std::string GetUninitializedLocalVariableTestString(std::string storage_type) {
- return GetLocalVariableTestString(
- GetPointerString(storage_type),
- GetLocalVariableString(storage_type, false));
-}
-
-std::string GetInitializedLocalVariableTestString(std::string storage_type) {
- return GetLocalVariableTestString(GetPointerString(storage_type),
- GetLocalVariableString(storage_type, true),
- GetNullConstantString());
-}
-
-TEST_P(LocalVariableTest, Check) {
- std::string storage_class = std::get<0>(GetParam());
- bool changed = std::get<1>(GetParam());
-
- std::string input = GetUninitializedLocalVariableTestString(storage_class);
- std::string expected =
- changed ? GetInitializedLocalVariableTestString(storage_class) : input;
-
- SinglePassRunAndCheck<GenerateWebGPUInitializersPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-// clang-format off
-INSTANTIATE_TEST_SUITE_P(
- GenerateWebGPUInitializers, LocalVariableTest,
- ::testing::ValuesIn(std::vector<GenerateWebGPUInitializersParam>({
- std::make_tuple("Private", true),
- std::make_tuple("Output", true),
- std::make_tuple("Function", true),
- std::make_tuple("UniformConstant", false),
- std::make_tuple("Input", false),
- std::make_tuple("Uniform", false),
- std::make_tuple("Workgroup", false)
- })));
-// clang-format on
-
-TEST_F(GenerateWebGPUInitializersTest, AlreadyInitializedUnchanged) {
- std::vector<const char*> spirv = {
- // clang-format off
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
- "%_ptr_Private_uint = OpTypePointer Private %uint",
- "%uint_0 = OpConstant %uint 0",
- "%5 = OpVariable %_ptr_Private_uint Private %uint_0",
- "%void = OpTypeVoid",
- "%7 = OpTypeFunction %void",
- "%1 = OpFunction %void None %7",
- "%8 = OpLabel",
- "OpReturn",
- "OpFunctionEnd"
- // clang-format on
- };
- std::string str = JoinAllInsts(spirv);
-
- SinglePassRunAndCheck<GenerateWebGPUInitializersPass>(str, str,
- /* skip_nop = */ false);
-}
-
-TEST_F(GenerateWebGPUInitializersTest, AmbigiousArrays) {
- std::vector<const char*> input_spirv = {
- // clang-format off
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
- "%uint_2 = OpConstant %uint 2",
- "%_arr_uint_uint_2 = OpTypeArray %uint %uint_2",
- "%_arr_uint_uint_2_0 = OpTypeArray %uint %uint_2",
- "%_ptr_Private__arr_uint_uint_2 = OpTypePointer Private %_arr_uint_uint_2",
-"%_ptr_Private__arr_uint_uint_2_0 = OpTypePointer Private %_arr_uint_uint_2_0",
- "%8 = OpConstantNull %_arr_uint_uint_2_0",
- "%9 = OpVariable %_ptr_Private__arr_uint_uint_2 Private",
- "%10 = OpVariable %_ptr_Private__arr_uint_uint_2_0 Private %8",
- "%void = OpTypeVoid",
- "%12 = OpTypeFunction %void",
- "%1 = OpFunction %void None %12",
- "%13 = OpLabel",
- "OpReturn",
- "OpFunctionEnd"
- // clang-format on
- };
- std::string input_str = JoinAllInsts(input_spirv);
-
- std::vector<const char*> expected_spirv = {
- // clang-format off
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
- "%uint_2 = OpConstant %uint 2",
- "%_arr_uint_uint_2 = OpTypeArray %uint %uint_2",
- "%_arr_uint_uint_2_0 = OpTypeArray %uint %uint_2",
- "%_ptr_Private__arr_uint_uint_2 = OpTypePointer Private %_arr_uint_uint_2",
-"%_ptr_Private__arr_uint_uint_2_0 = OpTypePointer Private %_arr_uint_uint_2_0",
- "%8 = OpConstantNull %_arr_uint_uint_2_0",
- "%14 = OpConstantNull %_arr_uint_uint_2",
- "%9 = OpVariable %_ptr_Private__arr_uint_uint_2 Private %14",
- "%10 = OpVariable %_ptr_Private__arr_uint_uint_2_0 Private %8",
- "%void = OpTypeVoid",
- "%12 = OpTypeFunction %void",
- "%1 = OpFunction %void None %12",
- "%13 = OpLabel",
- "OpReturn",
- "OpFunctionEnd"
- // clang-format on
- };
- std::string expected_str = JoinAllInsts(expected_spirv);
-
- SinglePassRunAndCheck<GenerateWebGPUInitializersPass>(input_str, expected_str,
- /* skip_nop = */ false);
-}
-
-TEST_F(GenerateWebGPUInitializersTest, AmbigiousStructs) {
- std::vector<const char*> input_spirv = {
- // clang-format off
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
- "%_struct_3 = OpTypeStruct %uint",
- "%_struct_4 = OpTypeStruct %uint",
-"%_ptr_Private__struct_3 = OpTypePointer Private %_struct_3",
-"%_ptr_Private__struct_4 = OpTypePointer Private %_struct_4",
- "%7 = OpConstantNull %_struct_3",
- "%8 = OpVariable %_ptr_Private__struct_3 Private %7",
- "%9 = OpVariable %_ptr_Private__struct_4 Private",
- "%void = OpTypeVoid",
- "%11 = OpTypeFunction %void",
- "%1 = OpFunction %void None %11",
- "%12 = OpLabel",
- "OpReturn",
- "OpFunctionEnd"
- // clang-format on
- };
- std::string input_str = JoinAllInsts(input_spirv);
-
- std::vector<const char*> expected_spirv = {
- // clang-format off
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
- "%_struct_3 = OpTypeStruct %uint",
- "%_struct_4 = OpTypeStruct %uint",
-"%_ptr_Private__struct_3 = OpTypePointer Private %_struct_3",
-"%_ptr_Private__struct_4 = OpTypePointer Private %_struct_4",
- "%7 = OpConstantNull %_struct_3",
- "%8 = OpVariable %_ptr_Private__struct_3 Private %7",
- "%13 = OpConstantNull %_struct_4",
- "%9 = OpVariable %_ptr_Private__struct_4 Private %13",
- "%void = OpTypeVoid",
- "%11 = OpTypeFunction %void",
- "%1 = OpFunction %void None %11",
- "%12 = OpLabel",
- "OpReturn",
- "OpFunctionEnd"
- // clang-format on
- };
- std::string expected_str = JoinAllInsts(expected_spirv);
-
- SinglePassRunAndCheck<GenerateWebGPUInitializersPass>(input_str, expected_str,
- /* skip_nop = */ false);
-}
-
-} // namespace
-} // namespace opt
-} // namespace spvtools
diff --git a/test/opt/inline_opaque_test.cpp b/test/opt/inline_opaque_test.cpp
index 47e0533..8cb8925 100644
--- a/test/opt/inline_opaque_test.cpp
+++ b/test/opt/inline_opaque_test.cpp
@@ -28,7 +28,7 @@
// Function with opaque argument is inlined.
// TODO(greg-lunarg): Add HLSL code
- const std::string predefs =
+ const std::string predefs_1 =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -47,22 +47,27 @@
OpName %s0 "s0"
OpName %texCoords "texCoords"
OpName %param "param"
-OpDecorate %sampler15 DescriptorSet 0
+)";
+
+ const std::string name = R"(OpName %return_value "return_value"
+)";
+
+ const std::string predefs_2 = R"(OpDecorate %sampler15 DescriptorSet 0
%void = OpTypeVoid
-%12 = OpTypeFunction %void
+%13 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%outColor = OpVariable %_ptr_Output_v4float Output
-%17 = OpTypeImage %float 2D 0 0 0 1 Unknown
-%18 = OpTypeSampledImage %17
-%S_t = OpTypeStruct %v2float %v2float %18
+%18 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%19 = OpTypeSampledImage %18
+%S_t = OpTypeStruct %v2float %v2float %19
%_ptr_Function_S_t = OpTypePointer Function %S_t
-%20 = OpTypeFunction %void %_ptr_Function_S_t
-%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
-%_ptr_Function_18 = OpTypePointer Function %18
-%sampler15 = OpVariable %_ptr_UniformConstant_18 UniformConstant
+%21 = OpTypeFunction %void %_ptr_Function_S_t
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+%_ptr_Function_19 = OpTypePointer Function %19
+%sampler15 = OpVariable %_ptr_UniformConstant_19 UniformConstant
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_2 = OpConstant %int 2
@@ -72,39 +77,38 @@
)";
const std::string before =
- R"(%main = OpFunction %void None %12
-%28 = OpLabel
+ R"(%main = OpFunction %void None %13
+%29 = OpLabel
%s0 = OpVariable %_ptr_Function_S_t Function
%param = OpVariable %_ptr_Function_S_t Function
-%29 = OpLoad %v2float %texCoords
-%30 = OpAccessChain %_ptr_Function_v2float %s0 %int_0
-OpStore %30 %29
-%31 = OpLoad %18 %sampler15
-%32 = OpAccessChain %_ptr_Function_18 %s0 %int_2
-OpStore %32 %31
-%33 = OpLoad %S_t %s0
-OpStore %param %33
-%34 = OpFunctionCall %void %foo_struct_S_t_vf2_vf21_ %param
+%30 = OpLoad %v2float %texCoords
+%31 = OpAccessChain %_ptr_Function_v2float %s0 %int_0
+OpStore %31 %30
+%32 = OpLoad %19 %sampler15
+%33 = OpAccessChain %_ptr_Function_19 %s0 %int_2
+OpStore %33 %32
+%34 = OpLoad %S_t %s0
+OpStore %param %34
+%return_value = OpFunctionCall %void %foo_struct_S_t_vf2_vf21_ %param
OpReturn
OpFunctionEnd
)";
const std::string after =
- R"(%34 = OpUndef %void
-%main = OpFunction %void None %12
-%28 = OpLabel
+ R"(%main = OpFunction %void None %13
+%29 = OpLabel
%s0 = OpVariable %_ptr_Function_S_t Function
%param = OpVariable %_ptr_Function_S_t Function
-%29 = OpLoad %v2float %texCoords
-%30 = OpAccessChain %_ptr_Function_v2float %s0 %int_0
-OpStore %30 %29
-%31 = OpLoad %18 %sampler15
-%32 = OpAccessChain %_ptr_Function_18 %s0 %int_2
-OpStore %32 %31
-%33 = OpLoad %S_t %s0
-OpStore %param %33
-%42 = OpAccessChain %_ptr_Function_18 %param %int_2
-%43 = OpLoad %18 %42
+%30 = OpLoad %v2float %texCoords
+%31 = OpAccessChain %_ptr_Function_v2float %s0 %int_0
+OpStore %31 %30
+%32 = OpLoad %19 %sampler15
+%33 = OpAccessChain %_ptr_Function_19 %s0 %int_2
+OpStore %33 %32
+%34 = OpLoad %S_t %s0
+OpStore %param %34
+%42 = OpAccessChain %_ptr_Function_19 %param %int_2
+%43 = OpLoad %19 %42
%44 = OpAccessChain %_ptr_Function_v2float %param %int_0
%45 = OpLoad %v2float %44
%46 = OpImageSampleImplicitLod %v4float %43 %45
@@ -114,11 +118,11 @@
)";
const std::string post_defs =
- R"(%foo_struct_S_t_vf2_vf21_ = OpFunction %void None %20
+ R"(%foo_struct_S_t_vf2_vf21_ = OpFunction %void None %21
%s = OpFunctionParameter %_ptr_Function_S_t
%35 = OpLabel
-%36 = OpAccessChain %_ptr_Function_18 %s %int_2
-%37 = OpLoad %18 %36
+%36 = OpAccessChain %_ptr_Function_19 %s %int_2
+%37 = OpLoad %19 %36
%38 = OpAccessChain %_ptr_Function_v2float %s %int_0
%39 = OpLoad %v2float %38
%40 = OpImageSampleImplicitLod %v4float %37 %39
@@ -128,7 +132,8 @@
)";
SinglePassRunAndCheck<InlineOpaquePass>(
- predefs + before + post_defs, predefs + after + post_defs, true, true);
+ predefs_1 + name + predefs_2 + before + post_defs,
+ predefs_1 + predefs_2 + after + post_defs, true, true);
}
TEST_F(InlineOpaqueTest, InlineOpaqueReturn) {
@@ -290,8 +295,7 @@
)";
const std::string after =
- R"(%35 = OpUndef %void
-%main2 = OpFunction %void None %13
+ R"(%main2 = OpFunction %void None %13
%29 = OpLabel
%s0 = OpVariable %_ptr_Function_S_t Function
%param = OpVariable %_ptr_Function_S_t Function
diff --git a/test/opt/inline_test.cpp b/test/opt/inline_test.cpp
index c0ca6da..2939901 100644
--- a/test/opt/inline_test.cpp
+++ b/test/opt/inline_test.cpp
@@ -381,7 +381,6 @@
const std::vector<const char*> after = {
// clang-format off
- "%26 = OpUndef %void",
"%main = OpFunction %void None %11",
"%23 = OpLabel",
"%b = OpVariable %_ptr_Function_v4float Function",
@@ -1543,11 +1542,9 @@
OpFunctionEnd
)";
- const std::string undef = "%11 = OpUndef %void\n";
-
- SinglePassRunAndCheck<InlineExhaustivePass>(
- predefs + nonEntryFuncs + before, predefs + undef + nonEntryFuncs + after,
- false, true);
+ SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
+ predefs + nonEntryFuncs + after,
+ false, true);
}
TEST_F(InlineTest, MultiBlockLoopHeaderCallsMultiBlockCallee) {
@@ -1622,10 +1619,9 @@
OpFunctionEnd
)";
- const std::string undef = "%20 = OpUndef %void\n";
- SinglePassRunAndCheck<InlineExhaustivePass>(
- predefs + nonEntryFuncs + before, predefs + undef + nonEntryFuncs + after,
- false, true);
+ SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
+ predefs + nonEntryFuncs + after,
+ false, true);
}
TEST_F(InlineTest, SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge) {
@@ -1711,10 +1707,9 @@
OpReturn
OpFunctionEnd
)";
- const std::string undef = "%15 = OpUndef %void\n";
- SinglePassRunAndCheck<InlineExhaustivePass>(
- predefs + nonEntryFuncs + before, predefs + undef + nonEntryFuncs + after,
- false, true);
+ SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
+ predefs + nonEntryFuncs + after,
+ false, true);
}
TEST_F(InlineTest,
@@ -1793,10 +1788,9 @@
OpFunctionEnd
)";
- const std::string undef = "%20 = OpUndef %void\n";
- SinglePassRunAndCheck<InlineExhaustivePass>(
- predefs + nonEntryFuncs + before, predefs + undef + nonEntryFuncs + after,
- false, true);
+ SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
+ predefs + nonEntryFuncs + after,
+ false, true);
}
TEST_F(InlineTest, NonInlinableCalleeWithSingleReturn) {
@@ -2169,7 +2163,6 @@
OpName %foo_entry "foo_entry"
%void = OpTypeVoid
%void_fn = OpTypeFunction %void
-%3 = OpUndef %void
%foo = OpFunction %void None %void_fn
%foo_entry = OpLabel
OpReturn
@@ -2475,7 +2468,6 @@
%3 = OpTypeFunction %void
%bool = OpTypeBool
%true = OpConstantTrue %bool
-%16 = OpUndef %void
%main = OpFunction %void None %3
%5 = OpLabel
OpKill
@@ -2573,7 +2565,6 @@
%3 = OpTypeFunction %void
%bool = OpTypeBool
%true = OpConstantTrue %bool
-%16 = OpUndef %void
%main = OpFunction %void None %3
%5 = OpLabel
OpTerminateInvocation
@@ -2590,6 +2581,63 @@
SinglePassRunAndCheck<InlineExhaustivePass>(before, after, false, true);
}
+TEST_F(InlineTest, InlineFuncWithOpTerminateRayNotInContinue) {
+ const std::string text =
+ R"(
+ OpCapability RayTracingKHR
+ OpExtension "SPV_KHR_ray_tracing"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint AnyHitKHR %MyAHitMain2 "MyAHitMain2" %a
+ OpSource HLSL 630
+ OpName %a "a"
+ OpName %MyAHitMain2 "MyAHitMain2"
+ OpName %param_var_a "param.var.a"
+ OpName %src_MyAHitMain2 "src.MyAHitMain2"
+ OpName %a_0 "a"
+ OpName %bb_entry "bb.entry"
+ %int = OpTypeInt 32 1
+%_ptr_IncomingRayPayloadKHR_int = OpTypePointer IncomingRayPayloadKHR %int
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+%_ptr_Function_int = OpTypePointer Function %int
+ %14 = OpTypeFunction %void %_ptr_Function_int
+ %a = OpVariable %_ptr_IncomingRayPayloadKHR_int IncomingRayPayloadKHR
+%MyAHitMain2 = OpFunction %void None %6
+ %7 = OpLabel
+%param_var_a = OpVariable %_ptr_Function_int Function
+ %10 = OpLoad %int %a
+ OpStore %param_var_a %10
+ %11 = OpFunctionCall %void %src_MyAHitMain2 %param_var_a
+ %13 = OpLoad %int %param_var_a
+ OpStore %a %13
+ OpReturn
+ OpFunctionEnd
+%src_MyAHitMain2 = OpFunction %void None %14
+ %a_0 = OpFunctionParameter %_ptr_Function_int
+ %bb_entry = OpLabel
+ %17 = OpLoad %int %a_0
+ OpStore %a %17
+ OpTerminateRayKHR
+ OpFunctionEnd
+
+; CHECK: %MyAHitMain2 = OpFunction %void None
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: %param_var_a = OpVariable %_ptr_Function_int Function
+; CHECK-NEXT: OpLoad %int %a
+; CHECK-NEXT: OpStore %param_var_a {{%\d+}}
+; CHECK-NEXT: OpLoad %int %param_var_a
+; CHECK-NEXT: OpStore %a {{%\d+}}
+; CHECK-NEXT: OpTerminateRayKHR
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: OpLoad %int %param_var_a
+; CHECK-NEXT: OpStore %a %16
+; CHECK-NEXT: OpReturn
+; CHECK-NEXT: OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<InlineExhaustivePass>(text, false);
+}
+
TEST_F(InlineTest, EarlyReturnFunctionInlined) {
// #version 140
//
@@ -2801,7 +2849,6 @@
%uint_0 = OpConstant %uint 0
%false = OpConstantFalse %bool
%_ptr_Function_bool = OpTypePointer Function %bool
-%11 = OpUndef %void
%foo_ = OpFunction %void None %4
%7 = OpLabel
%18 = OpVariable %_ptr_Function_bool Function %false
@@ -3890,35 +3937,6 @@
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
}
-TEST_F(InlineTest, UsingVoidFunctionResult) {
- const std::string text = R"(
-; CHECK: [[undef:%\w+]] = OpUndef %void
-; CHECK: OpFunction
-; CHECK: OpCopyObject %void [[undef]]
-; CHECK: OpFunctionEnd
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main"
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 320
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- %8 = OpFunctionCall %2 %6
- %9 = OpCopyObject %2 %8
- OpReturn
- OpFunctionEnd
- %6 = OpFunction %2 None %3
- %7 = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
-}
-
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// Empty modules
diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp
index 691bc9a..f189962 100644
--- a/test/opt/inst_bindless_check_test.cpp
+++ b/test/opt/inst_bindless_check_test.cpp
@@ -105,8 +105,8 @@
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
- SinglePassRunAndCheck<InstBindlessCheckPass>(before, before, true, true, 7u,
- 23u, false, false);
+ SinglePassRunAndCheck<InstBindlessCheckPass>(
+ before, before, true, true, 7u, 23u, false, false, false, false, false);
}
TEST_F(InstBindlessTest, NoInstrumentNonBindless) {
@@ -183,7 +183,8 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(whole_file, whole_file, true,
- true, 7u, 23u, false, false);
+ true, 7u, 23u, false, false,
+ false, false, false);
}
TEST_F(InstBindlessTest, Simple) {
@@ -412,7 +413,7 @@
func_pt2_before,
entry_after + names_annots + new_annots + consts_types_vars +
new_consts_types_vars + func_pt1 + func_pt2_after + output_func,
- true, true, 7u, 23u, false, false);
+ true, true, 7u, 23u, false, false, false, false, false);
}
TEST_F(InstBindlessTest, InstrumentMultipleInstructions) {
@@ -707,7 +708,7 @@
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + output_func, true,
- true, 7u, 23u, false, false);
+ true, 7u, 23u, false, false, false, false, false);
}
TEST_F(InstBindlessTest, InstrumentOpImage) {
@@ -935,7 +936,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + output_func, true,
- true, 7u, 23u, false, false);
+ true, 7u, 23u, false, false, false, false, false);
}
TEST_F(InstBindlessTest, InstrumentSampledImage) {
@@ -1158,7 +1159,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + output_func, true,
- true, 7u, 23u, false, false);
+ true, 7u, 23u, false, false, false, false, false);
}
TEST_F(InstBindlessTest, InstrumentImageWrite) {
@@ -1383,7 +1384,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + output_func, true,
- true, 7u, 23u, false, false);
+ true, 7u, 23u, false, false, false, false, false);
}
TEST_F(InstBindlessTest, InstrumentVertexSimple) {
@@ -1657,7 +1658,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + output_func, true,
- true, 7u, 23u, false, false);
+ true, 7u, 23u, false, false, false, false, false);
}
TEST_F(InstBindlessTest, InstrumentTeseSimple) {
@@ -1933,7 +1934,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + output_func, true,
- true, 7u, 23u, false, false);
+ true, 7u, 23u, false, false, false, false, false);
}
TEST_F(InstBindlessTest, MultipleDebugFunctions) {
@@ -2261,7 +2262,7 @@
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func1_before + func2_before,
defs_after + func1_after + func2_after + output_func, true, true, 7u, 23u,
- false, false);
+ false, false, false, false, false);
}
TEST_F(InstBindlessTest, RuntimeArray) {
@@ -2557,7 +2558,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptor) {
@@ -2793,7 +2794,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest, SPV14AddToEntryPoint) {
@@ -2849,7 +2850,8 @@
)";
SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
- SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true);
+ SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
+ false, false, false);
}
TEST_F(InstBindlessTest, SPV14AddToEntryPoints) {
@@ -2907,7 +2909,8 @@
)";
SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
- SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true);
+ SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
+ false, false, false);
}
TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) {
@@ -3188,7 +3191,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) {
@@ -3469,7 +3472,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArray) {
@@ -3739,7 +3742,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest, InstInitLoadUBOScalar) {
@@ -3964,7 +3967,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) {
@@ -4238,7 +4241,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) {
@@ -4507,7 +4510,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest,
@@ -4829,7 +4832,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest,
@@ -5153,7 +5156,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest,
@@ -5477,7 +5480,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest,
@@ -5801,7 +5804,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest,
@@ -6125,7 +6128,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest,
@@ -6449,7 +6452,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest,
@@ -6773,7 +6776,7 @@
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) {
@@ -7182,7 +7185,7 @@
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<InstBindlessCheckPass>(
defs_before + func_before, defs_after + func_after + new_funcs, true,
- true, 7u, 23u, true, true);
+ true, 7u, 23u, true, true, false, false, false);
}
TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
@@ -7456,7 +7459,7 @@
SetTargetEnv(SPV_ENV_VULKAN_1_2);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
- false, true);
+ false, true, false, true);
}
TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) {
@@ -7721,7 +7724,7 @@
SetTargetEnv(SPV_ENV_VULKAN_1_2);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
- false, true);
+ false, true, false, true);
}
TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
@@ -7978,7 +7981,7 @@
SetTargetEnv(SPV_ENV_VULKAN_1_2);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
- true);
+ true, false, true);
}
TEST_F(InstBindlessTest, Descriptor16BitIdxRef) {
@@ -8201,7 +8204,7 @@
SetTargetEnv(SPV_ENV_VULKAN_1_2);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
- false);
+ false, false, true);
}
TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
@@ -8471,7 +8474,7 @@
SetTargetEnv(SPV_ENV_VULKAN_1_2);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
- false, true);
+ false, true, false, true);
}
TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
@@ -8679,7 +8682,7 @@
SetTargetEnv(SPV_ENV_VULKAN_1_2);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
- false, true);
+ false, true, false, true);
}
TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) {
@@ -8885,7 +8888,7 @@
SetTargetEnv(SPV_ENV_VULKAN_1_2);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
- false, true);
+ false, true, false, true);
}
TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) {
@@ -9107,7 +9110,860 @@
SetTargetEnv(SPV_ENV_VULKAN_1_2);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
- false, true);
+ false, true, false, true);
+}
+
+TEST_F(InstBindlessTest, ImageBufferOOBRead) {
+ // Texel buffer (imagebuffer) oob check for ImageRead
+ //
+ // #version 450
+ // layout(set=3, binding=7, r32f) uniform readonly imageBuffer s;
+ // layout(location=11) out vec4 x;
+ // layout(location=13) in flat int ii;
+ //
+ // void main(){
+ // x = imageLoad(s, ii);
+ // }
+
+ 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
+;CHECK: OpDecorate %_struct_43 Block
+;CHECK: OpMemberDecorate %_struct_43 0 Offset 0
+;CHECK: OpMemberDecorate %_struct_43 1 Offset 4
+;CHECK: OpDecorate %45 DescriptorSet 7
+;CHECK: OpDecorate %45 Binding 0
+;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: %uint_0 = OpConstant %uint 0
+;CHECK: %bool = OpTypeBool
+;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK: %_ptr_StorageBuffer__struct_43 = OpTypePointer StorageBuffer %_struct_43
+;CHECK: %45 = OpVariable %_ptr_StorageBuffer__struct_43 StorageBuffer
+;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK: %uint_11 = OpConstant %uint 11
+;CHECK: %uint_4 = OpConstant %uint 4
+;CHECK: %uint_1 = OpConstant %uint 1
+;CHECK: %uint_23 = OpConstant %uint 23
+;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %uint_5 = OpConstant %uint 5
+;CHECK: %uint_7 = OpConstant %uint 7
+;CHECK: %uint_8 = OpConstant %uint 8
+;CHECK: %uint_9 = OpConstant %uint 9
+;CHECK: %uint_10 = OpConstant %uint 10
+;CHECK: %uint_33 = OpConstant %uint 33
+;CHECK: %93 = 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: %92 = OpFunctionCall %void %34 %uint_33 %uint_3 %uint_0 %23 %25
+;CHECK: OpBranch %29
+;CHECK: %29 = OpLabel
+;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31
+;CHECK: OpStore %x %94
+ OpReturn
+ OpFunctionEnd
+;CHECK: %34 = OpFunction %void None %35
+;CHECK: %36 = OpFunctionParameter %uint
+;CHECK: %37 = OpFunctionParameter %uint
+;CHECK: %38 = OpFunctionParameter %uint
+;CHECK: %39 = OpFunctionParameter %uint
+;CHECK: %40 = OpFunctionParameter %uint
+;CHECK: %41 = OpLabel
+;CHECK: %47 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0
+;CHECK: %50 = OpAtomicIAdd %uint %47 %uint_4 %uint_0 %uint_11
+;CHECK: %51 = OpIAdd %uint %50 %uint_11
+;CHECK: %52 = OpArrayLength %uint %45 1
+;CHECK: %53 = OpULessThanEqual %bool %51 %52
+;CHECK: OpSelectionMerge %54 None
+;CHECK: OpBranchConditional %53 %55 %54
+;CHECK: %55 = OpLabel
+;CHECK: %56 = OpIAdd %uint %50 %uint_0
+;CHECK: %58 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %56
+;CHECK: OpStore %58 %uint_11
+;CHECK: %60 = OpIAdd %uint %50 %uint_1
+;CHECK: %61 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %60
+;CHECK: OpStore %61 %uint_23
+;CHECK: %63 = OpIAdd %uint %50 %uint_2
+;CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63
+;CHECK: OpStore %64 %36
+;CHECK: %65 = OpIAdd %uint %50 %uint_3
+;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65
+;CHECK: OpStore %66 %uint_4
+;CHECK: %69 = OpLoad %v4float %gl_FragCoord
+;CHECK: %71 = OpBitcast %v4uint %69
+;CHECK: %72 = OpCompositeExtract %uint %71 0
+;CHECK: %73 = OpIAdd %uint %50 %uint_4
+;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73
+;CHECK: OpStore %74 %72
+;CHECK: %75 = OpCompositeExtract %uint %71 1
+;CHECK: %77 = OpIAdd %uint %50 %uint_5
+;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77
+;CHECK: OpStore %78 %75
+;CHECK: %80 = OpIAdd %uint %50 %uint_7
+;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80
+;CHECK: OpStore %81 %37
+;CHECK: %83 = OpIAdd %uint %50 %uint_8
+;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %83
+;CHECK: OpStore %84 %38
+;CHECK: %86 = OpIAdd %uint %50 %uint_9
+;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %86
+;CHECK: OpStore %87 %39
+;CHECK: %89 = OpIAdd %uint %50 %uint_10
+;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %89
+;CHECK: OpStore %90 %40
+;CHECK: OpBranch %54
+;CHECK: %54 = OpLabel
+;CHECK: OpReturn
+;CHECK: OpFunctionEnd
+ )";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_2);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
+ false, true, true, true);
+}
+
+TEST_F(InstBindlessTest, ImageBufferOOBWrite) {
+ // Texel buffer (imagebuffer) oob check for ImageWrite
+ //
+ // #version 450
+ // layout(set=3, binding=7, r32f) uniform readonly imageBuffer s;
+ // layout(location=11) out vec4 x;
+ // layout(location=13) in flat int ii;
+ //
+ // void main(){
+ // imageStore(s, ii, x);
+ // }
+
+ 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 %44 %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
+;CHECK: OpDecorate %_struct_42 Block
+;CHECK: OpMemberDecorate %_struct_42 0 Offset 0
+;CHECK: OpMemberDecorate %_struct_42 1 Offset 4
+;CHECK: OpDecorate %44 DescriptorSet 7
+;CHECK: OpDecorate %44 Binding 0
+;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: %uint_0 = OpConstant %uint 0
+;CHECK: %bool = OpTypeBool
+;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %34 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK: %_struct_42 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK: %_ptr_StorageBuffer__struct_42 = OpTypePointer StorageBuffer %_struct_42
+;CHECK: %44 = OpVariable %_ptr_StorageBuffer__struct_42 StorageBuffer
+;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK: %uint_11 = OpConstant %uint 11
+;CHECK: %uint_4 = OpConstant %uint 4
+;CHECK: %uint_1 = OpConstant %uint 1
+;CHECK: %uint_23 = OpConstant %uint 23
+;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %uint_5 = OpConstant %uint 5
+;CHECK: %uint_7 = OpConstant %uint 7
+;CHECK: %uint_8 = OpConstant %uint 8
+;CHECK: %uint_9 = OpConstant %uint 9
+;CHECK: %uint_10 = OpConstant %uint 10
+;CHECK: %uint_34 = OpConstant %uint 34
+ %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: %91 = OpFunctionCall %void %33 %uint_34 %uint_3 %uint_0 %23 %25
+;CHECK: OpBranch %29
+;CHECK: %29 = OpLabel
+ OpReturn
+ OpFunctionEnd
+;CHECK: %33 = OpFunction %void None %34
+;CHECK: %35 = OpFunctionParameter %uint
+;CHECK: %36 = OpFunctionParameter %uint
+;CHECK: %37 = OpFunctionParameter %uint
+;CHECK: %38 = OpFunctionParameter %uint
+;CHECK: %39 = OpFunctionParameter %uint
+;CHECK: %40 = OpLabel
+;CHECK: %46 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_0
+;CHECK: %49 = OpAtomicIAdd %uint %46 %uint_4 %uint_0 %uint_11
+;CHECK: %50 = OpIAdd %uint %49 %uint_11
+;CHECK: %51 = OpArrayLength %uint %44 1
+;CHECK: %52 = OpULessThanEqual %bool %50 %51
+;CHECK: OpSelectionMerge %53 None
+;CHECK: OpBranchConditional %52 %54 %53
+;CHECK: %54 = OpLabel
+;CHECK: %55 = OpIAdd %uint %49 %uint_0
+;CHECK: %57 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %55
+;CHECK: OpStore %57 %uint_11
+;CHECK: %59 = OpIAdd %uint %49 %uint_1
+;CHECK: %60 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %59
+;CHECK: OpStore %60 %uint_23
+;CHECK: %62 = OpIAdd %uint %49 %uint_2
+;CHECK: %63 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %62
+;CHECK: OpStore %63 %35
+;CHECK: %64 = OpIAdd %uint %49 %uint_3
+;CHECK: %65 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %64
+;CHECK: OpStore %65 %uint_4
+;CHECK: %68 = OpLoad %v4float %gl_FragCoord
+;CHECK: %70 = OpBitcast %v4uint %68
+;CHECK: %71 = OpCompositeExtract %uint %70 0
+;CHECK: %72 = OpIAdd %uint %49 %uint_4
+;CHECK: %73 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %72
+;CHECK: OpStore %73 %71
+;CHECK: %74 = OpCompositeExtract %uint %70 1
+;CHECK: %76 = OpIAdd %uint %49 %uint_5
+;CHECK: %77 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %76
+;CHECK: OpStore %77 %74
+;CHECK: %79 = OpIAdd %uint %49 %uint_7
+;CHECK: %80 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %79
+;CHECK: OpStore %80 %36
+;CHECK: %82 = OpIAdd %uint %49 %uint_8
+;CHECK: %83 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %82
+;CHECK: OpStore %83 %37
+;CHECK: %85 = OpIAdd %uint %49 %uint_9
+;CHECK: %86 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %85
+;CHECK: OpStore %86 %38
+;CHECK: %88 = OpIAdd %uint %49 %uint_10
+;CHECK: %89 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %88
+;CHECK: OpStore %89 %39
+;CHECK: OpBranch %53
+;CHECK: %53 = OpLabel
+;CHECK: OpReturn
+;CHECK: OpFunctionEnd
+ )";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_2);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
+ false, true, true, true);
+}
+
+TEST_F(InstBindlessTest, TextureBufferOOBFetch) {
+ // Texel buffer (texturebuffer) oob check for ImageFetch
+ //
+ // #version 450
+ // layout(set=3, binding=7) uniform textureBuffer s;
+ // layout(location=11) out vec4 x;
+ // layout(location=13) in flat int ii;
+ //
+ // void main(){
+ // x = texelFetch(s, ii);
+ // }
+
+ 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 %45 %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
+;CHECK: OpDecorate %_struct_43 Block
+;CHECK: OpMemberDecorate %_struct_43 0 Offset 0
+;CHECK: OpMemberDecorate %_struct_43 1 Offset 4
+;CHECK: OpDecorate %45 DescriptorSet 7
+;CHECK: OpDecorate %45 Binding 0
+;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: %uint_0 = OpConstant %uint 0
+;CHECK: %bool = OpTypeBool
+;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK: %_ptr_StorageBuffer__struct_43 = OpTypePointer StorageBuffer %_struct_43
+;CHECK: %45 = OpVariable %_ptr_StorageBuffer__struct_43 StorageBuffer
+;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK: %uint_11 = OpConstant %uint 11
+;CHECK: %uint_4 = OpConstant %uint 4
+;CHECK: %uint_1 = OpConstant %uint 1
+;CHECK: %uint_23 = OpConstant %uint 23
+;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %uint_5 = OpConstant %uint 5
+;CHECK: %uint_7 = OpConstant %uint 7
+;CHECK: %uint_8 = OpConstant %uint 8
+;CHECK: %uint_9 = OpConstant %uint 9
+;CHECK: %uint_10 = OpConstant %uint 10
+;CHECK: %uint_32 = OpConstant %uint 32
+;CHECK: %93 = 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: %92 = OpFunctionCall %void %34 %uint_32 %uint_3 %uint_0 %23 %25
+;CHECK: OpBranch %29
+;CHECK: %29 = OpLabel
+;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31
+;CHECK: OpStore %x %94
+ OpReturn
+ OpFunctionEnd
+;CHECK: %34 = OpFunction %void None %35
+;CHECK: %36 = OpFunctionParameter %uint
+;CHECK: %37 = OpFunctionParameter %uint
+;CHECK: %38 = OpFunctionParameter %uint
+;CHECK: %39 = OpFunctionParameter %uint
+;CHECK: %40 = OpFunctionParameter %uint
+;CHECK: %41 = OpLabel
+;CHECK: %47 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0
+;CHECK: %50 = OpAtomicIAdd %uint %47 %uint_4 %uint_0 %uint_11
+;CHECK: %51 = OpIAdd %uint %50 %uint_11
+;CHECK: %52 = OpArrayLength %uint %45 1
+;CHECK: %53 = OpULessThanEqual %bool %51 %52
+;CHECK: OpSelectionMerge %54 None
+;CHECK: OpBranchConditional %53 %55 %54
+;CHECK: %55 = OpLabel
+;CHECK: %56 = OpIAdd %uint %50 %uint_0
+;CHECK: %58 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %56
+;CHECK: OpStore %58 %uint_11
+;CHECK: %60 = OpIAdd %uint %50 %uint_1
+;CHECK: %61 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %60
+;CHECK: OpStore %61 %uint_23
+;CHECK: %63 = OpIAdd %uint %50 %uint_2
+;CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63
+;CHECK: OpStore %64 %36
+;CHECK: %65 = OpIAdd %uint %50 %uint_3
+;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65
+;CHECK: OpStore %66 %uint_4
+;CHECK: %69 = OpLoad %v4float %gl_FragCoord
+;CHECK: %71 = OpBitcast %v4uint %69
+;CHECK: %72 = OpCompositeExtract %uint %71 0
+;CHECK: %73 = OpIAdd %uint %50 %uint_4
+;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73
+;CHECK: OpStore %74 %72
+;CHECK: %75 = OpCompositeExtract %uint %71 1
+;CHECK: %77 = OpIAdd %uint %50 %uint_5
+;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77
+;CHECK: OpStore %78 %75
+;CHECK: %80 = OpIAdd %uint %50 %uint_7
+;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80
+;CHECK: OpStore %81 %37
+;CHECK: %83 = OpIAdd %uint %50 %uint_8
+;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %83
+;CHECK: OpStore %84 %38
+;CHECK: %86 = OpIAdd %uint %50 %uint_9
+;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %86
+;CHECK: OpStore %87 %39
+;CHECK: %89 = OpIAdd %uint %50 %uint_10
+;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %89
+;CHECK: OpStore %90 %40
+;CHECK: OpBranch %54
+;CHECK: %54 = OpLabel
+;CHECK: OpReturn
+;CHECK: OpFunctionEnd
+ )";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_2);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
+ false, true, true, true);
+}
+
+TEST_F(InstBindlessTest, SamplerBufferOOBFetch) {
+ // Texel buffer (samplerbuffer) oob check for ImageFetch
+ //
+ // #version 450
+ // layout(set=3, binding=7) uniform samplerBuffer s;
+ // layout(location=11) out vec4 x;
+ // layout(location=13) in flat int ii;
+ //
+ // void main(){
+ // x = texelFetch(s, ii);
+ // }
+
+ 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 %48 %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
+;CHECK: OpDecorate %_struct_46 Block
+;CHECK: OpMemberDecorate %_struct_46 0 Offset 0
+;CHECK: OpMemberDecorate %_struct_46 1 Offset 4
+;CHECK: OpDecorate %48 DescriptorSet 7
+;CHECK: OpDecorate %48 Binding 0
+;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: %uint_0 = OpConstant %uint 0
+;CHECK: %bool = OpTypeBool
+;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %38 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK: %_struct_46 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK: %_ptr_StorageBuffer__struct_46 = OpTypePointer StorageBuffer %_struct_46
+;CHECK: %48 = OpVariable %_ptr_StorageBuffer__struct_46 StorageBuffer
+;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK: %uint_11 = OpConstant %uint 11
+;CHECK: %uint_4 = OpConstant %uint 4
+;CHECK: %uint_1 = OpConstant %uint 1
+;CHECK: %uint_23 = OpConstant %uint 23
+;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %uint_5 = OpConstant %uint 5
+;CHECK: %uint_7 = OpConstant %uint 7
+;CHECK: %uint_8 = OpConstant %uint 8
+;CHECK: %uint_9 = OpConstant %uint 9
+;CHECK: %uint_10 = OpConstant %uint 10
+;CHECK: %uint_34 = OpConstant %uint 34
+;CHECK: %96 = 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: %95 = OpFunctionCall %void %37 %uint_34 %uint_3 %uint_0 %25 %27
+;CHECK: OpBranch %31
+;CHECK: %31 = OpLabel
+;CHECK: %97 = OpPhi %v4float %36 %32 %96 %33
+;CHECK: OpStore %x %97
+ OpReturn
+ OpFunctionEnd
+;CHECK: %37 = OpFunction %void None %38
+;CHECK: %39 = OpFunctionParameter %uint
+;CHECK: %40 = OpFunctionParameter %uint
+;CHECK: %41 = OpFunctionParameter %uint
+;CHECK: %42 = OpFunctionParameter %uint
+;CHECK: %43 = OpFunctionParameter %uint
+;CHECK: %44 = OpLabel
+;CHECK: %50 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0
+;CHECK: %53 = OpAtomicIAdd %uint %50 %uint_4 %uint_0 %uint_11
+;CHECK: %54 = OpIAdd %uint %53 %uint_11
+;CHECK: %55 = OpArrayLength %uint %48 1
+;CHECK: %56 = OpULessThanEqual %bool %54 %55
+;CHECK: OpSelectionMerge %57 None
+;CHECK: OpBranchConditional %56 %58 %57
+;CHECK: %58 = OpLabel
+;CHECK: %59 = OpIAdd %uint %53 %uint_0
+;CHECK: %61 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %59
+;CHECK: OpStore %61 %uint_11
+;CHECK: %63 = OpIAdd %uint %53 %uint_1
+;CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %63
+;CHECK: OpStore %64 %uint_23
+;CHECK: %66 = OpIAdd %uint %53 %uint_2
+;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %66
+;CHECK: OpStore %67 %39
+;CHECK: %68 = OpIAdd %uint %53 %uint_3
+;CHECK: %69 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %68
+;CHECK: OpStore %69 %uint_4
+;CHECK: %72 = OpLoad %v4float %gl_FragCoord
+;CHECK: %74 = OpBitcast %v4uint %72
+;CHECK: %75 = OpCompositeExtract %uint %74 0
+;CHECK: %76 = OpIAdd %uint %53 %uint_4
+;CHECK: %77 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %76
+;CHECK: OpStore %77 %75
+;CHECK: %78 = OpCompositeExtract %uint %74 1
+;CHECK: %80 = OpIAdd %uint %53 %uint_5
+;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %80
+;CHECK: OpStore %81 %78
+;CHECK: %83 = OpIAdd %uint %53 %uint_7
+;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %83
+;CHECK: OpStore %84 %40
+;CHECK: %86 = OpIAdd %uint %53 %uint_8
+;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %86
+;CHECK: OpStore %87 %41
+;CHECK: %89 = OpIAdd %uint %53 %uint_9
+;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %89
+;CHECK: OpStore %90 %42
+;CHECK: %92 = OpIAdd %uint %53 %uint_10
+;CHECK: %93 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %92
+;CHECK: OpStore %93 %43
+;CHECK: OpBranch %57
+;CHECK: %57 = OpLabel
+;CHECK: OpReturn
+;CHECK: OpFunctionEnd
+ )";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_2);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
+ false, true, true, true);
+}
+
+TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) {
+ // Texel buffer (samplerbuffer constructor) oob check for ImageFetch
+ //
+ // #version 450
+ // layout(set=3, binding=7) uniform textureBuffer tBuf;
+ // layout(set=3, binding=8) uniform sampler s;
+ // layout(location=11) out vec4 x;
+ // layout(location=13) in flat int ii;
+ //
+ // void main(){
+ // x = texelFetch(samplerBuffer(tBuf, s), ii);
+ // }
+
+ 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 %54 %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
+;CHECK: OpDecorate %_struct_52 Block
+;CHECK: OpMemberDecorate %_struct_52 0 Offset 0
+;CHECK: OpMemberDecorate %_struct_52 1 Offset 4
+;CHECK: OpDecorate %54 DescriptorSet 7
+;CHECK: OpDecorate %54 Binding 0
+;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: %uint_0 = OpConstant %uint 0
+;CHECK: %bool = OpTypeBool
+;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %44 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK: %_struct_52 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK: %_ptr_StorageBuffer__struct_52 = OpTypePointer StorageBuffer %_struct_52
+;CHECK: %54 = OpVariable %_ptr_StorageBuffer__struct_52 StorageBuffer
+;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK: %uint_11 = OpConstant %uint 11
+;CHECK: %uint_4 = OpConstant %uint 4
+;CHECK: %uint_1 = OpConstant %uint 1
+;CHECK: %uint_23 = OpConstant %uint 23
+;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: %uint_5 = OpConstant %uint 5
+;CHECK: %uint_7 = OpConstant %uint 7
+;CHECK: %uint_8 = OpConstant %uint 8
+;CHECK: %uint_9 = OpConstant %uint 9
+;CHECK: %uint_10 = OpConstant %uint 10
+;CHECK: %uint_42 = OpConstant %uint 42
+;CHECK: %102 = 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: %101 = OpFunctionCall %void %43 %uint_42 %uint_3 %uint_0 %30 %32
+;CHECK: OpBranch %36
+;CHECK: %36 = OpLabel
+;CHECK: %103 = OpPhi %v4float %42 %37 %102 %38
+;CHECK: OpStore %x %103
+ OpReturn
+ OpFunctionEnd
+;CHECK: %43 = OpFunction %void None %44
+;CHECK: %45 = OpFunctionParameter %uint
+;CHECK: %46 = OpFunctionParameter %uint
+;CHECK: %47 = OpFunctionParameter %uint
+;CHECK: %48 = OpFunctionParameter %uint
+;CHECK: %49 = OpFunctionParameter %uint
+;CHECK: %50 = OpLabel
+;CHECK: %56 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_0
+;CHECK: %59 = OpAtomicIAdd %uint %56 %uint_4 %uint_0 %uint_11
+;CHECK: %60 = OpIAdd %uint %59 %uint_11
+;CHECK: %61 = OpArrayLength %uint %54 1
+;CHECK: %62 = OpULessThanEqual %bool %60 %61
+;CHECK: OpSelectionMerge %63 None
+;CHECK: OpBranchConditional %62 %64 %63
+;CHECK: %64 = OpLabel
+;CHECK: %65 = OpIAdd %uint %59 %uint_0
+;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %65
+;CHECK: OpStore %67 %uint_11
+;CHECK: %69 = OpIAdd %uint %59 %uint_1
+;CHECK: %70 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %69
+;CHECK: OpStore %70 %uint_23
+;CHECK: %72 = OpIAdd %uint %59 %uint_2
+;CHECK: %73 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %72
+;CHECK: OpStore %73 %45
+;CHECK: %74 = OpIAdd %uint %59 %uint_3
+;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %74
+;CHECK: OpStore %75 %uint_4
+;CHECK: %78 = OpLoad %v4float %gl_FragCoord
+;CHECK: %80 = OpBitcast %v4uint %78
+;CHECK: %81 = OpCompositeExtract %uint %80 0
+;CHECK: %82 = OpIAdd %uint %59 %uint_4
+;CHECK: %83 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %82
+;CHECK: OpStore %83 %81
+;CHECK: %84 = OpCompositeExtract %uint %80 1
+;CHECK: %86 = OpIAdd %uint %59 %uint_5
+;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %86
+;CHECK: OpStore %87 %84
+;CHECK: %89 = OpIAdd %uint %59 %uint_7
+;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %89
+;CHECK: OpStore %90 %46
+;CHECK: %92 = OpIAdd %uint %59 %uint_8
+;CHECK: %93 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %92
+;CHECK: OpStore %93 %47
+;CHECK: %95 = OpIAdd %uint %59 %uint_9
+;CHECK: %96 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %95
+;CHECK: OpStore %96 %48
+;CHECK: %98 = OpIAdd %uint %59 %uint_10
+;CHECK: %99 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %98
+;CHECK: OpStore %99 %49
+;CHECK: OpBranch %63
+;CHECK: %63 = OpLabel
+;CHECK: OpReturn
+;CHECK: OpFunctionEnd
+ )";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_2);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
+ false, true, true, true);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
diff --git a/test/opt/ir_loader_test.cpp b/test/opt/ir_loader_test.cpp
index 8b77aa3..475dd23 100644
--- a/test/opt/ir_loader_test.cpp
+++ b/test/opt/ir_loader_test.cpp
@@ -19,7 +19,7 @@
#include <utility>
#include <vector>
-#include "gtest/gtest.h"
+#include "gmock/gmock.h"
#include "source/opt/build_module.h"
#include "source/opt/def_use_manager.h"
#include "source/opt/ir_context.h"
@@ -29,6 +29,8 @@
namespace opt {
namespace {
+using ::testing::ContainerEq;
+
constexpr uint32_t kOpLineOperandLineIndex = 1;
void DoRoundTripCheck(const std::string& text) {
@@ -236,6 +238,100 @@
}
}
+TEST(IrBuilder, BuildModule_WithoutExtraLines) {
+ const std::string text = R"(OpCapability Shader
+OpMemoryModel Logical Simple
+OpEntryPoint Vertex %main "main"
+%file = OpString "my file"
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%main = OpFunction %void None %voidfn
+%100 = OpLabel
+%1 = OpFAdd %float %float_1 %float_1
+OpLine %file 1 0
+%2 = OpFMul %float %1 %1
+%3 = OpFSub %float %2 %2
+OpReturn
+OpFunctionEnd
+)";
+
+ std::vector<uint32_t> binary;
+ SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
+ ASSERT_TRUE(t.Assemble(text, &binary,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS));
+
+ // This is the function we're testing.
+ std::unique_ptr<IRContext> context = BuildModule(
+ SPV_ENV_UNIVERSAL_1_5, nullptr, binary.data(), binary.size(), false);
+ ASSERT_NE(nullptr, context);
+
+ spvtools::opt::analysis::DefUseManager* def_use_mgr =
+ context->get_def_use_mgr();
+
+ std::vector<SpvOp> opcodes;
+ for (auto* inst = def_use_mgr->GetDef(1);
+ inst && (inst->opcode() != SpvOpFunctionEnd); inst = inst->NextNode()) {
+ inst->ForEachInst(
+ [&opcodes](spvtools::opt::Instruction* sub_inst) {
+ opcodes.push_back(sub_inst->opcode());
+ },
+ true);
+ }
+
+ EXPECT_THAT(opcodes,
+ ContainerEq(std::vector<SpvOp>{SpvOpFAdd, SpvOpLine, SpvOpFMul,
+ SpvOpFSub, SpvOpReturn}));
+}
+
+TEST(IrBuilder, BuildModule_WithExtraLines_IsDefault) {
+ const std::string text = R"(OpCapability Shader
+OpMemoryModel Logical Simple
+OpEntryPoint Vertex %main "main"
+%file = OpString "my file"
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%main = OpFunction %void None %voidfn
+%100 = OpLabel
+%1 = OpFAdd %float %float_1 %float_1
+OpLine %file 1 0
+%2 = OpFMul %float %1 %1
+%3 = OpFSub %float %2 %2
+OpReturn
+OpFunctionEnd
+)";
+
+ std::vector<uint32_t> binary;
+
+ SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
+ ASSERT_TRUE(t.Assemble(text, &binary,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS));
+
+ // This is the function we're testing.
+ std::unique_ptr<IRContext> context =
+ BuildModule(SPV_ENV_UNIVERSAL_1_5, nullptr, binary.data(), binary.size());
+
+ spvtools::opt::analysis::DefUseManager* def_use_mgr =
+ context->get_def_use_mgr();
+
+ std::vector<SpvOp> opcodes;
+ for (auto* inst = def_use_mgr->GetDef(1);
+ inst && (inst->opcode() != SpvOpFunctionEnd); inst = inst->NextNode()) {
+ inst->ForEachInst(
+ [&opcodes](spvtools::opt::Instruction* sub_inst) {
+ opcodes.push_back(sub_inst->opcode());
+ },
+ true);
+ }
+
+ EXPECT_THAT(opcodes, ContainerEq(std::vector<SpvOp>{
+ SpvOpFAdd, SpvOpLine, SpvOpFMul, SpvOpLine,
+ SpvOpFSub, SpvOpLine, SpvOpReturn}));
+}
+
TEST(IrBuilder, ConsumeDebugInfoInst) {
// /* HLSL */
//
diff --git a/test/opt/legalize_vector_shuffle_test.cpp b/test/opt/legalize_vector_shuffle_test.cpp
deleted file mode 100644
index 07d96eb..0000000
--- a/test/opt/legalize_vector_shuffle_test.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2019 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 <vector>
-
-#include "test/opt/pass_fixture.h"
-#include "test/opt/pass_utils.h"
-
-namespace spvtools {
-namespace opt {
-namespace {
-
-using LegalizeVectorShuffleTest = PassTest<::testing::Test>;
-
-void operator+=(std::vector<const char*>& lhs, const char* rhs) {
- lhs.push_back(rhs);
-}
-
-void operator+=(std::vector<const char*>& lhs,
- const std::vector<const char*> rhs) {
- for (auto elem : rhs) lhs.push_back(elem);
-}
-
-std::vector<const char*> header = {
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
- "%v3uint = OpTypeVector %uint 3"};
-
-std::string GetTestString(const char* shuffle) {
- std::vector<const char*> result = header;
- result += {"%_ptr_Function_v3uint = OpTypePointer Function %v3uint",
- "%void = OpTypeVoid",
- "%6 = OpTypeFunction %void",
- "%1 = OpFunction %void None %6",
- "%7 = OpLabel",
- "%8 = OpVariable %_ptr_Function_v3uint Function",
- "%9 = OpLoad %v3uint %8",
- "%10 = OpLoad %v3uint %8"};
- result += shuffle;
- result += {"OpReturn", "OpFunctionEnd"};
- return JoinAllInsts(result);
-}
-
-TEST_F(LegalizeVectorShuffleTest, Changed) {
- std::string input =
- GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0xFFFFFFFF");
- std::string expected =
- GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0");
-
- SinglePassRunAndCheck<LegalizeVectorShufflePass>(input, expected,
- /* skip_nop = */ false);
-}
-
-TEST_F(LegalizeVectorShuffleTest, FunctionUnchanged) {
- std::string input =
- GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0");
- std::string expected =
- GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0");
-
- SinglePassRunAndCheck<LegalizeVectorShufflePass>(input, expected,
- /* skip_nop = */ false);
-}
-
-} // namespace
-} // namespace opt
-} // namespace spvtools
diff --git a/test/opt/optimizer_test.cpp b/test/opt/optimizer_test.cpp
index 945aa78..a51638a 100644
--- a/test/opt/optimizer_test.cpp
+++ b/test/opt/optimizer_test.cpp
@@ -221,498 +221,6 @@
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
}
-TEST(Optimizer, VulkanToWebGPUSetsCorrectPasses) {
- Optimizer opt(SPV_ENV_VULKAN_1_1);
- opt.RegisterVulkanToWebGPUPasses();
- std::vector<const char*> pass_names = opt.GetPassNames();
-
- std::vector<std::string> registered_passes;
- for (auto name = pass_names.begin(); name != pass_names.end(); ++name)
- registered_passes.push_back(*name);
-
- std::vector<std::string> expected_passes = {"eliminate-dead-branches",
- "eliminate-dead-code-aggressive",
- "eliminate-dead-const",
- "flatten-decorations",
- "strip-atomic-counter-memory",
- "generate-webgpu-initializers",
- "legalize-vector-shuffle",
- "split-invalid-unreachable",
- "compact-ids"};
- std::sort(registered_passes.begin(), registered_passes.end());
- std::sort(expected_passes.begin(), expected_passes.end());
-
- ASSERT_EQ(registered_passes.size(), expected_passes.size());
- for (size_t i = 0; i < registered_passes.size(); i++)
- EXPECT_EQ(registered_passes[i], expected_passes[i]);
-}
-
-struct VulkanToWebGPUPassCase {
- // Input SPIR-V
- std::string input;
- // Expected result SPIR-V
- std::string expected;
- // Specific pass under test, used for logging messages.
- std::string pass;
-};
-
-using VulkanToWebGPUPassTest =
- PassTest<::testing::TestWithParam<VulkanToWebGPUPassCase>>;
-
-TEST_P(VulkanToWebGPUPassTest, Ran) {
- std::vector<uint32_t> binary;
- {
- SpirvTools tools(SPV_ENV_VULKAN_1_1);
- tools.Assemble(GetParam().input, &binary);
- }
-
- Optimizer opt(SPV_ENV_VULKAN_1_1);
- opt.RegisterVulkanToWebGPUPasses();
-
- std::vector<uint32_t> optimized;
- class ValidatorOptions validator_options;
- ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized,
- validator_options, true))
- << GetParam().input << "\n";
- std::string disassembly;
- {
- SpirvTools tools(SPV_ENV_WEBGPU_0);
- tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
- }
-
- EXPECT_EQ(GetParam().expected, disassembly)
- << "Was expecting pass '" << GetParam().pass << "' to have been run.\n";
-}
-
-INSTANTIATE_TEST_SUITE_P(
- Optimizer, VulkanToWebGPUPassTest,
- ::testing::ValuesIn(std::vector<VulkanToWebGPUPassCase>{
- // FlattenDecorations
- {// input
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Fragment %main \"main\" %hue %saturation %value\n"
- "OpExecutionMode %main OriginUpperLeft\n"
- "OpDecorate %group Flat\n"
- "OpDecorate %group NoPerspective\n"
- "%group = OpDecorationGroup\n"
- "%void = OpTypeVoid\n"
- "%void_fn = OpTypeFunction %void\n"
- "%float = OpTypeFloat 32\n"
- "%_ptr_Input_float = OpTypePointer Input %float\n"
- "%hue = OpVariable %_ptr_Input_float Input\n"
- "%saturation = OpVariable %_ptr_Input_float Input\n"
- "%value = OpVariable %_ptr_Input_float Input\n"
- "%main = OpFunction %void None %void_fn\n"
- "%entry = OpLabel\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // expected
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Fragment %1 \"main\" %2 %3 %4\n"
- "OpExecutionMode %1 OriginUpperLeft\n"
- "%void = OpTypeVoid\n"
- "%6 = OpTypeFunction %void\n"
- "%float = OpTypeFloat 32\n"
- "%_ptr_Input_float = OpTypePointer Input %float\n"
- "%2 = OpVariable %_ptr_Input_float Input\n"
- "%3 = OpVariable %_ptr_Input_float Input\n"
- "%4 = OpVariable %_ptr_Input_float Input\n"
- "%1 = OpFunction %void None %6\n"
- "%9 = OpLabel\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // pass
- "flatten-decorations"},
- // Eliminate Dead Constants
- {// input
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %func \"shader\"\n"
- "%u32 = OpTypeInt 32 0\n"
- "%u32_ptr = OpTypePointer Workgroup %u32\n"
- "%u32_var = OpVariable %u32_ptr Workgroup\n"
- "%u32_1 = OpConstant %u32 1\n"
- "%cross_device = OpConstant %u32 0\n"
- "%relaxed = OpConstant %u32 0\n"
- "%acquire_release_atomic_counter_workgroup = OpConstant %u32 1288\n"
- "%void = OpTypeVoid\n"
- "%void_f = OpTypeFunction %void\n"
- "%func = OpFunction %void None %void_f\n"
- "%label = OpLabel\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // expected
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%uint = OpTypeInt 32 0\n"
- "%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n"
- "%4 = OpVariable %_ptr_Workgroup_uint Workgroup\n"
- "%void = OpTypeVoid\n"
- "%6 = OpTypeFunction %void\n"
- "%1 = OpFunction %void None %6\n"
- "%7 = OpLabel\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- "eliminate-dead-const"},
- // Strip Atomic Counter Memory
- {// input
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %func \"shader\"\n"
- "%u32 = OpTypeInt 32 0\n"
- "%u32_ptr = OpTypePointer Workgroup %u32\n"
- "%u32_var = OpVariable %u32_ptr Workgroup\n"
- "%u32_0 = OpConstant %u32 0\n"
- "%u32_1 = OpConstant %u32 1\n"
- "%cross_device = OpConstant %u32 0\n"
- "%acquire_release_atomic_counter_workgroup = OpConstant %u32 1288\n"
- "%void = OpTypeVoid\n"
- "%void_f = OpTypeFunction %void\n"
- "%func = OpFunction %void None %void_f\n"
- "%label = OpLabel\n"
- " OpAtomicStore %u32_var %cross_device "
- "%acquire_release_atomic_counter_workgroup %u32_1\n"
- "%val1 = OpAtomicIIncrement %u32 %u32_var %cross_device "
- "%acquire_release_atomic_counter_workgroup\n"
- "%val2 = OpAtomicCompareExchange %u32 %u32_var %cross_device "
- "%acquire_release_atomic_counter_workgroup "
- "%acquire_release_atomic_counter_workgroup %u32_0 %u32_0\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // expected
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%uint = OpTypeInt 32 0\n"
- "%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n"
- "%4 = OpVariable %_ptr_Workgroup_uint Workgroup\n"
- "%uint_0 = OpConstant %uint 0\n"
- "%uint_1 = OpConstant %uint 1\n"
- "%uint_0_0 = OpConstant %uint 0\n"
- "%void = OpTypeVoid\n"
- "%9 = OpTypeFunction %void\n"
- "%uint_264 = OpConstant %uint 264\n"
- "%1 = OpFunction %void None %9\n"
- "%11 = OpLabel\n"
- "OpAtomicStore %4 %uint_0_0 %uint_264 %uint_1\n"
- "%12 = OpAtomicIIncrement %uint %4 %uint_0_0 %uint_264\n"
- "%13 = OpAtomicCompareExchange %uint %4 %uint_0_0 %uint_264 %uint_264 "
- "%uint_0 %uint_0\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // pass
- "strip-atomic-counter-memory"},
- // Generate WebGPU Initializers
- {// input
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %func \"shader\"\n"
- "%u32 = OpTypeInt 32 0\n"
- "%u32_ptr = OpTypePointer Private %u32\n"
- "%u32_var = OpVariable %u32_ptr Private\n"
- "%u32_0 = OpConstant %u32 0\n"
- "%void = OpTypeVoid\n"
- "%void_f = OpTypeFunction %void\n"
- "%func = OpFunction %void None %void_f\n"
- "%label = OpLabel\n"
- "OpStore %u32_var %u32_0\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // expected
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%uint = OpTypeInt 32 0\n"
- "%_ptr_Private_uint = OpTypePointer Private %uint\n"
- "%4 = OpConstantNull %uint\n"
- "%5 = OpVariable %_ptr_Private_uint Private %4\n"
- "%uint_0 = OpConstant %uint 0\n"
- "%void = OpTypeVoid\n"
- "%8 = OpTypeFunction %void\n"
- "%1 = OpFunction %void None %8\n"
- "%9 = OpLabel\n"
- "OpStore %5 %uint_0\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // pass
- "generate-webgpu-initializers"},
- // Legalize Vector Shuffle
- {// input
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%uint = OpTypeInt 32 0\n"
- "%v3uint = OpTypeVector %uint 3\n"
- "%_ptr_Function_v3uint = OpTypePointer Function %v3uint\n"
- "%void = OpTypeVoid\n"
- "%6 = OpTypeFunction %void\n"
- "%1 = OpFunction %void None %6\n"
- "%7 = OpLabel\n"
- "%8 = OpVariable %_ptr_Function_v3uint Function\n"
- "%9 = OpLoad %v3uint %8\n"
- "%10 = OpLoad %v3uint %8\n"
- "%11 = OpVectorShuffle %v3uint %9 %10 2 1 0xFFFFFFFF\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // expected
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%uint = OpTypeInt 32 0\n"
- "%v3uint = OpTypeVector %uint 3\n"
- "%_ptr_Function_v3uint = OpTypePointer Function %v3uint\n"
- "%void = OpTypeVoid\n"
- "%6 = OpTypeFunction %void\n"
- "%7 = OpConstantNull %v3uint\n"
- "%1 = OpFunction %void None %6\n"
- "%8 = OpLabel\n"
- "%9 = OpVariable %_ptr_Function_v3uint Function %7\n"
- "%10 = OpLoad %v3uint %9\n"
- "%11 = OpLoad %v3uint %9\n"
- "%12 = OpVectorShuffle %v3uint %10 %11 2 1 0\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // pass
- "legalize-vector-shuffle"},
- // Split Invalid Unreachable
- {// input
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%uint = OpTypeInt 32 0\n"
- "%uint_1 = OpConstant %uint 1\n"
- "%uint_2 = OpConstant %uint 2\n"
- "%void = OpTypeVoid\n"
- "%bool = OpTypeBool\n"
- "%7 = OpTypeFunction %void\n"
- "%1 = OpFunction %void None %7\n"
- "%8 = OpLabel\n"
- "OpBranch %9\n"
- "%9 = OpLabel\n"
- "OpLoopMerge %10 %11 None\n"
- "OpBranch %12\n"
- "%12 = OpLabel\n"
- "%13 = OpSLessThan %bool %uint_1 %uint_2\n"
- "OpSelectionMerge %11 None\n"
- "OpBranchConditional %13 %14 %15\n"
- "%14 = OpLabel\n"
- "OpReturn\n"
- "%15 = OpLabel\n"
- "OpReturn\n"
- "%10 = OpLabel\n"
- "OpUnreachable\n"
- "%11 = OpLabel\n"
- "OpBranch %9\n"
- "OpFunctionEnd\n",
- // expected
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%uint = OpTypeInt 32 0\n"
- "%uint_1 = OpConstant %uint 1\n"
- "%uint_2 = OpConstant %uint 2\n"
- "%void = OpTypeVoid\n"
- "%bool = OpTypeBool\n"
- "%7 = OpTypeFunction %void\n"
- "%1 = OpFunction %void None %7\n"
- "%8 = OpLabel\n"
- "OpBranch %9\n"
- "%9 = OpLabel\n"
- "OpLoopMerge %10 %11 None\n"
- "OpBranch %12\n"
- "%12 = OpLabel\n"
- "%13 = OpSLessThan %bool %uint_1 %uint_2\n"
- "OpSelectionMerge %14 None\n"
- "OpBranchConditional %13 %15 %16\n"
- "%15 = OpLabel\n"
- "OpReturn\n"
- "%16 = OpLabel\n"
- "OpReturn\n"
- "%10 = OpLabel\n"
- "OpUnreachable\n"
- "%14 = OpLabel\n"
- "OpUnreachable\n"
- "%11 = OpLabel\n"
- "OpBranch %9\n"
- "OpFunctionEnd\n",
- // pass
- "split-invalid-unreachable"},
- // Compact IDs
- {// input
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1000 \"shader\"\n"
- "%10 = OpTypeVoid\n"
- "%100 = OpTypeFunction %10\n"
- "%1000 = OpFunction %10 None %100\n"
- "%10000 = OpLabel\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // expected
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%void = OpTypeVoid\n"
- "%3 = OpTypeFunction %void\n"
- "%1 = OpFunction %void None %3\n"
- "%4 = OpLabel\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // pass
- "compact-ids"}}));
-
-TEST(Optimizer, WebGPUToVulkanSetsCorrectPasses) {
- Optimizer opt(SPV_ENV_WEBGPU_0);
- opt.RegisterWebGPUToVulkanPasses();
- std::vector<const char*> pass_names = opt.GetPassNames();
-
- std::vector<std::string> registered_passes;
- for (auto name = pass_names.begin(); name != pass_names.end(); ++name)
- registered_passes.push_back(*name);
-
- std::vector<std::string> expected_passes = {"decompose-initialized-variables",
- "compact-ids"};
- std::sort(registered_passes.begin(), registered_passes.end());
- std::sort(expected_passes.begin(), expected_passes.end());
-
- ASSERT_EQ(registered_passes.size(), expected_passes.size());
- for (size_t i = 0; i < registered_passes.size(); i++)
- EXPECT_EQ(registered_passes[i], expected_passes[i]);
-}
-
-struct WebGPUToVulkanPassCase {
- // Input SPIR-V
- std::string input;
- // Expected result SPIR-V
- std::string expected;
- // Specific pass under test, used for logging messages.
- std::string pass;
-};
-
-using WebGPUToVulkanPassTest =
- PassTest<::testing::TestWithParam<WebGPUToVulkanPassCase>>;
-
-TEST_P(WebGPUToVulkanPassTest, Ran) {
- std::vector<uint32_t> binary;
- {
- SpirvTools tools(SPV_ENV_WEBGPU_0);
- tools.Assemble(GetParam().input, &binary);
- }
-
- Optimizer opt(SPV_ENV_WEBGPU_0);
- opt.RegisterWebGPUToVulkanPasses();
-
- std::vector<uint32_t> optimized;
- class ValidatorOptions validator_options;
- ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized,
- validator_options, true));
- std::string disassembly;
- {
- SpirvTools tools(SPV_ENV_VULKAN_1_1);
- tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
- }
-
- EXPECT_EQ(GetParam().expected, disassembly)
- << "Was expecting pass '" << GetParam().pass << "' to have been run.\n";
-}
-
-INSTANTIATE_TEST_SUITE_P(
- Optimizer, WebGPUToVulkanPassTest,
- ::testing::ValuesIn(std::vector<WebGPUToVulkanPassCase>{
- // Decompose Initialized Variables
- {// input
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%uint = OpTypeInt 32 0\n"
- "%_ptr_Function_uint = OpTypePointer Function %uint\n"
- "%4 = OpConstantNull %uint\n"
- "%void = OpTypeVoid\n"
- "%6 = OpTypeFunction %void\n"
- "%1 = OpFunction %void None %6\n"
- "%7 = OpLabel\n"
- "%8 = OpVariable %_ptr_Function_uint Function %4\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // expected
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%uint = OpTypeInt 32 0\n"
- "%_ptr_Function_uint = OpTypePointer Function %uint\n"
- "%4 = OpConstantNull %uint\n"
- "%void = OpTypeVoid\n"
- "%6 = OpTypeFunction %void\n"
- "%1 = OpFunction %void None %6\n"
- "%7 = OpLabel\n"
- "%8 = OpVariable %_ptr_Function_uint Function\n"
- "OpStore %8 %4\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // pass
- "decompose-initialized-variables"},
- // Compact IDs
- {// input
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1000 \"shader\"\n"
- "%10 = OpTypeVoid\n"
- "%100 = OpTypeFunction %10\n"
- "%1000 = OpFunction %10 None %100\n"
- "%10000 = OpLabel\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // expected
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModel\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical Vulkan\n"
- "OpEntryPoint Vertex %1 \"shader\"\n"
- "%void = OpTypeVoid\n"
- "%3 = OpTypeFunction %void\n"
- "%1 = OpFunction %void None %3\n"
- "%4 = OpLabel\n"
- "OpReturn\n"
- "OpFunctionEnd\n",
- // pass
- "compact-ids"}}));
TEST(Optimizer, RemoveNop) {
// Test that OpNops are removed even if no optimizations are run.
@@ -754,7 +262,7 @@
<< before << "\n";
std::string disassembly;
{
- SpirvTools tools(SPV_ENV_WEBGPU_0);
+ SpirvTools tools(SPV_ENV_VULKAN_1_1);
tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
}
@@ -762,6 +270,124 @@
<< "Was expecting the OpNop to have been removed.";
}
+TEST(Optimizer, AvoidIntegrityCheckForExtraLineInfo) {
+ // Test that it avoids the integrity check when no optimizations are run and
+ // OpLines are propagated.
+ const std::string before = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%1 = OpString "Test"
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%_ptr_Function_uint = OpTypePointer Function %uint
+%6 = OpFunction %void None %3
+%7 = OpLabel
+OpLine %1 10 0
+%8 = OpVariable %_ptr_Function_uint Function
+OpLine %1 10 0
+%9 = OpVariable %_ptr_Function_uint Function
+OpLine %1 20 0
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string after = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%1 = OpString "Test"
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%_ptr_Function_uint = OpTypePointer Function %uint
+%6 = OpFunction %void None %3
+%7 = OpLabel
+OpLine %1 10 0
+%8 = OpVariable %_ptr_Function_uint Function
+%9 = OpVariable %_ptr_Function_uint Function
+OpLine %1 20 0
+OpReturn
+OpFunctionEnd
+)";
+
+ std::vector<uint32_t> binary;
+ SpirvTools tools(SPV_ENV_VULKAN_1_1);
+ tools.Assemble(before, &binary);
+
+ Optimizer opt(SPV_ENV_VULKAN_1_1);
+
+ std::vector<uint32_t> optimized;
+ class ValidatorOptions validator_options;
+ ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized,
+ validator_options, true))
+ << before << "\n";
+
+ std::string disassembly;
+ tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
+
+ EXPECT_EQ(after, disassembly)
+ << "Was expecting the OpLine to have been propagated.";
+}
+
+TEST(Optimizer, AvoidIntegrityCheckForDebugScope) {
+ // Test that it avoids the integrity check when the code contains DebugScope.
+ const std::string before = R"(OpCapability Shader
+%1 = OpExtInstImport "OpenCL.DebugInfo.100"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%3 = OpString "simple_vs.hlsl"
+OpSource HLSL 600 %3
+OpName %main "main"
+%void = OpTypeVoid
+%5 = OpTypeFunction %void
+%6 = OpExtInst %void %1 DebugSource %3
+%7 = OpExtInst %void %1 DebugCompilationUnit 2 4 %6 HLSL
+%main = OpFunction %void None %5
+%14 = OpLabel
+%26 = OpExtInst %void %1 DebugScope %7
+OpReturn
+%27 = OpExtInst %void %1 DebugNoScope
+OpFunctionEnd
+)";
+
+ const std::string after = R"(OpCapability Shader
+%1 = OpExtInstImport "OpenCL.DebugInfo.100"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%3 = OpString "simple_vs.hlsl"
+OpSource HLSL 600 %3
+OpName %main "main"
+%void = OpTypeVoid
+%5 = OpTypeFunction %void
+%6 = OpExtInst %void %1 DebugSource %3
+%7 = OpExtInst %void %1 DebugCompilationUnit 2 4 %6 HLSL
+%main = OpFunction %void None %5
+%8 = OpLabel
+%11 = OpExtInst %void %1 DebugScope %7
+OpReturn
+%12 = OpExtInst %void %1 DebugNoScope
+OpFunctionEnd
+)";
+
+ std::vector<uint32_t> binary;
+ SpirvTools tools(SPV_ENV_VULKAN_1_1);
+ tools.Assemble(before, &binary);
+
+ Optimizer opt(SPV_ENV_VULKAN_1_1);
+
+ std::vector<uint32_t> optimized;
+ ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized))
+ << before << "\n";
+
+ std::string disassembly;
+ tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
+
+ EXPECT_EQ(after, disassembly)
+ << "Was expecting the result id of DebugScope to have been changed.";
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/split_invalid_unreachable_test.cpp b/test/opt/split_invalid_unreachable_test.cpp
deleted file mode 100644
index 520af01..0000000
--- a/test/opt/split_invalid_unreachable_test.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (c) 2019 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 <vector>
-
-#include "test/opt/pass_fixture.h"
-#include "test/opt/pass_utils.h"
-
-namespace spvtools {
-namespace opt {
-namespace {
-
-using SplitInvalidUnreachableTest = PassTest<::testing::Test>;
-
-std::string spirv_header = R"(OpCapability Shader
-OpCapability VulkanMemoryModel
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical Vulkan
-OpEntryPoint Vertex %1 "shader"
-%uint = OpTypeInt 32 0
-%uint_1 = OpConstant %uint 1
-%uint_2 = OpConstant %uint 2
-%void = OpTypeVoid
-%bool = OpTypeBool
-%7 = OpTypeFunction %void
-)";
-
-std::string function_head = R"(%1 = OpFunction %void None %7
-%8 = OpLabel
-OpBranch %9
-)";
-
-std::string function_tail = "OpFunctionEnd\n";
-
-std::string GetLoopMergeBlock(std::string block_id, std::string merge_id,
- std::string continue_id, std::string body_id) {
- std::string result;
- result += block_id + " = OpLabel\n";
- result += "OpLoopMerge " + merge_id + " " + continue_id + " None\n";
- result += "OpBranch " + body_id + "\n";
- return result;
-}
-
-std::string GetSelectionMergeBlock(std::string block_id,
- std::string condition_id,
- std::string merge_id, std::string true_id,
- std::string false_id) {
- std::string result;
- result += block_id + " = OpLabel\n";
- result += condition_id + " = OpSLessThan %bool %uint_1 %uint_2\n";
- result += "OpSelectionMerge " + merge_id + " None\n";
- result += "OpBranchConditional " + condition_id + " " + true_id + " " +
- false_id + "\n";
-
- return result;
-}
-
-std::string GetReturnBlock(std::string block_id) {
- std::string result;
- result += block_id + " = OpLabel\n";
- result += "OpReturn\n";
- return result;
-}
-
-std::string GetUnreachableBlock(std::string block_id) {
- std::string result;
- result += block_id + " = OpLabel\n";
- result += "OpUnreachable\n";
- return result;
-}
-
-std::string GetBranchBlock(std::string block_id, std::string target_id) {
- std::string result;
- result += block_id + " = OpLabel\n";
- result += "OpBranch " + target_id + "\n";
- return result;
-}
-
-TEST_F(SplitInvalidUnreachableTest, NoInvalidBlocks) {
- std::string input = spirv_header + function_head;
- input += GetLoopMergeBlock("%9", "%10", "%11", "%12");
- input += GetSelectionMergeBlock("%12", "%13", "%14", "%15", "%16");
- input += GetReturnBlock("%15");
- input += GetReturnBlock("%16");
- input += GetUnreachableBlock("%10");
- input += GetBranchBlock("%11", "%9");
- input += GetUnreachableBlock("%14");
- input += function_tail;
-
- SinglePassRunAndCheck<SplitInvalidUnreachablePass>(input, input,
- /* skip_nop = */ false);
-}
-
-TEST_F(SplitInvalidUnreachableTest, SelectionInLoop) {
- std::string input = spirv_header + function_head;
- input += GetLoopMergeBlock("%9", "%10", "%11", "%12");
- input += GetSelectionMergeBlock("%12", "%13", "%11", "%15", "%16");
- input += GetReturnBlock("%15");
- input += GetReturnBlock("%16");
- input += GetUnreachableBlock("%10");
- input += GetBranchBlock("%11", "%9");
- input += function_tail;
-
- std::string expected = spirv_header + function_head;
- expected += GetLoopMergeBlock("%9", "%10", "%11", "%12");
- expected += GetSelectionMergeBlock("%12", "%13", "%16", "%14", "%15");
- expected += GetReturnBlock("%14");
- expected += GetReturnBlock("%15");
- expected += GetUnreachableBlock("%10");
- expected += GetUnreachableBlock("%16");
- expected += GetBranchBlock("%11", "%9");
- expected += function_tail;
-
- SinglePassRunAndCheck<SplitInvalidUnreachablePass>(input, expected,
- /* skip_nop = */ false);
-}
-
-TEST_F(SplitInvalidUnreachableTest, LoopInSelection) {
- std::string input = spirv_header + function_head;
- input += GetSelectionMergeBlock("%9", "%10", "%11", "%12", "%13");
- input += GetLoopMergeBlock("%12", "%14", "%11", "%15");
- input += GetReturnBlock("%13");
- input += GetUnreachableBlock("%14");
- input += GetBranchBlock("%11", "%12");
- input += GetReturnBlock("%15");
- input += function_tail;
-
- std::string expected = spirv_header + function_head;
- expected += GetSelectionMergeBlock("%9", "%10", "%16", "%12", "%13");
- expected += GetLoopMergeBlock("%12", "%14", "%11", "%15");
- expected += GetReturnBlock("%13");
- expected += GetUnreachableBlock("%14");
- expected += GetUnreachableBlock("%16");
- expected += GetBranchBlock("%11", "%12");
- expected += GetReturnBlock("%15");
- expected += function_tail;
-
- SinglePassRunAndCheck<SplitInvalidUnreachablePass>(input, expected,
- /* skip_nop = */ false);
-}
-
-} // namespace
-} // namespace opt
-} // namespace spvtools
diff --git a/test/opt/strip_atomic_counter_memory_test.cpp b/test/opt/strip_atomic_counter_memory_test.cpp
deleted file mode 100644
index 90daa59..0000000
--- a/test/opt/strip_atomic_counter_memory_test.cpp
+++ /dev/null
@@ -1,406 +0,0 @@
-// Copyright (c) 2019 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 <vector>
-
-#include "test/opt/pass_fixture.h"
-#include "test/opt/pass_utils.h"
-
-namespace spvtools {
-namespace opt {
-namespace {
-
-typedef std::tuple<std::string, std::string> StripAtomicCounterMemoryParam;
-
-using MemorySemanticsModified =
- PassTest<::testing::TestWithParam<StripAtomicCounterMemoryParam>>;
-using NonMemorySemanticsUnmodifiedTest = PassTest<::testing::Test>;
-
-void operator+=(std::vector<const char*>& lhs, const char* rhs) {
- lhs.push_back(rhs);
-}
-
-std::string GetConstDecl(std::string val) {
- std::string decl;
- decl += "%uint_" + val + " = OpConstant %uint " + val;
- return decl;
-}
-
-std::string GetUnchangedString(std::string(generate_inst)(std::string),
- std::string val) {
- std::string decl = GetConstDecl(val);
- std::string inst = generate_inst(val);
-
- std::vector<const char*> result = {
- // clang-format off
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
-"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint",
- "%4 = OpVariable %_ptr_Workgroup_uint Workgroup",
- "%uint_0 = OpConstant %uint 0",
- "%uint_1 = OpConstant %uint 1",
- "%void = OpTypeVoid",
- "%8 = OpTypeFunction %void",
- decl.c_str(),
- "%1 = OpFunction %void None %8",
- "%10 = OpLabel",
- inst.c_str(),
- "OpReturn",
- "OpFunctionEnd"
- // clang-format on
- };
- return JoinAllInsts(result);
-}
-
-std::string GetChangedString(std::string(generate_inst)(std::string),
- std::string orig, std::string changed) {
- std::string orig_decl = GetConstDecl(orig);
- std::string changed_decl = GetConstDecl(changed);
- std::string inst = generate_inst(changed);
-
- std::vector<const char*> result = {
- // clang-format off
- "OpCapability Shader",
- "OpCapability VulkanMemoryModel",
- "OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical Vulkan",
- "OpEntryPoint Vertex %1 \"shader\"",
- "%uint = OpTypeInt 32 0",
-"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint",
- "%4 = OpVariable %_ptr_Workgroup_uint Workgroup",
- "%uint_0 = OpConstant %uint 0",
- "%uint_1 = OpConstant %uint 1",
- "%void = OpTypeVoid",
- "%8 = OpTypeFunction %void",
- orig_decl.c_str() };
- // clang-format on
- if (changed != "0") result += changed_decl.c_str();
- result += "%1 = OpFunction %void None %8";
- result += "%10 = OpLabel";
- result += inst.c_str();
- result += "OpReturn";
- result += "OpFunctionEnd";
- return JoinAllInsts(result);
-}
-
-std::tuple<std::string, std::string> GetInputAndExpected(
- std::string(generate_inst)(std::string),
- StripAtomicCounterMemoryParam param) {
- std::string orig = std::get<0>(param);
- std::string changed = std::get<1>(param);
- std::string input = GetUnchangedString(generate_inst, orig);
- std::string expected = orig == changed
- ? GetUnchangedString(generate_inst, changed)
- : GetChangedString(generate_inst, orig, changed);
- return std::make_tuple(input, expected);
-}
-
-std::string GetOpControlBarrierInst(std::string val) {
- return "OpControlBarrier %uint_1 %uint_1 %uint_" + val;
-}
-
-TEST_P(MemorySemanticsModified, OpControlBarrier) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpControlBarrierInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpMemoryBarrierInst(std::string val) {
- return "OpMemoryBarrier %uint_1 %uint_" + val;
-}
-
-TEST_P(MemorySemanticsModified, OpMemoryBarrier) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpMemoryBarrierInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicLoadInst(std::string val) {
- return "%11 = OpAtomicLoad %uint %4 %uint_1 %uint_" + val;
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicLoad) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicLoadInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicStoreInst(std::string val) {
- return "OpAtomicStore %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicStore) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicStoreInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicExchangeInst(std::string val) {
- return "%11 = OpAtomicExchange %uint %4 %uint_1 %uint_" + val + " %uint_0";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicExchange) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicExchangeInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicCompareExchangeInst(std::string val) {
- return "%11 = OpAtomicCompareExchange %uint %4 %uint_1 %uint_" + val +
- " %uint_" + val + " %uint_0 %uint_0";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicCompareExchange) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicCompareExchangeInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicCompareExchangeWeakInst(std::string val) {
- return "%11 = OpAtomicCompareExchangeWeak %uint %4 %uint_1 %uint_" + val +
- " %uint_" + val + " %uint_0 %uint_0";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicCompareExchangeWeak) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicCompareExchangeWeakInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicIIncrementInst(std::string val) {
- return "%11 = OpAtomicIIncrement %uint %4 %uint_1 %uint_" + val;
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicIIncrement) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicIIncrementInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicIDecrementInst(std::string val) {
- return "%11 = OpAtomicIDecrement %uint %4 %uint_1 %uint_" + val;
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicIDecrement) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicIDecrementInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicIAddInst(std::string val) {
- return "%11 = OpAtomicIAdd %uint %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicIAdd) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicIAddInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicISubInst(std::string val) {
- return "%11 = OpAtomicISub %uint %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicISub) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicISubInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicSMinInst(std::string val) {
- return "%11 = OpAtomicSMin %uint %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicSMin) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicSMinInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicUMinInst(std::string val) {
- return "%11 = OpAtomicUMin %uint %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicUMin) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicUMinInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicSMaxInst(std::string val) {
- return "%11 = OpAtomicSMax %uint %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicSMax) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicSMaxInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicUMaxInst(std::string val) {
- return "%11 = OpAtomicUMax %uint %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicUMax) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicUMaxInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicAndInst(std::string val) {
- return "%11 = OpAtomicAnd %uint %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicAnd) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicAndInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicOrInst(std::string val) {
- return "%11 = OpAtomicOr %uint %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicOr) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicOrInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicXorInst(std::string val) {
- return "%11 = OpAtomicXor %uint %4 %uint_1 %uint_" + val + " %uint_1";
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicXor) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicXorInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicFlagTestAndSetInst(std::string val) {
- return "%11 = OpAtomicFlagTestAndSet %uint %4 %uint_1 %uint_" + val;
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicFlagTestAndSet) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicFlagTestAndSetInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpAtomicFlagClearInst(std::string val) {
- return "OpAtomicFlagClear %4 %uint_1 %uint_" + val;
-}
-
-TEST_P(MemorySemanticsModified, OpAtomicFlagClear) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpAtomicFlagClearInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetOpMemoryNamedBarrierInst(std::string val) {
- return "OpMemoryNamedBarrier %4 %uint_1 %uint_" + val;
-}
-
-TEST_P(MemorySemanticsModified, OpMemoryNamedBarrier) {
- std::string input, expected;
- std::tie(input, expected) =
- GetInputAndExpected(GetOpMemoryNamedBarrierInst, GetParam());
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-// clang-format off
-INSTANTIATE_TEST_SUITE_P(
- StripAtomicCounterMemoryTest, MemorySemanticsModified,
- ::testing::ValuesIn(std::vector<StripAtomicCounterMemoryParam>({
- std::make_tuple("1024", "0"),
- std::make_tuple("5", "5"),
- std::make_tuple("1288", "264"),
- std::make_tuple("264", "264")
- })));
-// clang-format on
-
-std::string GetNoMemorySemanticsPresentInst(std::string val) {
- return "%11 = OpVariable %_ptr_Workgroup_uint Workgroup %uint_" + val;
-}
-
-TEST_F(NonMemorySemanticsUnmodifiedTest, NoMemorySemanticsPresent) {
- std::string input, expected;
- StripAtomicCounterMemoryParam param = std::make_tuple("1288", "1288");
- std::tie(input, expected) =
- GetInputAndExpected(GetNoMemorySemanticsPresentInst, param);
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-std::string GetMemorySemanticsPresentInst(std::string val) {
- return "%11 = OpAtomicIAdd %uint %4 %uint_1 %uint_" + val + " %uint_1288";
-}
-
-TEST_F(NonMemorySemanticsUnmodifiedTest, MemorySemanticsPresent) {
- std::string input, expected;
- StripAtomicCounterMemoryParam param = std::make_tuple("1288", "264");
- std::tie(input, expected) =
- GetInputAndExpected(GetMemorySemanticsPresentInst, param);
- SinglePassRunAndCheck<StripAtomicCounterMemoryPass>(input, expected,
- /* skip_nop = */ false);
-}
-
-} // namespace
-} // namespace opt
-} // namespace spvtools
diff --git a/test/target_env_test.cpp b/test/target_env_test.cpp
index 9c86e2d..4acb8ff 100644
--- a/test/target_env_test.cpp
+++ b/test/target_env_test.cpp
@@ -95,7 +95,6 @@
{"opencl2.0embedded", true, SPV_ENV_OPENCL_EMBEDDED_2_0},
{"opencl2.1embedded", true, SPV_ENV_OPENCL_EMBEDDED_2_1},
{"opencl2.2embedded", true, SPV_ENV_OPENCL_EMBEDDED_2_2},
- {"webgpu0", true, SPV_ENV_WEBGPU_0},
{"opencl2.3", false, SPV_ENV_UNIVERSAL_1_0},
{"opencl3.0", false, SPV_ENV_UNIVERSAL_1_0},
{"vulkan1.9", false, SPV_ENV_UNIVERSAL_1_0},
diff --git a/test/tools/opt/flags.py b/test/tools/opt/flags.py
index f8117d9..c79f680 100644
--- a/test/tools/opt/flags.py
+++ b/test/tools/opt/flags.py
@@ -73,10 +73,7 @@
'--remove-duplicates', '--replace-invalid-opcode', '--ssa-rewrite',
'--scalar-replacement', '--scalar-replacement=42', '--strength-reduction',
'--strip-debug', '--strip-reflect', '--vector-dce', '--workaround-1209',
- '--unify-const', '--legalize-vector-shuffle',
- '--split-invalid-unreachable', '--generate-webgpu-initializers',
- '--decompose-initialized-variables', '--graphics-robust-access',
- '--wrap-opkill', '--amd-ext-to-khr'
+ '--unify-const', '--graphics-robust-access', '--wrap-opkill', '--amd-ext-to-khr'
]
expected_passes = [
'wrap-opkill',
@@ -124,10 +121,6 @@
'vector-dce',
'workaround-1209',
'unify-const',
- 'legalize-vector-shuffle',
- 'split-invalid-unreachable',
- 'generate-webgpu-initializers',
- 'decompose-initialized-variables',
'graphics-robust-access',
'wrap-opkill',
'amd-ext-to-khr'
@@ -362,45 +355,3 @@
spirv_args = ['--loop-peeling-threshold=a10f']
expected_error_substr = 'must have a positive integer argument'
-
-@inside_spirv_testsuite('SpirvOptFlags')
-class TestWebGPUToVulkanThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr):
- """Tests Vulkan->WebGPU flag cannot be used after WebGPU->Vulkan flag."""
-
- spirv_args = ['--webgpu-to-vulkan', '--vulkan-to-webgpu']
- expected_error_substr = 'Cannot use both'
-
-@inside_spirv_testsuite('SpirvOptFlags')
-class TestVulkanToWebGPUThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr):
- """Tests WebGPU->Vulkan flag cannot be used after Vulkan->WebGPU flag."""
-
- spirv_args = ['--vulkan-to-webgpu', '--webgpu-to-vulkan']
- expected_error_substr = 'Cannot use both'
-
-@inside_spirv_testsuite('SpirvOptFlags')
-class TestTargetEnvThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr):
- """Tests Vulkan->WebGPU flag cannot be used after target env flag."""
-
- spirv_args = ['--target-env=opengl4.0', '--vulkan-to-webgpu']
- expected_error_substr = 'defines the target environment'
-
-@inside_spirv_testsuite('SpirvOptFlags')
-class TestVulkanToWebGPUThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr):
- """Tests target env flag cannot be used after Vulkan->WebGPU flag."""
-
- spirv_args = ['--vulkan-to-webgpu', '--target-env=opengl4.0']
- expected_error_substr = 'defines the target environment'
-
-@inside_spirv_testsuite('SpirvOptFlags')
-class TestTargetEnvThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr):
- """Tests WebGPU->Vulkan flag cannot be used after target env flag."""
-
- spirv_args = ['--target-env=opengl4.0', '--webgpu-to-vulkan']
- expected_error_substr = 'defines the target environment'
-
-@inside_spirv_testsuite('SpirvOptFlags')
-class TestWebGPUToVulkanThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr):
- """Tests target env flag cannot be used after WebGPU->Vulkan flag."""
-
- spirv_args = ['--webgpu-to-vulkan', '--target-env=opengl4.0']
- expected_error_substr = 'defines the target environment'
diff --git a/test/unit_spirv.h b/test/unit_spirv.h
index 3264662..f0a2958 100644
--- a/test/unit_spirv.h
+++ b/test/unit_spirv.h
@@ -195,7 +195,7 @@
SPV_ENV_OPENGL_4_1, SPV_ENV_OPENGL_4_2,
SPV_ENV_OPENGL_4_3, SPV_ENV_OPENGL_4_5,
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3,
- SPV_ENV_VULKAN_1_1, SPV_ENV_WEBGPU_0,
+ SPV_ENV_VULKAN_1_1,
};
}
diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt
index 153a916..b17d1cb 100644
--- a/test/val/CMakeLists.txt
+++ b/test/val/CMakeLists.txt
@@ -89,7 +89,6 @@
val_type_unique_test.cpp
val_validation_state_test.cpp
val_version_test.cpp
- val_webgpu_test.cpp
${VAL_TEST_COMMON_SRCS}
LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}
PCH_FILE pch_test_val
diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp
index aca0f3c..c7e36f5 100644
--- a/test/val/val_atomics_test.cpp
+++ b/test/val/val_atomics_test.cpp
@@ -30,16 +30,16 @@
std::string GenerateShaderCodeImpl(
const std::string& body, const std::string& capabilities_and_extensions,
- const std::string& definitions, const std::string& memory_model) {
+ const std::string& definitions, const std::string& memory_model,
+ const std::string& execution) {
std::ostringstream ss;
ss << R"(
OpCapability Shader
)";
ss << capabilities_and_extensions;
ss << "OpMemoryModel Logical " << memory_model << "\n";
+ ss << execution;
ss << R"(
-OpEntryPoint Fragment %main "main"
-OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool
@@ -96,6 +96,10 @@
const std::string& body,
const std::string& capabilities_and_extensions = "",
const std::string& memory_model = "GLSL450") {
+ const std::string execution = R"(
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+)";
const std::string defintions = R"(
%u64 = OpTypeInt 64 0
%s64 = OpTypeInt 64 1
@@ -110,24 +114,32 @@
)";
return GenerateShaderCodeImpl(
body, "OpCapability Int64\n" + capabilities_and_extensions, defintions,
- memory_model);
+ memory_model, execution);
}
-std::string GenerateWebGPUShaderCode(
+std::string GenerateShaderComputeCode(
const std::string& body,
- const std::string& capabilities_and_extensions = "") {
- const std::string vulkan_memory_capability = R"(
-OpCapability VulkanMemoryModelDeviceScopeKHR
-OpCapability VulkanMemoryModelKHR
+ const std::string& capabilities_and_extensions = "",
+ const std::string& memory_model = "GLSL450") {
+ const std::string execution = R"(
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 32 1 1
)";
- const std::string vulkan_memory_extension = R"(
-OpExtension "SPV_KHR_vulkan_memory_model"
+ const std::string defintions = R"(
+%u64 = OpTypeInt 64 0
+%s64 = OpTypeInt 64 1
+
+%u64_1 = OpConstant %u64 1
+%s64_1 = OpConstant %s64 1
+
+%u64_ptr = OpTypePointer Workgroup %u64
+%s64_ptr = OpTypePointer Workgroup %s64
+%u64_var = OpVariable %u64_ptr Workgroup
+%s64_var = OpVariable %s64_ptr Workgroup
)";
- return GenerateShaderCodeImpl(body,
- vulkan_memory_capability +
- capabilities_and_extensions +
- vulkan_memory_extension,
- "", "VulkanKHR");
+ return GenerateShaderCodeImpl(
+ body, "OpCapability Int64\n" + capabilities_and_extensions, defintions,
+ memory_model, execution);
}
std::string GenerateKernelCode(
@@ -234,7 +246,7 @@
%val2 = OpAtomicLoad %u32 %u32_var %workgroup %acquire
)";
- CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
+ CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
@@ -358,7 +370,7 @@
%val2 = OpAtomicLoad %f32 %f32_var %workgroup %acquire
)";
- CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
+ CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
@@ -386,8 +398,9 @@
%val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire
)";
- CompileSuccessfully(GenerateShaderCode(body, "OpCapability Int64Atomics\n"),
- SPV_ENV_VULKAN_1_0);
+ CompileSuccessfully(
+ GenerateShaderComputeCode(body, "OpCapability Int64Atomics\n"),
+ SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
@@ -397,7 +410,7 @@
%val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire
)";
- CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
+ CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("64-bit atomics require the Int64Atomics capability"));
@@ -422,6 +435,23 @@
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-None-04686"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("AtomicStore: Vulkan spec only allows storage classes for "
+ "atomic to be: Uniform, Workgroup, Image, StorageBuffer, or "
+ "PhysicalStorageBuffer."));
+}
+
+TEST_F(ValidateAtomics, AtomicStoreFunctionPointerStorageType) {
+ const std::string body = R"(
+%f32_var_function = OpVariable %f32_ptr_function Function
+OpAtomicStore %f32_var_function %device %relaxed %f32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("AtomicStore: Function storage class forbidden when "
"the Shader capability is declared."));
}
@@ -501,39 +531,6 @@
"AtomicLoad: 64-bit atomics require the Int64Atomics capability"));
}
-TEST_F(ValidateAtomics, AtomicLoadWebGPUSuccess) {
- const std::string body = R"(
-%val1 = OpAtomicLoad %u32 %u32_var %queuefamily %relaxed
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateAtomics, AtomicLoadWebGPUNonQueueFamilyFailure) {
- const std::string body = R"(
-%val3 = OpAtomicLoad %u32 %u32_var %invocation %relaxed
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Memory Scope is limited to QueueFamilyKHR for "
- "OpAtomic* operations"));
-}
-
-TEST_F(ValidateAtomics, AtomicLoadWebGPUNonRelaxedFailure) {
- const std::string body = R"(
-%val1 = OpAtomicLoad %u32 %u32_var %queuefamily %acquire
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("no bits may be set for Memory Semantics of OpAtomic* "
- "instructions"));
-}
-
TEST_F(ValidateAtomics, VK_KHR_shader_atomic_int64Success) {
const std::string body = R"(
%val1 = OpAtomicUMin %u64 %u64_var %device %relaxed %u64_1
@@ -710,38 +707,6 @@
"Acquire, AcquireRelease and SequentiallyConsistent"));
}
-TEST_F(ValidateAtomics, AtomicStoreWebGPUSuccess) {
- const std::string body = R"(
-OpAtomicStore %u32_var %queuefamily %relaxed %u32_1
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-TEST_F(ValidateAtomics, AtomicStoreWebGPUNonQueueFamilyFailure) {
- const std::string body = R"(
-OpAtomicStore %u32_var %workgroup %relaxed %u32_1
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Memory Scope is limited to QueueFamilyKHR for "
- "OpAtomic* operations"));
-}
-
-TEST_F(ValidateAtomics, AtomicStoreWebGPUNonRelaxedFailure) {
- const std::string body = R"(
-OpAtomicStore %u32_var %queuefamily %release %u32_1
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("no bits may be set for Memory Semantics of OpAtomic* "
- "instructions"));
-}
-
TEST_F(ValidateAtomics, AtomicStoreWrongPointerType) {
const std::string body = R"(
OpAtomicStore %f32_1 %device %relaxed %f32_1
@@ -2032,75 +1997,6 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
-TEST_F(ValidateAtomics, WebGPUCrossDeviceMemoryScopeBad) {
- const std::string body = R"(
-%val1 = OpAtomicLoad %u32 %u32_var %cross_device %relaxed
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("in WebGPU environment Memory Scope is limited to "
- "QueueFamilyKHR for OpAtomic* operations"));
-}
-
-TEST_F(ValidateAtomics, WebGPUDeviceMemoryScopeBad) {
- const std::string body = R"(
-%val1 = OpAtomicLoad %u32 %u32_var %device %relaxed
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("in WebGPU environment Memory Scope is limited to "
- "QueueFamilyKHR for OpAtomic* operations"));
-}
-
-TEST_F(ValidateAtomics, WebGPUWorkgroupMemoryScopeBad) {
- const std::string body = R"(
-%val1 = OpAtomicLoad %u32 %u32_var %workgroup %relaxed
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("in WebGPU environment Memory Scope is limited to "
- "QueueFamilyKHR for OpAtomic* operations"));
-}
-
-TEST_F(ValidateAtomics, WebGPUSubgroupMemoryScopeBad) {
- const std::string body = R"(
-%val1 = OpAtomicLoad %u32 %u32_var %subgroup %relaxed
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("in WebGPU environment Memory Scope is limited to "
- "QueueFamilyKHR for OpAtomic* operations"));
-}
-
-TEST_F(ValidateAtomics, WebGPUInvocationMemoryScopeBad) {
- const std::string body = R"(
-%val1 = OpAtomicLoad %u32 %u32_var %invocation %relaxed
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("in WebGPU environment Memory Scope is limited to "
- "QueueFamilyKHR for OpAtomic* operations"));
-}
-
-TEST_F(ValidateAtomics, WebGPUQueueFamilyMemoryScopeGood) {
- const std::string body = R"(
-%val1 = OpAtomicLoad %u32 %u32_var %queuefamily %relaxed
-)";
-
- CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
TEST_F(ValidateAtomics, CompareExchangeWeakV13ValV14Good) {
const std::string body = R"(
%val1 = OpAtomicCompareExchangeWeak %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0
diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp
index 8bd10d4..9a4beba 100644
--- a/test/val/val_barriers_test.cpp
+++ b/test/val/val_barriers_test.cpp
@@ -121,40 +121,13 @@
execution_model, memory_model);
}
-std::string GenerateWebGPUComputeShaderCode(
- const std::string& body,
- const std::string& capabilities_and_extensions = "",
- const std::string& execution_model = "GLCompute") {
- const std::string vulkan_memory_capability = R"(
-OpCapability VulkanMemoryModelKHR
-)";
- const std::string vulkan_memory_extension = R"(
-OpExtension "SPV_KHR_vulkan_memory_model"
-)";
- const std::string memory_model = "OpMemoryModel Logical VulkanKHR";
- return GenerateShaderCodeImpl(body,
- vulkan_memory_capability +
- capabilities_and_extensions +
- vulkan_memory_extension,
- "", execution_model, memory_model);
-}
-
-std::string GenerateWebGPUVertexShaderCode(
+std::string GenerateVulkanVertexShaderCode(
const std::string& body,
const std::string& capabilities_and_extensions = "",
const std::string& execution_model = "Vertex") {
- const std::string vulkan_memory_capability = R"(
-OpCapability VulkanMemoryModelKHR
-)";
- const std::string vulkan_memory_extension = R"(
-OpExtension "SPV_KHR_vulkan_memory_model"
-)";
- const std::string memory_model = "OpMemoryModel Logical VulkanKHR";
- return GenerateShaderCodeImpl(body,
- vulkan_memory_capability +
- capabilities_and_extensions +
- vulkan_memory_extension,
- "", execution_model, memory_model);
+ const std::string memory_model = "OpMemoryModel Logical GLSL450";
+ return GenerateShaderCodeImpl(body, capabilities_and_extensions, "",
+ execution_model, memory_model);
}
std::string GenerateKernelCode(
@@ -271,64 +244,6 @@
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
-TEST_F(ValidateBarriers, OpControlBarrierWebGPUAcquireReleaseSuccess) {
- const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_release_workgroup
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateBarriers, OpControlBarrierWebGPURelaxedFailure) {
- const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %workgroup
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, AcquireRelease must be set for Memory "
- "Semantics of OpControlBarrier"));
-}
-
-TEST_F(ValidateBarriers, OpControlBarrierWebGPUMissingWorkgroupFailure) {
- const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_release
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, WorkgroupMemory must be set for Memory "
- "Semantics"));
-}
-
-TEST_F(ValidateBarriers, OpControlBarrierWebGPUUniformFailure) {
- const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("For WebGPU only WorkgroupMemory and AcquireRelease may be set "
- "for Memory Semantics of OpControlBarrier."));
-}
-
-TEST_F(ValidateBarriers, OpControlBarrierWebGPUReleaseFailure) {
- const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %release_uniform_workgroup
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, AcquireRelease must be set for Memory "
- "Semantics of OpControlBarrier"));
-}
-
TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv12) {
const std::string body = R"(
OpControlBarrier %device %device %none
@@ -435,44 +350,6 @@
"is limited to Workgroup and Subgroup"));
}
-TEST_F(ValidateBarriers, OpControlBarrierWebGPUExecutionScopeDeviceBad) {
- const std::string body = R"(
-OpControlBarrier %device %workgroup %none
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("ControlBarrier: in WebGPU environment Execution Scope "
- "is limited to Workgroup"));
-}
-
-TEST_F(ValidateBarriers, OpControlBarrierWebGPUExecutionScopeSubgroupBad) {
- const std::string body = R"(
-OpControlBarrier %subgroup %workgroup %none
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("ControlBarrier: in WebGPU environment Execution Scope "
- "is limited to Workgroup"));
-}
-
-TEST_F(ValidateBarriers,
- OpControlBarrierWebGPUExecutionScopeWorkgroupNonComputeBad) {
- const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_release_workgroup
-)";
-
- CompileSuccessfully(GenerateWebGPUVertexShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr(
- "Workgroup Execution Scope is limited to GLCompute execution model"));
-}
-
TEST_F(ValidateBarriers, OpControlBarrierVulkanMemoryScopeSubgroup) {
const std::string body = R"(
OpControlBarrier %subgroup %subgroup %none
@@ -480,6 +357,8 @@
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-None-04638"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("ControlBarrier: in Vulkan 1.0 environment Memory Scope is "
@@ -503,20 +382,33 @@
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-None-04638"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("ControlBarrier: in Vulkan environment, Memory Scope "
"cannot be CrossDevice"));
}
-TEST_F(ValidateBarriers, OpControlBarrierWebGPUMemoryScopeNonWorkgroup) {
+TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeFailure) {
const std::string body = R"(
-OpControlBarrier %workgroup %subgroup %acquire_release_workgroup
+OpControlBarrier %workgroup %workgroup %acquire
)";
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
+ CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("ControlBarrier: in WebGPU environment Memory Scope is "
- "limited to Workgroup for OpControlBarrier"));
+ AnyVUID("VUID-StandaloneSpirv-None-04639"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Workgroup Memory Scope is limited to MeshNV, TaskNV, "
+ "and GLCompute execution model"));
+}
+
+TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeSuccess) {
+ const std::string body = R"(
+OpControlBarrier %workgroup %workgroup %acquire
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
}
TEST_F(ValidateBarriers, OpControlBarrierAcquireAndRelease) {
@@ -738,100 +630,6 @@
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
-TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUImageMemorySuccess) {
- const std::string body = R"(
-OpMemoryBarrier %workgroup %image_memory
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUDeviceFailure) {
- const std::string body = R"(
-OpMemoryBarrier %subgroup %image_memory
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("in WebGPU environment Memory Scope is limited to "
- "Workgroup for OpMemoryBarrier"));
-}
-
-TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireReleaseFailure) {
- const std::string body = R"(
-OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("ImageMemory must be set for Memory Semantics of "
- "OpMemoryBarrier"));
-}
-
-TEST_F(ValidateBarriers, OpMemoryBarrierWebGPURelaxedFailure) {
- const std::string body = R"(
-OpMemoryBarrier %workgroup %uniform_workgroup
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("ImageMemory must be set for Memory Semantics of "
- "OpMemoryBarrier"));
-}
-
-TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireFailure) {
- const std::string body = R"(
-OpMemoryBarrier %workgroup %acquire_uniform_workgroup
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("ImageMemory must be set for Memory Semantics of "
- "OpMemoryBarrier"));
-}
-
-TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUReleaseFailure) {
- const std::string body = R"(
-OpMemoryBarrier %workgroup %release_uniform_workgroup
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("ImageMemory must be set for Memory Semantics of "
- "OpMemoryBarrier"));
-}
-
-TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUUniformFailure) {
- const std::string body = R"(
-OpMemoryBarrier %workgroup %uniform_image_memory
-)";
-
- CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("only ImageMemory may be set for Memory Semantics of "
- "OpMemoryBarrier"));
-}
-
-TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUWorkgroupNonComputeFailure) {
- const std::string body = R"(
-OpMemoryBarrier %workgroup %image_memory
-)";
-
- CompileSuccessfully(GenerateWebGPUVertexShaderCode(body), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr(
- "Workgroup Memory Scope is limited to GLCompute execution model"));
-}
-
TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemoryScope) {
const std::string body = R"(
OpMemoryBarrier %f32_1 %acquire_release_uniform_workgroup
@@ -885,6 +683,8 @@
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-None-04638"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("MemoryBarrier: in Vulkan 1.0 environment Memory Scope is "
@@ -920,6 +720,8 @@
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-OpMemoryBarrier-04649"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("MemoryBarrier: Vulkan specification requires Memory Semantics "
@@ -935,6 +737,8 @@
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-OpMemoryBarrier-04649"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
"Vulkan-supported storage class"));
}
@@ -947,6 +751,8 @@
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-OpMemoryBarrier-04649"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
"Vulkan-supported storage class"));
}
@@ -1629,6 +1435,8 @@
SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-None-04640"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp
index 74d5c3a..bbcdbb1 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -54,18 +54,14 @@
using ::testing::ValuesIn;
using ValidateBuiltIns = spvtest::ValidateBase<bool>;
-using ValidateVulkanSubgroupBuiltIns = spvtest::ValidateBase<
- std::tuple<const char*, const char*, const char*, const char*, TestResult>>;
+using ValidateVulkanSubgroupBuiltIns =
+ spvtest::ValidateBase<std::tuple<const char*, const char*, const char*,
+ const char*, const char*, TestResult>>;
using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult =
spvtest::ValidateBase<std::tuple<const char*, const char*, const char*,
const char*, const char*, TestResult>>;
-using ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult =
- spvtest::ValidateBase<std::tuple<const char*, const char*, const char*,
- const char*, TestResult>>;
using ValidateVulkanCombineBuiltInArrayedVariable = spvtest::ValidateBase<
std::tuple<const char*, const char*, const char*, const char*, TestResult>>;
-using ValidateWebGPUCombineBuiltInArrayedVariable = spvtest::ValidateBase<
- std::tuple<const char*, const char*, const char*, const char*, TestResult>>;
using ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult =
spvtest::ValidateBase<
std::tuple<const char*, const char*, const char*, const char*,
@@ -76,22 +72,19 @@
const char*, const char*, const char*,
const char*, const char*, TestResult>>;
-bool InitializerRequired(spv_target_env env, const char* const storage_class) {
- return spvIsWebGPUEnv(env) && (strncmp(storage_class, "Output", 6) == 0 ||
- strncmp(storage_class, "Private", 7) == 0 ||
- strncmp(storage_class, "Function", 8) == 0);
+bool InitializerRequired(const char* const storage_class) {
+ return (strncmp(storage_class, "Output", 6) == 0 ||
+ strncmp(storage_class, "Private", 7) == 0 ||
+ strncmp(storage_class, "Function", 8) == 0);
}
-CodeGenerator GetInMainCodeGenerator(spv_target_env env,
- const char* const built_in,
+CodeGenerator GetInMainCodeGenerator(const char* const built_in,
const char* const execution_model,
const char* const storage_class,
const char* const capabilities,
const char* const extensions,
const char* const data_type) {
- CodeGenerator generator =
- spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
if (capabilities) {
generator.capabilities_ += capabilities;
@@ -107,13 +100,13 @@
std::ostringstream after_types;
after_types << "%built_in_type = OpTypeStruct " << data_type << "\n";
- if (InitializerRequired(env, storage_class)) {
+ if (InitializerRequired(storage_class)) {
after_types << "%built_in_null = OpConstantNull %built_in_type\n";
}
after_types << "%built_in_ptr = OpTypePointer " << storage_class
<< " %built_in_type\n";
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
- if (InitializerRequired(env, storage_class)) {
+ if (InitializerRequired(storage_class)) {
after_types << " %built_in_null";
}
after_types << "\n";
@@ -158,44 +151,6 @@
return generator;
}
-// Allows test parameter test to list all possible VUIDs with a delimiter that
-// is then split here to check if one VUID was in the error message
-MATCHER_P(AnyVUID, vuid_set, "VUID from the set is in error message") {
- // use space as delimiter because clang-format will properly line break VUID
- // strings which is important the entire VUID is in a single line for script
- // to scan
- std::string delimiter = " ";
- std::string token;
- std::string vuids = std::string(vuid_set);
- size_t position;
-
- // Catch case were someone accidentally left spaces by trimming string
- // clang-format off
- vuids.erase(std::find_if(vuids.rbegin(), vuids.rend(), [](unsigned char c) {
- return (c != ' ');
- }).base(), vuids.end());
- vuids.erase(vuids.begin(), std::find_if(vuids.begin(), vuids.end(), [](unsigned char c) {
- return (c != ' ');
- }));
- // clang-format on
-
- do {
- position = vuids.find(delimiter);
- if (position != std::string::npos) {
- token = vuids.substr(0, position);
- vuids.erase(0, position + delimiter.length());
- } else {
- token = vuids.substr(0); // last item
- }
-
- // arg contains diagnostic message
- if (arg.find(token) != std::string::npos) {
- return true;
- }
- } while (position != std::string::npos);
- return false;
-}
-
TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) {
const char* const built_in = std::get<0>(GetParam());
const char* const execution_model = std::get<1>(GetParam());
@@ -204,9 +159,8 @@
const char* const vuid = std::get<4>(GetParam());
const TestResult& test_result = std::get<5>(GetParam());
- CodeGenerator generator =
- GetInMainCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model,
- storage_class, NULL, NULL, data_type);
+ CodeGenerator generator = GetInMainCodeGenerator(
+ built_in, execution_model, storage_class, NULL, NULL, data_type);
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(test_result.validation_result,
@@ -222,28 +176,6 @@
}
}
-TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InMain) {
- const char* const built_in = std::get<0>(GetParam());
- const char* const execution_model = std::get<1>(GetParam());
- const char* const storage_class = std::get<2>(GetParam());
- const char* const data_type = std::get<3>(GetParam());
- const TestResult& test_result = std::get<4>(GetParam());
-
- CodeGenerator generator =
- GetInMainCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model,
- storage_class, NULL, NULL, data_type);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(test_result.validation_result,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- if (test_result.error_str) {
- EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
- }
- if (test_result.error_str2) {
- EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
- }
-}
-
TEST_P(
ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
InMain) {
@@ -256,9 +188,9 @@
const char* const vuid = std::get<6>(GetParam());
const TestResult& test_result = std::get<7>(GetParam());
- CodeGenerator generator = GetInMainCodeGenerator(
- SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class,
- capabilities, extensions, data_type);
+ CodeGenerator generator =
+ GetInMainCodeGenerator(built_in, execution_model, storage_class,
+ capabilities, extensions, data_type);
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(test_result.validation_result,
@@ -288,7 +220,7 @@
const TestResult& test_result = std::get<8>(GetParam());
CodeGenerator generator =
- GetInMainCodeGenerator(env, built_in, execution_model, storage_class,
+ GetInMainCodeGenerator(built_in, execution_model, storage_class,
capabilities, extensions, data_type);
CompileSuccessfully(generator.Build(), env);
@@ -304,16 +236,13 @@
}
}
-CodeGenerator GetInFunctionCodeGenerator(spv_target_env env,
- const char* const built_in,
+CodeGenerator GetInFunctionCodeGenerator(const char* const built_in,
const char* const execution_model,
const char* const storage_class,
const char* const capabilities,
const char* const extensions,
const char* const data_type) {
- CodeGenerator generator =
- spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
if (capabilities) {
generator.capabilities_ += capabilities;
@@ -328,13 +257,13 @@
std::ostringstream after_types;
after_types << "%built_in_type = OpTypeStruct " << data_type << "\n";
- if (InitializerRequired(env, storage_class)) {
+ if (InitializerRequired(storage_class)) {
after_types << "%built_in_null = OpConstantNull %built_in_type\n";
}
after_types << "%built_in_ptr = OpTypePointer " << storage_class
<< " %built_in_type\n";
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
- if (InitializerRequired(env, storage_class)) {
+ if (InitializerRequired(storage_class)) {
after_types << " %built_in_null";
}
after_types << "\n";
@@ -383,11 +312,7 @@
OpFunctionEnd
)";
- if (spvIsWebGPUEnv(env)) {
- generator.after_types_ += function_body;
- } else {
- generator.add_at_the_end_ = function_body;
- }
+ generator.add_at_the_end_ = function_body;
generator.entry_points_.push_back(std::move(entry_point));
@@ -402,9 +327,8 @@
const char* const vuid = std::get<4>(GetParam());
const TestResult& test_result = std::get<5>(GetParam());
- CodeGenerator generator =
- GetInFunctionCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model,
- storage_class, NULL, NULL, data_type);
+ CodeGenerator generator = GetInFunctionCodeGenerator(
+ built_in, execution_model, storage_class, NULL, NULL, data_type);
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(test_result.validation_result,
@@ -420,28 +344,6 @@
}
}
-TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InFunction) {
- const char* const built_in = std::get<0>(GetParam());
- const char* const execution_model = std::get<1>(GetParam());
- const char* const storage_class = std::get<2>(GetParam());
- const char* const data_type = std::get<3>(GetParam());
- const TestResult& test_result = std::get<4>(GetParam());
-
- CodeGenerator generator =
- GetInFunctionCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model,
- storage_class, NULL, NULL, data_type);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(test_result.validation_result,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- if (test_result.error_str) {
- EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
- }
- if (test_result.error_str2) {
- EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
- }
-}
-
TEST_P(
ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
InFunction) {
@@ -454,9 +356,9 @@
const char* const vuid = std::get<6>(GetParam());
const TestResult& test_result = std::get<7>(GetParam());
- CodeGenerator generator = GetInFunctionCodeGenerator(
- SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class,
- capabilities, extensions, data_type);
+ CodeGenerator generator =
+ GetInFunctionCodeGenerator(built_in, execution_model, storage_class,
+ capabilities, extensions, data_type);
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(test_result.validation_result,
@@ -472,16 +374,13 @@
}
}
-CodeGenerator GetVariableCodeGenerator(spv_target_env env,
- const char* const built_in,
+CodeGenerator GetVariableCodeGenerator(const char* const built_in,
const char* const execution_model,
const char* const storage_class,
const char* const capabilities,
const char* const extensions,
const char* const data_type) {
- CodeGenerator generator =
- spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
if (capabilities) {
generator.capabilities_ += capabilities;
@@ -495,13 +394,13 @@
generator.before_types_ += "\n";
std::ostringstream after_types;
- if (InitializerRequired(env, storage_class)) {
+ if (InitializerRequired(storage_class)) {
after_types << "%built_in_null = OpConstantNull " << data_type << "\n";
}
after_types << "%built_in_ptr = OpTypePointer " << storage_class << " "
<< data_type << "\n";
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
- if (InitializerRequired(env, storage_class)) {
+ if (InitializerRequired(storage_class)) {
after_types << " %built_in_null";
}
after_types << "\n";
@@ -553,9 +452,8 @@
const char* const vuid = std::get<4>(GetParam());
const TestResult& test_result = std::get<5>(GetParam());
- CodeGenerator generator =
- GetVariableCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model,
- storage_class, NULL, NULL, data_type);
+ CodeGenerator generator = GetVariableCodeGenerator(
+ built_in, execution_model, storage_class, NULL, NULL, data_type);
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(test_result.validation_result,
@@ -571,28 +469,6 @@
}
}
-TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, Variable) {
- const char* const built_in = std::get<0>(GetParam());
- const char* const execution_model = std::get<1>(GetParam());
- const char* const storage_class = std::get<2>(GetParam());
- const char* const data_type = std::get<3>(GetParam());
- const TestResult& test_result = std::get<4>(GetParam());
-
- CodeGenerator generator =
- GetVariableCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model,
- storage_class, NULL, NULL, data_type);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(test_result.validation_result,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- if (test_result.error_str) {
- EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
- }
- if (test_result.error_str2) {
- EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
- }
-}
-
TEST_P(
ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
Variable) {
@@ -605,9 +481,9 @@
const char* const vuid = std::get<6>(GetParam());
const TestResult& test_result = std::get<7>(GetParam());
- CodeGenerator generator = GetVariableCodeGenerator(
- SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class,
- capabilities, extensions, data_type);
+ CodeGenerator generator =
+ GetVariableCodeGenerator(built_in, execution_model, storage_class,
+ capabilities, extensions, data_type);
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(test_result.validation_result,
@@ -642,10 +518,26 @@
Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
+ ClipAndCullDistanceInvalidStorageClass,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
+ Combine(Values("ClipDistance", "CullDistance"),
+ Values("Vertex", "Geometry", "TessellationControl",
+ "TessellationEvaluation"),
+ Values("Private"), Values("%f32arr2", "%f32arr4"),
+ Values("VUID-ClipDistance-ClipDistance-04190 "
+ "VUID-CullDistance-CullDistance-04199"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "to be only used for variables with Input or Output storage "
+ "class."))));
+
+INSTANTIATE_TEST_SUITE_P(
ClipAndCullDistanceFragmentOutput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("ClipDistance", "CullDistance"), Values("Fragment"),
- Values("Output"), Values("%f32arr4"), Values(nullptr),
+ Values("Output"), Values("%f32arr4"),
+ Values("VUID-ClipDistance-ClipDistance-04189 "
+ "VUID-CullDistance-CullDistance-04198"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance "
@@ -654,20 +546,22 @@
"which is called with execution model Fragment."))));
INSTANTIATE_TEST_SUITE_P(
- VertexIdAndInstanceIdVertexInput,
+ VertexIdVertexInput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("VertexId", "InstanceId"), Values("Vertex"), Values("Input"),
- Values("%u32"), Values(nullptr),
- Values(TestResult(
- SPV_ERROR_INVALID_DATA,
- "Vulkan spec doesn't allow BuiltIn VertexId/InstanceId to be "
- "used."))));
+ Combine(
+ Values("VertexId"), Values("Vertex"), Values("Input"), Values("%u32"),
+ Values(nullptr),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec doesn't allow BuiltIn VertexId to be "
+ "used."))));
INSTANTIATE_TEST_SUITE_P(
ClipAndCullDistanceVertexInput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("ClipDistance", "CullDistance"), Values("Vertex"),
- Values("Input"), Values("%f32arr4"), Values(nullptr),
+ Values("Input"), Values("%f32arr4"),
+ Values("VUID-ClipDistance-ClipDistance-04188 "
+ "VUID-CullDistance-CullDistance-04197"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance "
@@ -726,11 +620,6 @@
Values("%f32vec4"), Values(nullptr), Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
- FragCoordSuccess, ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FragCoord"), Values("Fragment"), Values("Input"),
- Values("%f32vec4"), Values(TestResult())));
-
-INSTANTIATE_TEST_SUITE_P(
FragCoordNotFragment,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(
@@ -743,15 +632,6 @@
"to be used only with Fragment execution model"))));
INSTANTIATE_TEST_SUITE_P(
- FragCoordNotFragment,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("FragCoord"), Values("Vertex", "GLCompute"), Values("Input"),
- Values("%f32vec4"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "to be used only with Fragment execution model"))));
-
-INSTANTIATE_TEST_SUITE_P(
FragCoordNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("FragCoord"), Values("Fragment"), Values("Output"),
Values("%f32vec4"), Values("VUID-FragCoord-FragCoord-04211"),
@@ -761,15 +641,6 @@
"uses storage class Output"))));
INSTANTIATE_TEST_SUITE_P(
- FragCoordNotInput, ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FragCoord"), Values("Fragment"), Values("Output"),
- Values("%f32vec4"),
- Values(TestResult(
- SPV_ERROR_INVALID_DATA,
- "to be only used for variables with Input storage class",
- "uses storage class Output"))));
-
-INSTANTIATE_TEST_SUITE_P(
FragCoordNotFloatVector,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("FragCoord"), Values("Fragment"), Values("Input"),
@@ -780,15 +651,6 @@
"is not a float vector"))));
INSTANTIATE_TEST_SUITE_P(
- FragCoordNotFloatVector,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FragCoord"), Values("Fragment"), Values("Input"),
- Values("%f32arr4", "%u32vec4"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 4-component 32-bit float vector",
- "is not a float vector"))));
-
-INSTANTIATE_TEST_SUITE_P(
FragCoordNotFloatVec4,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("FragCoord"), Values("Fragment"), Values("Input"),
@@ -798,15 +660,6 @@
"has 3 components"))));
INSTANTIATE_TEST_SUITE_P(
- FragCoordNotFloatVec4,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FragCoord"), Values("Fragment"), Values("Input"),
- Values("%f32vec3"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 4-component 32-bit float vector",
- "has 3 components"))));
-
-INSTANTIATE_TEST_SUITE_P(
FragCoordNotF32Vec4,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("FragCoord"), Values("Fragment"), Values("Input"),
@@ -821,11 +674,6 @@
Values("%f32"), Values(nullptr), Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
- FragDepthSuccess, ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FragDepth"), Values("Fragment"), Values("Output"),
- Values("%f32"), Values(TestResult())));
-
-INSTANTIATE_TEST_SUITE_P(
FragDepthNotFragment,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(
@@ -838,15 +686,6 @@
"to be used only with Fragment execution model"))));
INSTANTIATE_TEST_SUITE_P(
- FragDepthNotFragment,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("FragDepth"), Values("Vertex", "GLCompute"), Values("Output"),
- Values("%f32"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "to be used only with Fragment execution model"))));
-
-INSTANTIATE_TEST_SUITE_P(
FragDepthNotOutput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("FragDepth"), Values("Fragment"), Values("Input"),
@@ -857,16 +696,6 @@
"uses storage class Input"))));
INSTANTIATE_TEST_SUITE_P(
- FragDepthNotOutput,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FragDepth"), Values("Fragment"), Values("Input"),
- Values("%f32"),
- Values(TestResult(
- SPV_ERROR_INVALID_DATA,
- "to be only used for variables with Output storage class",
- "uses storage class Input"))));
-
-INSTANTIATE_TEST_SUITE_P(
FragDepthNotFloatScalar,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("FragDepth"), Values("Fragment"), Values("Output"),
@@ -877,15 +706,6 @@
"is not a float scalar"))));
INSTANTIATE_TEST_SUITE_P(
- FragDepthNotFloatScalar,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FragDepth"), Values("Fragment"), Values("Output"),
- Values("%f32vec4", "%u32"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 32-bit float scalar",
- "is not a float scalar"))));
-
-INSTANTIATE_TEST_SUITE_P(
FragDepthNotF32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("FragDepth"), Values("Fragment"), Values("Output"),
Values("%f64"), Values("VUID-FragDepth-FragDepth-04215"),
@@ -901,12 +721,6 @@
Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
- FrontFacingSuccess,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FrontFacing"), Values("Fragment"), Values("Input"),
- Values("%bool"), Values(TestResult())));
-
-INSTANTIATE_TEST_SUITE_P(
FrontFacingAndHelperInvocationNotFragment,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(
@@ -920,15 +734,6 @@
"to be used only with Fragment execution model"))));
INSTANTIATE_TEST_SUITE_P(
- FrontFacingNotFragment,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("FrontFacing"), Values("Vertex", "GLCompute"), Values("Input"),
- Values("%bool"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "to be used only with Fragment execution model"))));
-
-INSTANTIATE_TEST_SUITE_P(
FrontFacingAndHelperInvocationNotInput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("FrontFacing", "HelperInvocation"), Values("Fragment"),
@@ -941,16 +746,6 @@
"uses storage class Output"))));
INSTANTIATE_TEST_SUITE_P(
- FrontFacingNotInput,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FrontFacing"), Values("Fragment"), Values("Output"),
- Values("%bool"),
- Values(TestResult(
- SPV_ERROR_INVALID_DATA,
- "to be only used for variables with Input storage class",
- "uses storage class Output"))));
-
-INSTANTIATE_TEST_SUITE_P(
FrontFacingAndHelperInvocationNotBool,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("FrontFacing", "HelperInvocation"), Values("Fragment"),
@@ -962,15 +757,6 @@
"is not a bool scalar"))));
INSTANTIATE_TEST_SUITE_P(
- FrontFacingNotBool,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("FrontFacing"), Values("Fragment"), Values("Input"),
- Values("%f32", "%u32"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a bool scalar",
- "is not a bool scalar"))));
-
-INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3Success,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",
@@ -979,13 +765,6 @@
Values(nullptr), Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
- ComputeShaderInputInt32Vec3Success,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
- Values("GLCompute"), Values("Input"), Values("%u32vec3"),
- Values(TestResult())));
-
-INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotGLCompute,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(
@@ -1002,15 +781,6 @@
"to be used only with GLCompute execution model"))));
INSTANTIATE_TEST_SUITE_P(
- ComputeShaderInputInt32Vec3NotGLCompute,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
- Values("Vertex", "Fragment"), Values("Input"), Values("%u32vec3"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "to be used only with GLCompute execution model"))));
-
-INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotInput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",
@@ -1026,16 +796,6 @@
"uses storage class Output"))));
INSTANTIATE_TEST_SUITE_P(
- ComputeShaderInputInt32Vec3NotInput,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
- Values("GLCompute"), Values("Output"), Values("%u32vec3"),
- Values(TestResult(
- SPV_ERROR_INVALID_DATA,
- "to be only used for variables with Input storage class",
- "uses storage class Output"))));
-
-INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotIntVector,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",
@@ -1051,16 +811,6 @@
"is not an int vector"))));
INSTANTIATE_TEST_SUITE_P(
- ComputeShaderInputInt32Vec3NotIntVector,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
- Values("GLCompute"), Values("Input"),
- Values("%u32arr3", "%f32vec3"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 3-component 32-bit int vector",
- "is not an int vector"))));
-
-INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotIntVec3,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",
@@ -1075,15 +825,6 @@
"has 4 components"))));
INSTANTIATE_TEST_SUITE_P(
- ComputeShaderInputInt32Vec3NotIntVec3,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
- Values("GLCompute"), Values("Input"), Values("%u32vec4"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 3-component 32-bit int vector",
- "has 4 components"))));
-
-INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotInt32Vec,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",
@@ -1153,12 +894,6 @@
Values("%u32"), Values(nullptr), Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
- InstanceIndexSuccess,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"),
- Values("%u32"), Values(TestResult())));
-
-INSTANTIATE_TEST_SUITE_P(
InstanceIndexInvalidExecutionModel,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("InstanceIndex"),
@@ -1170,14 +905,6 @@
"to be used only with Vertex execution model"))));
INSTANTIATE_TEST_SUITE_P(
- InstanceIndexInvalidExecutionModel,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("InstanceIndex"), Values("Fragment", "GLCompute"),
- Values("Input"), Values("%u32"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "to be used only with Vertex execution model"))));
-
-INSTANTIATE_TEST_SUITE_P(
InstanceIndexNotInput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("InstanceIndex"), Values("Vertex"), Values("Output"),
@@ -1188,16 +915,6 @@
"uses storage class Output"))));
INSTANTIATE_TEST_SUITE_P(
- InstanceIndexNotInput,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("InstanceIndex"), Values("Vertex"), Values("Output"),
- Values("%u32"),
- Values(TestResult(
- SPV_ERROR_INVALID_DATA,
- "to be only used for variables with Input storage class",
- "uses storage class Output"))));
-
-INSTANTIATE_TEST_SUITE_P(
InstanceIndexNotIntScalar,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"),
@@ -1208,15 +925,6 @@
"is not an int scalar"))));
INSTANTIATE_TEST_SUITE_P(
- InstanceIndexNotIntScalar,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"),
- Values("%f32", "%u32vec3"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 32-bit int scalar",
- "is not an int scalar"))));
-
-INSTANTIATE_TEST_SUITE_P(
InstanceIndexNotInt32,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"),
@@ -1256,7 +964,8 @@
ViewportIndexExecutionModelEnabledByCapability,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("ViewportIndex"), Values("Vertex", "TessellationEvaluation"),
- Values("Output"), Values("%u32"), Values(nullptr),
+ Values("Output"), Values("%u32"),
+ Values("VUID-ViewportIndex-ViewportIndex-04405"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"ShaderViewportIndexLayerEXT or ShaderViewportIndex"))));
@@ -1265,7 +974,7 @@
LayerExecutionModelEnabledByCapability,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("Layer"), Values("Vertex", "TessellationEvaluation"),
- Values("Output"), Values("%u32"), Values(nullptr),
+ Values("Output"), Values("%u32"), Values("VUID-Layer-Layer-04273"),
Values(TestResult(SPV_ERROR_INVALID_DATA,
"ShaderViewportIndexLayerEXT or ShaderLayer"))));
@@ -1507,21 +1216,6 @@
Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
- PositionOutputSuccess,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("Position"), Values("Vertex"), Values("Output"),
- Values("%f32vec4"), Values(TestResult())));
-
-INSTANTIATE_TEST_SUITE_P(
- PositionOutputFailure,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("Position"), Values("Fragment", "GLCompute"),
- Values("Output"), Values("%f32vec4"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "WebGPU spec allows BuiltIn Position to be used "
- "only with the Vertex execution model."))));
-
-INSTANTIATE_TEST_SUITE_P(
PositionInputSuccess,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("Position"),
@@ -1530,20 +1224,22 @@
Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
- PositionInputFailure,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("Position"), Values("Vertex", "Fragment", "GLCompute"),
- Values("Input"), Values("%f32vec4"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "WebGPU spec allows BuiltIn Position to be only used "
- "for variables with Output storage class"))));
+ PositionInvalidStorageClass,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
+ Combine(Values("Position"),
+ Values("Geometry", "TessellationControl", "TessellationEvaluation"),
+ Values("Private"), Values("%f32vec4"),
+ Values("VUID-Position-Position-04320"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "Vulkan spec allows BuiltIn Position to be only used for "
+ "variables with Input or Output storage class."))));
INSTANTIATE_TEST_SUITE_P(
PositionVertexInput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("Position"), Values("Vertex"), Values("Input"),
- Values("%f32vec4"), Values("VUID-Position-Position-04320"),
+ Values("%f32vec4"), Values("VUID-Position-Position-04319"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"Vulkan spec doesn't allow BuiltIn Position "
@@ -1573,15 +1269,6 @@
"is not a float vector"))));
INSTANTIATE_TEST_SUITE_P(
- PositionNotFloatVector,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("Position"), Values("Vertex"), Values("Output"),
- Values("%f32arr4", "%u32vec4"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 4-component 32-bit float vector"))));
-
-INSTANTIATE_TEST_SUITE_P(
PositionNotFloatVec4,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("Position"), Values("Geometry"), Values("Input"),
@@ -1591,15 +1278,6 @@
"has 3 components"))));
INSTANTIATE_TEST_SUITE_P(
- PositionNotFloatVec4,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("Position"), Values("Vertex"), Values("Output"),
- Values("%f32vec3"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 4-component 32-bit float vector"))));
-
-INSTANTIATE_TEST_SUITE_P(
PositionNotF32Vec4,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("Position"), Values("Geometry"), Values("Input"),
@@ -1632,7 +1310,8 @@
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"to be used only with Fragment, TessellationControl, "
- "TessellationEvaluation or Geometry execution models"))));
+ "TessellationEvaluation, Geometry, MeshNV, IntersectionKHR, "
+ "AnyHitKHR, and ClosestHitKHR execution models"))));
INSTANTIATE_TEST_SUITE_P(
PrimitiveIdFragmentNotInput,
@@ -1645,7 +1324,7 @@
"which is called with execution model Fragment"))));
INSTANTIATE_TEST_SUITE_P(
- PrimitiveIdGeometryNotInput,
+ PrimitiveIdTessellationNotInput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("PrimitiveId"),
Values("TessellationControl", "TessellationEvaluation"),
@@ -1917,7 +1596,8 @@
TessLevelOuterOutputTese,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("TessLevelOuter"), Values("TessellationEvaluation"),
- Values("Output"), Values("%f32arr4"), Values(nullptr),
+ Values("Output"), Values("%f32arr4"),
+ Values("VUID-TessLevelOuter-TessLevelOuter-04392"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
@@ -1928,7 +1608,8 @@
TessLevelOuterInputTesc,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("TessLevelOuter"), Values("TessellationControl"),
- Values("Input"), Values("%f32arr4"), Values(nullptr),
+ Values("Input"), Values("%f32arr4"),
+ Values("VUID-TessLevelOuter-TessLevelOuter-04391"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
@@ -2004,7 +1685,8 @@
TessLevelInnerOutputTese,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("TessLevelInner"), Values("TessellationEvaluation"),
- Values("Output"), Values("%f32arr2"), Values(nullptr),
+ Values("Output"), Values("%f32arr2"),
+ Values("VUID-TessLevelInner-TessLevelInner-04396"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
@@ -2015,7 +1697,8 @@
TessLevelInnerInputTesc,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("TessLevelInner"), Values("TessellationControl"),
- Values("Input"), Values("%f32arr2"), Values(nullptr),
+ Values("Input"), Values("%f32arr2"),
+ Values("VUID-TessLevelInner-TessLevelInner-04395"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
@@ -2069,12 +1752,6 @@
Values("%u32"), Values(nullptr), Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
- VertexIndexSuccess,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"),
- Values("%u32"), Values(TestResult())));
-
-INSTANTIATE_TEST_SUITE_P(
VertexIndexInvalidExecutionModel,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("VertexIndex"),
@@ -2086,14 +1763,6 @@
"to be used only with Vertex execution model"))));
INSTANTIATE_TEST_SUITE_P(
- VertexIndexInvalidExecutionModel,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("VertexIndex"), Values("Fragment", "GLCompute"),
- Values("Input"), Values("%u32"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "to be used only with Vertex execution model"))));
-
-INSTANTIATE_TEST_SUITE_P(
VertexIndexNotInput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(
@@ -2104,16 +1773,6 @@
"used for variables with Input storage class"))));
INSTANTIATE_TEST_SUITE_P(
- VertexIndexNotInput,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("VertexIndex"), Values("Vertex"), Values("Output"),
- Values("%u32"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "WebGPU spec allows BuiltIn VertexIndex to be only "
- "used for variables with Input storage class"))));
-
-INSTANTIATE_TEST_SUITE_P(
VertexIndexNotIntScalar,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"),
@@ -2124,15 +1783,6 @@
"is not an int scalar"))));
INSTANTIATE_TEST_SUITE_P(
- VertexIndexNotIntScalar,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"),
- Values("%f32", "%u32vec3"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 32-bit int scalar",
- "is not an int scalar"))));
-
-INSTANTIATE_TEST_SUITE_P(
VertexIndexNotInt32,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"),
@@ -2142,50 +1792,6 @@
"has bit width 64"))));
INSTANTIATE_TEST_SUITE_P(
- LocalInvocationIndexSuccess,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("LocalInvocationIndex"), Values("GLCompute"),
- Values("Input"), Values("%u32"), Values(TestResult())));
-
-INSTANTIATE_TEST_SUITE_P(
- LocalInvocationIndexInvalidExecutionModel,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("LocalInvocationIndex"), Values("Fragment", "Vertex"),
- Values("Input"), Values("%u32"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "to be used only with GLCompute execution model"))));
-
-INSTANTIATE_TEST_SUITE_P(
- LocalInvocationIndexNotInput,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(
- Values("LocalInvocationIndex"), Values("GLCompute"), Values("Output"),
- Values("%u32"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "WebGPU spec allows BuiltIn LocalInvocationIndex to "
- "be only used for variables with Input storage "
- "class"))));
-
-INSTANTIATE_TEST_SUITE_P(
- LocalInvocationIndexNotIntScalar,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("LocalInvocationIndex"), Values("GLCompute"),
- Values("Input"), Values("%f32", "%u32vec3"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 32-bit int", "is not an int"))));
-
-INSTANTIATE_TEST_SUITE_P(
- AllowListRejection,
- ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
- Combine(Values("PointSize", "ClipDistance", "CullDistance", "VertexId",
- "InstanceId", "PointCoord", "SampleMask", "HelperInvocation",
- "WorkgroupId"),
- Values("Vertex"), Values("Input"), Values("%u32"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "WebGPU does not allow BuiltIn"))));
-
-INSTANTIATE_TEST_SUITE_P(
BaseInstanceOrVertexSuccess,
ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
Combine(Values("BaseInstance", "BaseVertex"), Values("Vertex"),
@@ -2362,14 +1968,586 @@
"needs to be a 32-bit int scalar",
"is not an int scalar"))));
-CodeGenerator GetArrayedVariableCodeGenerator(spv_target_env env,
- const char* const built_in,
+// Test HitKind in NV RT shaders
+INSTANTIATE_TEST_SUITE_P(
+ HitKindNVSuccess,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindNV"),
+ Values("AnyHitNV", "ClosestHitNV"), Values("Input"), Values("%u32"),
+ Values("OpCapability RayTracingNV\n"),
+ Values("OpExtension \"SPV_NV_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+// HitKind is valid in AH, CH shaders as input i32 scalar
+INSTANTIATE_TEST_SUITE_P(
+ HitKindSuccess,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR"), Values("Input"),
+ Values("%u32"), Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ HitKindNotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindKHR"),
+ Values("Vertex", "Fragment", "TessellationControl",
+ "TessellationEvaluation", "Geometry", "Fragment",
+ "GLCompute", "RayGenerationKHR", "IntersectionKHR",
+ "MissKHR", "CallableKHR"),
+ Values("Input"), Values("%u32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-HitKindKHR-HitKindKHR-04242"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec does not allow BuiltIn",
+ "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ HitKindNotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR"), Values("Output"),
+ Values("%u32"), Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-HitKindKHR-HitKindKHR-04243"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+ "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ HitKindNotIntScalar,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR"), Values("Input"),
+ Values("%f32", "%u32vec3"), Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-HitKindKHR-HitKindKHR-04244"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 32-bit int scalar",
+ "is not an int scalar"))));
+
+// Ensure HitT is not supported in KHR RT shaders
+INSTANTIATE_TEST_SUITE_P(
+ HitTNVNotSupportedInKHR,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+ Values("AnyHitKHR", "ClosestHitKHR"), Values("Input"),
+ Values("%u32"), Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult(
+ SPV_ERROR_INVALID_CAPABILITY,
+ "of MemberDecorate requires one of these capabilities"))));
+
+// HitT is valid in AH, CH shaders as input f32 scalar (NV RT only)
+INSTANTIATE_TEST_SUITE_P(
+ HitTNVSuccess,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+ Values("AnyHitNV", "ClosestHitNV"), Values("Input"), Values("%f32"),
+ Values("OpCapability RayTracingNV\n"),
+ Values("OpExtension \"SPV_NV_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ HitTNVNotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+ Values("Vertex", "Fragment", "TessellationControl",
+ "TessellationEvaluation", "Geometry", "Fragment",
+ "GLCompute", "RayGenerationNV", "IntersectionNV", "MissNV",
+ "CallableNV"),
+ Values("Input"), Values("%f32"),
+ Values("OpCapability RayTracingNV\n"),
+ Values("OpExtension \"SPV_NV_ray_tracing\"\n"),
+ Values("VUID-HitTNV-HitTNV-04245"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec does not allow BuiltIn",
+ "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ HitTNVNotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+ Values("AnyHitNV", "ClosestHitNV"), Values("Output"),
+ Values("%f32"), Values("OpCapability RayTracingNV\n"),
+ Values("OpExtension \"SPV_NV_ray_tracing\"\n"),
+ Values("VUID-HitTNV-HitTNV-04246"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+ "used for variables with Input storage class"))));
+INSTANTIATE_TEST_SUITE_P(
+ HitTNVNotIntScalar,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+ Values("AnyHitNV", "ClosestHitNV"), Values("Input"),
+ Values("%u32", "%f32vec3"), Values("OpCapability RayTracingNV\n"),
+ Values("OpExtension \"SPV_NV_ray_tracing\"\n"),
+ Values("VUID-HitTNV-HitTNV-04247"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 32-bit float scalar",
+ "is not a float scalar"))));
+
+// InstanceCustomIndexKHR, InstanceId, PrimitiveId, RayGeometryIndexKHR are
+// valid in IS, AH, CH shaders as input i32 scalars
+INSTANTIATE_TEST_SUITE_P(
+ RTBuiltIn3StageI32Success,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("InstanceCustomIndexKHR", "RayGeometryIndexKHR",
+ "InstanceId", "PrimitiveId"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Input"), Values("%u32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ RTBuiltIn3StageI32NotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("InstanceCustomIndexKHR", "RayGeometryIndexKHR",
+ "InstanceId"),
+ Values("Vertex", "Fragment", "TessellationControl",
+ "TessellationEvaluation", "Geometry", "Fragment",
+ "GLCompute", "RayGenerationKHR", "MissKHR", "CallableKHR"),
+ Values("Input"), Values("%u32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04251 "
+ "VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04345 "
+ "VUID-InstanceId-InstanceId-04254 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec does not allow BuiltIn",
+ "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ RTBuiltIn3StageI32NotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("InstanceCustomIndexKHR", "RayGeometryIndexKHR",
+ "InstanceId"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Output"), Values("%u32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04252 "
+ "VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04346 "
+ "VUID-InstanceId-InstanceId-04255 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+ "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ RTBuiltIn3StageI32NotIntScalar,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("InstanceCustomIndexKHR", "RayGeometryIndexKHR",
+ "InstanceId"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Input"), Values("%f32", "%u32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04253 "
+ "VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04347 "
+ "VUID-InstanceId-InstanceId-04256 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 32-bit int scalar",
+ "is not an int scalar"))));
+
+// PrimitiveId needs special negative testing because it has non-RT uses
+INSTANTIATE_TEST_SUITE_P(
+ PrimitiveIdRTNotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("PrimitiveId"),
+ Values("RayGenerationKHR", "MissKHR", "CallableKHR"),
+ Values("Input"), Values("%u32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-PrimitiveId-PrimitiveId-04330"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "to be used only with Fragment, TessellationControl, "
+ "TessellationEvaluation, Geometry, MeshNV, IntersectionKHR, "
+ "AnyHitKHR, and ClosestHitKHR execution models"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ PrimitiveIdRTNotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("PrimitiveId"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Output"), Values("%u32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-PrimitiveId-PrimitiveId-04334"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Output storage class if execution model is "))));
+
+INSTANTIATE_TEST_SUITE_P(
+ PrimitiveIdRTNotIntScalar,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("PrimitiveId"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Input"), Values("%f32", "%u32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-PrimitiveId-PrimitiveId-04337"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 32-bit int scalar",
+ "is not an int scalar"))));
+
+// ObjectRayDirectionKHR and ObjectRayOriginKHR valid
+// in IS, AH, CH shaders as input 32-bit float vec3
+INSTANTIATE_TEST_SUITE_P(
+ ObjectRayDirectionAndOriginSuccess,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("ObjectRayDirectionKHR", "ObjectRayOriginKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Input"), Values("%f32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ ObjectRayDirectionAndOriginNotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("ObjectRayDirectionKHR", "ObjectRayOriginKHR"),
+ Values("Vertex", "Fragment", "TessellationControl",
+ "TessellationEvaluation", "Geometry", "Fragment",
+ "GLCompute", "RayGenerationKHR", "MissKHR", "CallableKHR"),
+ Values("Input"), Values("%f32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04299 "
+ "VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04302 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec does not allow BuiltIn",
+ "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ ObjectRayDirectionAndOriginNotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("ObjectRayDirectionKHR", "ObjectRayOriginKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Output"), Values("%f32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04300 "
+ "VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04303 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+ "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ ObjectRayDirectionAndOriginNotFloatVec3,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(
+ Values(SPV_ENV_VULKAN_1_2),
+ Values("ObjectRayDirectionKHR", "ObjectRayOriginKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Input"), Values("%u32vec3", "%f32", "%f32vec2", "%f32vec4"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04301 "
+ "VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04304 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 3-component 32-bit float vector"))));
+
+// ObjectToWorldKHR and WorldToObjectKHR valid
+// in IS, AH, CH shaders as input mat4x3
+INSTANTIATE_TEST_SUITE_P(
+ RTObjectMatrixSuccess,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("ObjectToWorldKHR", "WorldToObjectKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Input"), Values("%f32mat34"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ RTObjectMatrixNotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("ObjectToWorldKHR", "WorldToObjectKHR"),
+ Values("Vertex", "Fragment", "TessellationControl",
+ "TessellationEvaluation", "Geometry", "Fragment",
+ "GLCompute", "RayGenerationKHR", "MissKHR", "CallableKHR"),
+ Values("Input"), Values("%f32mat34"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-ObjectToWorldKHR-ObjectToWorldKHR-04305 "
+ "VUID-WorldToObjectKHR-WorldToObjectKHR-04434 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec does not allow BuiltIn",
+ "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ RTObjectMatrixNotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("ObjectToWorldKHR", "WorldToObjectKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Output"), Values("%f32mat34"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-ObjectToWorldKHR-ObjectToWorldKHR-04306 "
+ "VUID-WorldToObjectKHR-WorldToObjectKHR-04435 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+ "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ RTObjectMatrixNotMat4x3,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("ObjectToWorldKHR", "WorldToObjectKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+ Values("Input"), Values("%f32mat43", "%f32mat44", "%f32vec4"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-ObjectToWorldKHR-ObjectToWorldKHR-04307 "
+ "VUID-WorldToObjectKHR-WorldToObjectKHR-04436 "),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "variable needs to be a matrix with "
+ "4 columns of 3-component vectors of 32-bit floats"))));
+
+// IncomingRayFlagsKHR is valid
+// in IS, AH, CH, MS shaders as an input i32 scalar
+INSTANTIATE_TEST_SUITE_P(
+ IncomingRayFlagsSuccess,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("IncomingRayFlagsKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+ Values("Input"), Values("%u32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ IncomingRayFlagsNotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("IncomingRayFlagsKHR"),
+ Values("Vertex", "Fragment", "TessellationControl",
+ "TessellationEvaluation", "Geometry", "Fragment",
+ "GLCompute", "RayGenerationKHR", "CallableKHR"),
+ Values("Input"), Values("%u32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248 "
+ "VUID-RayTmaxKHR-RayTmaxKHR-04348 "
+ "VUID-RayTminKHR-RayTminKHR-04351 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec does not allow BuiltIn",
+ "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ IncomingRayFlagsNotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("IncomingRayFlagsKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+ Values("Output"), Values("%u32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249 "
+ "VUID-RayTmaxKHR-RayTmaxKHR-04349 "
+ "VUID-RayTminKHR-RayTminKHR-04352 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+ "used for variables with Input storage class"))));
+INSTANTIATE_TEST_SUITE_P(
+ IncomingRayFlagsNotIntScalar,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("IncomingRayFlagsKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+ Values("Input"), Values("%f32", "%u32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250 "
+ "VUID-RayTmaxKHR-RayTmaxKHR-04350 "
+ "VUID-RayTminKHR-RayTminKHR-04353 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 32-bit int scalar",
+ "is not an int scalar"))));
+
+// RayTmaxKHR, RayTminKHR are all valid
+// in IS, AH, CH, MS shaders as input f32 scalars
+INSTANTIATE_TEST_SUITE_P(
+ RayTSuccess,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("RayTmaxKHR", "RayTminKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+ Values("Input"), Values("%f32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ RayTNotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("RayTmaxKHR", "RayTminKHR"),
+ Values("Vertex", "Fragment", "TessellationControl",
+ "TessellationEvaluation", "Geometry", "Fragment",
+ "GLCompute", "RayGenerationKHR", "CallableKHR"),
+ Values("Input"), Values("%f32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248 "
+ "VUID-RayTmaxKHR-RayTmaxKHR-04348 "
+ "VUID-RayTminKHR-RayTminKHR-04351 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec does not allow BuiltIn",
+ "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ RayTNotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("RayTmaxKHR", "RayTminKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+ Values("Output"), Values("%f32"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249 "
+ "VUID-RayTmaxKHR-RayTmaxKHR-04349 "
+ "VUID-RayTminKHR-RayTminKHR-04352 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+ "used for variables with Input storage class"))));
+INSTANTIATE_TEST_SUITE_P(
+ RayTNotFloatScalar,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("RayTmaxKHR", "RayTminKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+ Values("Input"), Values("%u32", "%f32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250 "
+ "VUID-RayTmaxKHR-RayTmaxKHR-04350 "
+ "VUID-RayTminKHR-RayTminKHR-04353 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 32-bit float scalar",
+ "is not a float scalar"))));
+
+// WorldRayDirectionKHR and WorldRayOriginKHR are valid
+// in IS, AH, CH, MS shaders as input 32-bit float vec3
+INSTANTIATE_TEST_SUITE_P(
+ WorldRayDirectionAndOriginSuccess,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("WorldRayDirectionKHR", "WorldRayOriginKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+ Values("Input"), Values("%f32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ WorldRayDirectionAndOriginNotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("WorldRayDirectionKHR", "WorldRayOriginKHR"),
+ Values("Vertex", "Fragment", "TessellationControl",
+ "TessellationEvaluation", "Geometry", "Fragment",
+ "GLCompute", "RayGenerationKHR", "CallableKHR"),
+ Values("Input"), Values("%f32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04428 "
+ "VUID-WorldRayOriginKHR-WorldRayOriginKHR-04431 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec does not allow BuiltIn",
+ "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ WorldRayDirectionAndOriginNotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2),
+ Values("WorldRayDirectionKHR", "WorldRayOriginKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+ Values("Output"), Values("%f32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04429 "
+ "VUID-WorldRayOriginKHR-WorldRayOriginKHR-04432 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+ "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ WorldRayDirectionAndOriginNotFloatVec3,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(
+ Values(SPV_ENV_VULKAN_1_2),
+ Values("WorldRayDirectionKHR", "WorldRayOriginKHR"),
+ Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+ Values("Input"), Values("%u32vec3", "%f32", "%f32vec2", "%f32vec4"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04430 "
+ "VUID-WorldRayOriginKHR-WorldRayOriginKHR-04433 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 3-component 32-bit float vector"))));
+
+// LaunchIdKHR and LaunchSizeKHR are valid
+// in RG, IS, AH, CH, MS shaders as input 32-bit ivec3
+INSTANTIATE_TEST_SUITE_P(
+ LaunchRTSuccess,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("LaunchIdKHR", "LaunchSizeKHR"),
+ Values("RayGenerationKHR", "AnyHitKHR", "ClosestHitKHR",
+ "IntersectionKHR", "MissKHR", "CallableKHR"),
+ Values("Input"), Values("%u32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ LaunchRTNotExecutionMode,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("LaunchIdKHR", "LaunchSizeKHR"),
+ Values("Vertex", "Fragment", "TessellationControl",
+ "TessellationEvaluation", "Geometry", "Fragment",
+ "GLCompute"),
+ Values("Input"), Values("%u32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-LaunchIdKHR-LaunchIdKHR-04266 "
+ "VUID-LaunchSizeKHR-LaunchSizeKHR-04269 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec does not allow BuiltIn",
+ "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ LaunchRTNotInput,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("LaunchIdKHR", "LaunchSizeKHR"),
+ Values("RayGenerationKHR", "AnyHitKHR", "ClosestHitKHR",
+ "IntersectionKHR", "MissKHR", "CallableKHR"),
+ Values("Output"), Values("%u32vec3"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-LaunchIdKHR-LaunchIdKHR-04267 "
+ "VUID-LaunchSizeKHR-LaunchSizeKHR-04270 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+ "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+ LaunchRTNotIntVec3,
+ ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values(SPV_ENV_VULKAN_1_2), Values("LaunchIdKHR", "LaunchSizeKHR"),
+ Values("RayGenerationKHR", "AnyHitKHR", "ClosestHitKHR",
+ "IntersectionKHR", "MissKHR", "CallableKHR"),
+ Values("Input"), Values("%f32vec3", "%u32", "%u32vec2", "%u32vec4"),
+ Values("OpCapability RayTracingKHR\n"),
+ Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+ Values("VUID-LaunchIdKHR-LaunchIdKHR-04268 "
+ "VUID-LaunchSizeKHR-LaunchSizeKHR-04271 "),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 3-component 32-bit int vector"))));
+
+CodeGenerator GetArrayedVariableCodeGenerator(const char* const built_in,
const char* const execution_model,
const char* const storage_class,
const char* const data_type) {
- CodeGenerator generator =
- spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = "OpDecorate %built_in_var BuiltIn ";
generator.before_types_ += built_in;
@@ -2377,14 +2555,14 @@
std::ostringstream after_types;
after_types << "%built_in_array = OpTypeArray " << data_type << " %u32_3\n";
- if (InitializerRequired(env, storage_class)) {
+ if (InitializerRequired(storage_class)) {
after_types << "%built_in_array_null = OpConstantNull %built_in_array\n";
}
after_types << "%built_in_ptr = OpTypePointer " << storage_class
<< " %built_in_array\n";
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
- if (InitializerRequired(env, storage_class)) {
+ if (InitializerRequired(storage_class)) {
after_types << " %built_in_array_null";
}
after_types << "\n";
@@ -2433,7 +2611,7 @@
const TestResult& test_result = std::get<4>(GetParam());
CodeGenerator generator = GetArrayedVariableCodeGenerator(
- SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type);
+ built_in, execution_model, storage_class, data_type);
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(test_result.validation_result,
@@ -2446,27 +2624,6 @@
}
}
-TEST_P(ValidateWebGPUCombineBuiltInArrayedVariable, Variable) {
- const char* const built_in = std::get<0>(GetParam());
- const char* const execution_model = std::get<1>(GetParam());
- const char* const storage_class = std::get<2>(GetParam());
- const char* const data_type = std::get<3>(GetParam());
- const TestResult& test_result = std::get<4>(GetParam());
-
- CodeGenerator generator = GetArrayedVariableCodeGenerator(
- SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(test_result.validation_result,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- if (test_result.error_str) {
- EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
- }
- if (test_result.error_str2) {
- EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
- }
-}
-
INSTANTIATE_TEST_SUITE_P(PointSizeArrayedF32TessControl,
ValidateVulkanCombineBuiltInArrayedVariable,
Combine(Values("PointSize"),
@@ -2513,14 +2670,6 @@
"is not a float vector"))));
INSTANTIATE_TEST_SUITE_P(
- PositionArrayedF32Vec4Vertex, ValidateWebGPUCombineBuiltInArrayedVariable,
- Combine(Values("Position"), Values("Vertex"), Values("Output"),
- Values("%f32vec4"),
- Values(TestResult(SPV_ERROR_INVALID_DATA,
- "needs to be a 4-component 32-bit float vector",
- "is not a float vector"))));
-
-INSTANTIATE_TEST_SUITE_P(
ClipAndCullDistanceOutputSuccess,
ValidateVulkanCombineBuiltInArrayedVariable,
Combine(Values("ClipDistance", "CullDistance"),
@@ -2623,10 +2772,8 @@
"needs to be a 32-bit int scalar",
"has bit width 64"))));
-CodeGenerator GetWorkgroupSizeSuccessGenerator(spv_target_env env) {
- CodeGenerator generator =
- env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+CodeGenerator GetWorkgroupSizeSuccessGenerator() {
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
OpDecorate %workgroup_size BuiltIn WorkgroupSize
@@ -2648,22 +2795,13 @@
}
TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeSuccess) {
- CodeGenerator generator =
- GetWorkgroupSizeSuccessGenerator(SPV_ENV_VULKAN_1_0);
+ CodeGenerator generator = GetWorkgroupSizeSuccessGenerator();
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
-TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeSuccess) {
- CodeGenerator generator = GetWorkgroupSizeSuccessGenerator(SPV_ENV_WEBGPU_0);
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-CodeGenerator GetWorkgroupSizeFragmentGenerator(spv_target_env env) {
- CodeGenerator generator =
- env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+CodeGenerator GetWorkgroupSizeFragmentGenerator() {
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
OpDecorate %workgroup_size BuiltIn WorkgroupSize
@@ -2686,8 +2824,7 @@
}
TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeFragment) {
- CodeGenerator generator =
- GetWorkgroupSizeFragmentGenerator(SPV_ENV_VULKAN_1_0);
+ CodeGenerator generator = GetWorkgroupSizeFragmentGenerator();
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
@@ -2703,20 +2840,6 @@
"VUID-WorkgroupSize-WorkgroupSize-04427"));
}
-TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeFragment) {
- CodeGenerator generator = GetWorkgroupSizeFragmentGenerator(SPV_ENV_WEBGPU_0);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("WebGPU spec allows BuiltIn WorkgroupSize to be used "
- "only with GLCompute execution model"));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("is referencing ID <2> (OpConstantComposite) which is "
- "decorated with BuiltIn WorkgroupSize in function <1> "
- "called with execution model Fragment"));
-}
-
TEST_F(ValidateBuiltIns, WorkgroupSizeNotConstant) {
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
@@ -2742,10 +2865,8 @@
HasSubstr("BuiltIns can only target variables, structs or constants"));
}
-CodeGenerator GetWorkgroupSizeNotVectorGenerator(spv_target_env env) {
- CodeGenerator generator =
- env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+CodeGenerator GetWorkgroupSizeNotVectorGenerator() {
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
OpDecorate %workgroup_size BuiltIn WorkgroupSize
@@ -2767,8 +2888,7 @@
}
TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVector) {
- CodeGenerator generator =
- GetWorkgroupSizeNotVectorGenerator(SPV_ENV_VULKAN_1_0);
+ CodeGenerator generator = GetWorkgroupSizeNotVectorGenerator();
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
@@ -2780,22 +2900,8 @@
AnyVUID("VUID-WorkgroupSize-WorkgroupSize-04427"));
}
-TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeNotVector) {
- CodeGenerator generator =
- GetWorkgroupSizeNotVectorGenerator(SPV_ENV_WEBGPU_0);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("According to the WebGPU spec BuiltIn WorkgroupSize "
- "variable needs to be a 3-component 32-bit int vector. "
- "ID <2> (OpConstant) is not an int vector."));
-}
-
-CodeGenerator GetWorkgroupSizeNotIntVectorGenerator(spv_target_env env) {
- CodeGenerator generator =
- env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+CodeGenerator GetWorkgroupSizeNotIntVectorGenerator() {
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
OpDecorate %workgroup_size BuiltIn WorkgroupSize
@@ -2817,8 +2923,7 @@
}
TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotIntVector) {
- CodeGenerator generator =
- GetWorkgroupSizeNotIntVectorGenerator(SPV_ENV_VULKAN_1_0);
+ CodeGenerator generator = GetWorkgroupSizeNotIntVectorGenerator();
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
@@ -2830,22 +2935,8 @@
AnyVUID("VUID-WorkgroupSize-WorkgroupSize-04427"));
}
-TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeNotIntVector) {
- CodeGenerator generator =
- GetWorkgroupSizeNotIntVectorGenerator(SPV_ENV_WEBGPU_0);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("According to the WebGPU spec BuiltIn WorkgroupSize "
- "variable needs to be a 3-component 32-bit int vector. "
- "ID <2> (OpConstantComposite) is not an int vector."));
-}
-
-CodeGenerator GetWorkgroupSizeNotVec3Generator(spv_target_env env) {
- CodeGenerator generator =
- env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+CodeGenerator GetWorkgroupSizeNotVec3Generator() {
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
OpDecorate %workgroup_size BuiltIn WorkgroupSize
@@ -2867,8 +2958,7 @@
}
TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVec3) {
- CodeGenerator generator =
- GetWorkgroupSizeNotVec3Generator(SPV_ENV_VULKAN_1_0);
+ CodeGenerator generator = GetWorkgroupSizeNotVec3Generator();
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
@@ -2880,17 +2970,6 @@
AnyVUID("VUID-WorkgroupSize-WorkgroupSize-04427"));
}
-TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeNotVec3) {
- CodeGenerator generator = GetWorkgroupSizeNotVec3Generator(SPV_ENV_WEBGPU_0);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("According to the WebGPU spec BuiltIn WorkgroupSize "
- "variable needs to be a 3-component 32-bit int vector. "
- "ID <2> (OpConstantComposite) has 2 components."));
-}
-
TEST_F(ValidateBuiltIns, WorkgroupSizeNotInt32Vec) {
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
@@ -3168,10 +3247,8 @@
HasSubstr("called with execution model Fragment"));
}
-CodeGenerator GetNoDepthReplacingGenerator(spv_target_env env) {
- CodeGenerator generator =
- spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+CodeGenerator GetNoDepthReplacingGenerator() {
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
OpMemberDecorate %output_type 0 BuiltIn FragDepth
@@ -3204,17 +3281,13 @@
OpFunctionEnd
)";
- if (spvIsWebGPUEnv(env)) {
- generator.after_types_ += function_body;
- } else {
generator.add_at_the_end_ = function_body;
- }
return generator;
}
TEST_F(ValidateBuiltIns, VulkanFragmentFragDepthNoDepthReplacing) {
- CodeGenerator generator = GetNoDepthReplacingGenerator(SPV_ENV_VULKAN_1_0);
+ CodeGenerator generator = GetNoDepthReplacingGenerator();
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
@@ -3225,21 +3298,8 @@
HasSubstr("VUID-FragDepth-FragDepth-04216"));
}
-TEST_F(ValidateBuiltIns, WebGPUFragmentFragDepthNoDepthReplacing) {
- CodeGenerator generator = GetNoDepthReplacingGenerator(SPV_ENV_WEBGPU_0);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("WebGPU spec requires DepthReplacing execution mode to "
- "be declared when using BuiltIn FragDepth"));
-}
-
-CodeGenerator GetOneMainHasDepthReplacingOtherHasntGenerator(
- spv_target_env env) {
- CodeGenerator generator =
- spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator()
- : CodeGenerator::GetDefaultShaderCodeGenerator();
+CodeGenerator GetOneMainHasDepthReplacingOtherHasntGenerator() {
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
OpMemberDecorate %output_type 0 BuiltIn FragDepth
@@ -3283,19 +3343,14 @@
OpFunctionEnd
)";
- if (spvIsWebGPUEnv(env)) {
- generator.after_types_ += function_body;
- } else {
generator.add_at_the_end_ = function_body;
- }
return generator;
}
TEST_F(ValidateBuiltIns,
VulkanFragmentFragDepthOneMainHasDepthReplacingOtherHasnt) {
- CodeGenerator generator =
- GetOneMainHasDepthReplacingOtherHasntGenerator(SPV_ENV_VULKAN_1_0);
+ CodeGenerator generator = GetOneMainHasDepthReplacingOtherHasntGenerator();
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
@@ -3306,17 +3361,6 @@
HasSubstr("VUID-FragDepth-FragDepth-04216"));
}
-TEST_F(ValidateBuiltIns,
- WebGPUFragmentFragDepthOneMainHasDepthReplacingOtherHasnt) {
- CodeGenerator generator =
- GetOneMainHasDepthReplacingOtherHasntGenerator(SPV_ENV_WEBGPU_0);
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("WebGPU spec requires DepthReplacing execution mode to "
- "be declared when using BuiltIn FragDepth"));
-}
TEST_F(ValidateBuiltIns, AllowInstanceIdWithIntersectionShader) {
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
@@ -3358,44 +3402,6 @@
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
-TEST_F(ValidateBuiltIns, DisallowInstanceIdWithRayGenShader) {
- CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
- generator.capabilities_ += R"(
-OpCapability RayTracingNV
-)";
-
- generator.extensions_ = R"(
-OpExtension "SPV_NV_ray_tracing"
-)";
-
- generator.before_types_ = R"(
-OpMemberDecorate %input_type 0 BuiltIn InstanceId
-)";
-
- generator.after_types_ = R"(
-%input_type = OpTypeStruct %u32
-%input_ptr = OpTypePointer Input %input_type
-%input_ptr_u32 = OpTypePointer Input %u32
-%input = OpVariable %input_ptr Input
-)";
-
- EntryPoint entry_point;
- entry_point.name = "main_d_r";
- entry_point.execution_model = "RayGenerationNV";
- entry_point.interfaces = "%input";
- entry_point.body = R"(
-%input_member = OpAccessChain %input_ptr_u32 %input %u32_0
-)";
- generator.entry_points_.push_back(std::move(entry_point));
-
- CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Vulkan spec allows BuiltIn InstanceId to be used "
- "only with IntersectionNV, ClosestHitNV and "
- "AnyHitNV execution models"));
-}
-
TEST_F(ValidateBuiltIns, ValidBuiltinsForMeshShader) {
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.capabilities_ += R"(
@@ -3509,7 +3515,8 @@
const char* const execution_model = std::get<1>(GetParam());
const char* const storage_class = std::get<2>(GetParam());
const char* const data_type = std::get<3>(GetParam());
- const TestResult& test_result = std::get<4>(GetParam());
+ const char* const vuid = std::get<4>(GetParam());
+ const TestResult& test_result = std::get<5>(GetParam());
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.capabilities_ += R"(
@@ -3569,6 +3576,9 @@
if (test_result.error_str2) {
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
}
+ if (vuid) {
+ EXPECT_THAT(getDiagnosticString(), AnyVUID(vuid));
+ }
}
INSTANTIATE_TEST_SUITE_P(
@@ -3576,6 +3586,11 @@
Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask",
"SubgroupLeMask", "SubgroupLtMask"),
Values("GLCompute"), Values("Input"), Values("%u32vec3"),
+ Values("VUID-SubgroupEqMask-SubgroupEqMask-04371 "
+ "VUID-SubgroupGeMask-SubgroupGeMask-04373 "
+ "VUID-SubgroupGtMask-SubgroupGtMask-04375 "
+ "VUID-SubgroupLeMask-SubgroupLeMask-04377 "
+ "VUID-SubgroupLtMask-SubgroupLtMask-04379"),
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 4-component 32-bit int vector"))));
@@ -3584,6 +3599,11 @@
Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask",
"SubgroupLeMask", "SubgroupLtMask"),
Values("GLCompute"), Values("Input"), Values("%f32vec4"),
+ Values("VUID-SubgroupEqMask-SubgroupEqMask-04371 "
+ "VUID-SubgroupGeMask-SubgroupGeMask-04373 "
+ "VUID-SubgroupGtMask-SubgroupGtMask-04375 "
+ "VUID-SubgroupLeMask-SubgroupLeMask-04377 "
+ "VUID-SubgroupLtMask-SubgroupLtMask-04379"),
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 4-component 32-bit int vector"))));
@@ -3593,6 +3613,11 @@
"SubgroupLeMask", "SubgroupLtMask"),
Values("GLCompute"), Values("Output", "Workgroup", "Private"),
Values("%u32vec4"),
+ Values("VUID-SubgroupEqMask-SubgroupEqMask-04370 "
+ "VUID-SubgroupGeMask-SubgroupGeMask-04372 "
+ "VUID-SubgroupGtMask-SubgroupGtMask-04374 "
+ "VUID-SubgroupLeMask-SubgroupLeMask-04376 "
+ "VUID-SubgroupLtMask-SubgroupLtMask-04378"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"to be only used for variables with Input storage class"))));
@@ -3602,7 +3627,7 @@
"SubgroupGtMask", "SubgroupLeMask",
"SubgroupLtMask"),
Values("GLCompute"), Values("Input"),
- Values("%u32vec4"),
+ Values("%u32vec4"), Values(nullptr),
Values(TestResult(SPV_SUCCESS, ""))));
TEST_F(ValidateBuiltIns, SubgroupMaskMemberDecorate) {
@@ -3635,6 +3660,8 @@
SubgroupInvocationIdAndSizeNotU32, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"),
Values("GLCompute"), Values("Input"), Values("%f32"),
+ Values("VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-"
+ "04381 VUID-SubgroupSize-SubgroupSize-04383"),
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 32-bit int"))));
@@ -3643,6 +3670,8 @@
Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"),
Values("GLCompute"), Values("Output", "Workgroup", "Private"),
Values("%u32"),
+ Values("VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-"
+ "04380 VUID-SubgroupSize-SubgroupSize-04382"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"to be only used for variables with Input storage class"))));
@@ -3651,7 +3680,7 @@
SubgroupInvocationIdAndSizeOk, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"),
Values("GLCompute"), Values("Input"), Values("%u32"),
- Values(TestResult(SPV_SUCCESS, ""))));
+ Values(nullptr), Values(TestResult(SPV_SUCCESS, ""))));
TEST_F(ValidateBuiltIns, SubgroupSizeMemberDecorate) {
const std::string text = R"(
@@ -3679,9 +3708,21 @@
}
INSTANTIATE_TEST_SUITE_P(
+ SubgroupNumAndIdNotCompute, ValidateVulkanSubgroupBuiltIns,
+ Combine(
+ Values("SubgroupId", "NumSubgroups"), Values("Vertex"), Values("Input"),
+ Values("%u32"),
+ Values("VUID-SubgroupId-SubgroupId-04367 "
+ "VUID-NumSubgroups-NumSubgroups-04293"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "to be used only with GLCompute execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
SubgroupNumAndIdNotU32, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"),
Values("Input"), Values("%f32"),
+ Values("VUID-SubgroupId-SubgroupId-04369 "
+ "VUID-NumSubgroups-NumSubgroups-04295"),
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 32-bit int"))));
@@ -3689,6 +3730,8 @@
SubgroupNumAndIdNotInput, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"),
Values("Output", "Workgroup", "Private"), Values("%u32"),
+ Values("VUID-SubgroupId-SubgroupId-04368 "
+ "VUID-NumSubgroups-NumSubgroups-04294"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"to be only used for variables with Input storage class"))));
@@ -3696,7 +3739,7 @@
INSTANTIATE_TEST_SUITE_P(SubgroupNumAndIdOk, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupId", "NumSubgroups"),
Values("GLCompute"), Values("Input"),
- Values("%u32"),
+ Values("%u32"), Values(nullptr),
Values(TestResult(SPV_SUCCESS, ""))));
TEST_F(ValidateBuiltIns, SubgroupIdMemberDecorate) {
@@ -3898,6 +3941,184 @@
Values(TestResult(SPV_ERROR_INVALID_DATA,
"According to the Vulkan spec BuiltIn ShadingRateKHR "
"variable needs to be a 32-bit int scalar."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragInvocationCountInputSuccess,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragInvocationCountEXT"), Values("Fragment"),
+ Values("Input"), Values("%u32"),
+ Values("OpCapability FragmentDensityEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"),
+ Values(nullptr), Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragInvocationCountInvalidExecutionModel,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(
+ Values("FragInvocationCountEXT"), Values("Vertex"), Values("Input"),
+ Values("%u32"), Values("OpCapability FragmentDensityEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"),
+ Values("VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec allows BuiltIn FragInvocationCountEXT "
+ "to be used only with Fragment execution model."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragInvocationCountInvalidStorageClass,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragInvocationCountEXT"), Values("Fragment"),
+ Values("Output"), Values("%u32"),
+ Values("OpCapability FragmentDensityEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"),
+ Values("VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "Vulkan spec allows BuiltIn FragInvocationCountEXT to be only "
+ "used for variables with Input storage class."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragInvocationCountInvalidType,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragInvocationCountEXT"), Values("Fragment"),
+ Values("Input"), Values("%f32"),
+ Values("OpCapability FragmentDensityEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"),
+ Values("VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "According to the Vulkan spec BuiltIn FragInvocationCountEXT "
+ "variable needs to be a 32-bit int scalar."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragSizeInputSuccess,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragSizeEXT"), Values("Fragment"), Values("Input"),
+ Values("%u32vec2"), Values("OpCapability FragmentDensityEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"),
+ Values(nullptr), Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragSizeInvalidExecutionModel,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragSizeEXT"), Values("Vertex"), Values("Input"),
+ Values("%u32vec2"), Values("OpCapability FragmentDensityEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"),
+ Values("VUID-FragSizeEXT-FragSizeEXT-04220"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec allows BuiltIn FragSizeEXT to be "
+ "used only with Fragment execution model."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragSizeInvalidStorageClass,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(
+ Values("FragSizeEXT"), Values("Fragment"), Values("Output"),
+ Values("%u32vec2"), Values("OpCapability FragmentDensityEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"),
+ Values("VUID-FragSizeEXT-FragSizeEXT-04221"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec allows BuiltIn FragSizeEXT to be only "
+ "used for variables with Input storage class."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragSizeInvalidType,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragSizeEXT"), Values("Fragment"), Values("Input"),
+ Values("%u32vec3"), Values("OpCapability FragmentDensityEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"),
+ Values("VUID-FragSizeEXT-FragSizeEXT-04222"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "According to the Vulkan spec BuiltIn FragSizeEXT variable "
+ "needs to be a 2-component 32-bit int vector."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragStencilRefOutputSuccess,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragStencilRefEXT"), Values("Fragment"), Values("Output"),
+ Values("%u32", "%u64"), Values("OpCapability StencilExportEXT\n"),
+ Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"),
+ Values(nullptr), Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragStencilRefInvalidExecutionModel,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragStencilRefEXT"), Values("Vertex"), Values("Output"),
+ Values("%u32", "%u64"), Values("OpCapability StencilExportEXT\n"),
+ Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"),
+ Values("VUID-FragStencilRefEXT-FragStencilRefEXT-04223"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec allows BuiltIn FragStencilRefEXT to "
+ "be used only with Fragment execution model."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragStencilRefInvalidStorageClass,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragStencilRefEXT"), Values("Fragment"), Values("Input"),
+ Values("%u32", "%u64"), Values("OpCapability StencilExportEXT\n"),
+ Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"),
+ Values("VUID-FragStencilRefEXT-FragStencilRefEXT-04224"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "Vulkan spec allows BuiltIn FragStencilRefEXT to be only used "
+ "for variables with Output storage class."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FragStencilRefInvalidType,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FragStencilRefEXT"), Values("Fragment"), Values("Output"),
+ Values("%f32", "%f64", "%u32vec2"),
+ Values("OpCapability StencilExportEXT\n"),
+ Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"),
+ Values("VUID-FragStencilRefEXT-FragStencilRefEXT-04225"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "According to the Vulkan spec BuiltIn FragStencilRefEXT "
+ "variable needs to be a int scalar."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FullyCoveredEXTInputSuccess,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FullyCoveredEXT"), Values("Fragment"), Values("Input"),
+ Values("%bool"), Values("OpCapability FragmentFullyCoveredEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"),
+ Values(nullptr), Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+ FullyCoveredEXTInvalidExecutionModel,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FullyCoveredEXT"), Values("Vertex"), Values("Input"),
+ Values("%bool"), Values("OpCapability FragmentFullyCoveredEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"),
+ Values("VUID-FullyCoveredEXT-FullyCoveredEXT-04232"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "Vulkan spec allows BuiltIn FullyCoveredEXT to "
+ "be used only with Fragment execution model."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FullyCoveredEXTInvalidStorageClass,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FullyCoveredEXT"), Values("Fragment"), Values("Output"),
+ Values("%bool"), Values("OpCapability FragmentFullyCoveredEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"),
+ Values("VUID-FullyCoveredEXT-FullyCoveredEXT-04233"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "Vulkan spec allows BuiltIn FullyCoveredEXT to be only used "
+ "for variables with Input storage class."))));
+
+INSTANTIATE_TEST_SUITE_P(
+ FullyCoveredEXTInvalidType,
+ ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+ Combine(Values("FullyCoveredEXT"), Values("Fragment"), Values("Input"),
+ Values("%f32"), Values("OpCapability FragmentFullyCoveredEXT\n"),
+ Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"),
+ Values("VUID-FullyCoveredEXT-FullyCoveredEXT-04234"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "According to the Vulkan spec BuiltIn FullyCoveredEXT variable "
+ "needs to be a bool scalar."))));
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_capability_test.cpp b/test/val/val_capability_test.cpp
index 9705cb8..82f8d38 100644
--- a/test/val/val_capability_test.cpp
+++ b/test/val/val_capability_test.cpp
@@ -116,8 +116,6 @@
using ValidateCapabilityVulkan11 = spvtest::ValidateBase<CapTestParameter>;
// Always assembles using Vulkan 1.2.
using ValidateCapabilityVulkan12 = spvtest::ValidateBase<CapTestParameter>;
-// Always assembles using WebGPU.
-using ValidateCapabilityWebGPU = spvtest::ValidateBase<CapTestParameter>;
TEST_F(ValidateCapability, Default) {
const char str[] = R"(
@@ -588,18 +586,6 @@
return *r;
}
-const std::vector<std::string>& AllWebGPUCapabilities() {
- static const auto r = new std::vector<std::string>{
- "",
- "Shader",
- "Matrix",
- "Sampled1D",
- "Image1D",
- "ImageQuery",
- "DerivativeControl"};
- return *r;
-}
-
const std::vector<std::string>& MatrixDependencies() {
static const auto r = new std::vector<std::string>{
"Matrix",
@@ -790,12 +776,6 @@
" OpCapability Shader"
" OpMemoryModel Logical GLSL450 ";
-const char kVulkanMemoryModel[] = \
- " OpCapability Shader"
- " OpCapability VulkanMemoryModelKHR"
- " OpExtension \"SPV_KHR_vulkan_memory_model\""
- " OpMemoryModel Logical VulkanKHR ";
-
const char kVoidFVoid[] = \
" %void = OpTypeVoid"
" %void_f = OpTypeFunction %void"
@@ -1814,16 +1794,6 @@
AllSpirV10Capabilities())
)));
-INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityWebGPU,
- Combine(
- // All capabilities to try.
- ValuesIn(AllCapabilities()),
- Values(
-std::make_pair(std::string(kVulkanMemoryModel) +
- "OpEntryPoint Vertex %func \"shader\" \n" + std::string(kVoidFVoid),
- AllWebGPUCapabilities())
-)));
-
INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan11,
Combine(
// All capabilities to try.
@@ -2047,17 +2017,6 @@
}
}
-TEST_P(ValidateCapabilityWebGPU, Capability) {
- const std::string capability = Capability(GetParam());
- if (Exists(capability, SPV_ENV_WEBGPU_0)) {
- const std::string test_code = MakeAssembly(GetParam());
- CompileSuccessfully(test_code, SPV_ENV_WEBGPU_0);
- ASSERT_EQ(ExpectedResult(GetParam()),
- ValidateInstructions(SPV_ENV_WEBGPU_0))
- << test_code;
- }
-}
-
TEST_F(ValidateCapability, SemanticsIdIsAnIdNotALiteral) {
// From https://github.com/KhronosGroup/SPIRV-Tools/issues/248
// The validator was interpreting the memory semantics ID number
diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp
index b4d1c28..9698fb1 100644
--- a/test/val/val_cfg_test.cpp
+++ b/test/val/val_cfg_test.cpp
@@ -168,15 +168,6 @@
return (cap == SpvCapabilityShader) ? shader_header : kernel_header;
}
-const std::string& GetWebGPUHeader() {
- static const std::string header =
- "OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
- "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n";
- return header;
-}
-
const std::string& types_consts() {
static const std::string types =
"%voidt = OpTypeVoid\n"
@@ -496,10 +487,10 @@
TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) {
Block entry("entry");
- entry.SetBody("%undef = OpUndef %voidt\n");
+ entry.SetBody("%undef = OpUndef %boolt\n");
Block bad("bad");
Block end("end", SpvOpReturn);
- Block badvalue("undef"); // This referenes the OpUndef.
+ Block badvalue("undef"); // This references the OpUndef.
std::string str = GetDefaultHeader(GetParam()) +
nameOps("entry", "bad", std::make_pair("func", "Main")) +
types_consts() +
@@ -714,10 +705,8 @@
}
}
-std::string GetUnreachableMergeNoMergeInst(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableMergeNoMergeInst(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block branch("branch", SpvOpBranchConditional);
Block t("t", SpvOpReturn);
@@ -725,17 +714,11 @@
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
- if (!spvIsWebGPUEnv(env) && cap == SpvCapabilityShader)
+ if (cap == SpvCapabilityShader)
branch.AppendBody("OpSelectionMerge %merge None\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", std::make_pair("func", "Main"));
str += types_consts() + "%func = OpFunction %voidt None %funct\n";
str += entry >> branch;
str += branch >> std::vector<Block>({t, f});
@@ -748,23 +731,12 @@
}
TEST_P(ValidateCFG, UnreachableMergeNoMergeInst) {
- CompileSuccessfully(
- GetUnreachableMergeNoMergeInst(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableMergeNoMergeInst(GetParam()));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableMergeNoMergeInst) {
- CompileSuccessfully(
- GetUnreachableMergeNoMergeInst(SpvCapabilityShader, SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, all blocks must be reachable"));
-}
-
-std::string GetUnreachableMergeTerminatedBy(SpvCapability cap,
- spv_target_env env, SpvOp op) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableMergeTerminatedBy(SpvCapability cap, SpvOp op) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block branch("branch", SpvOpBranchConditional);
@@ -774,16 +746,10 @@
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader)
branch.AppendBody("OpSelectionMerge %merge None\n");
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
str += entry >> branch;
@@ -797,49 +763,24 @@
}
TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpUnreachable) {
- CompileSuccessfully(GetUnreachableMergeTerminatedBy(
- GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpUnreachable));
+ CompileSuccessfully(
+ GetUnreachableMergeTerminatedBy(GetParam(), SpvOpUnreachable));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateCFG, UnreachableMergeTerminatedByOpKill) {
- CompileSuccessfully(GetUnreachableMergeTerminatedBy(
- SpvCapabilityShader, SPV_ENV_UNIVERSAL_1_0, SpvOpKill));
+ CompileSuccessfully(
+ GetUnreachableMergeTerminatedBy(SpvCapabilityShader, SpvOpKill));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpReturn) {
- CompileSuccessfully(GetUnreachableMergeTerminatedBy(
- GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpReturn));
+ CompileSuccessfully(GetUnreachableMergeTerminatedBy(GetParam(), SpvOpReturn));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableMergeTerminatedByOpUnreachable) {
- CompileSuccessfully(GetUnreachableMergeTerminatedBy(
- SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpUnreachable));
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateCFG, WebGPUUnreachableMergeTerminatedByOpKill) {
- CompileSuccessfully(GetUnreachableMergeTerminatedBy(
- SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpKill));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("must terminate with OpUnreachable"));
-}
-
-TEST_P(ValidateCFG, WebGPUUnreachableMergeTerminatedByOpReturn) {
- CompileSuccessfully(GetUnreachableMergeTerminatedBy(
- SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpReturn));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("must terminate with OpUnreachable"));
-}
-
-std::string GetUnreachableContinueTerminatedBy(SpvCapability cap,
- spv_target_env env, SpvOp op) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableContinueTerminatedBy(SpvCapability cap, SpvOp op) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block branch("branch", SpvOpBranch);
@@ -849,16 +790,10 @@
if (op == SpvOpBranch) target >> branch;
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader)
branch.AppendBody("OpLoopMerge %merge %target None\n");
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
str += entry >> branch;
@@ -871,8 +806,8 @@
}
TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpUnreachable) {
- CompileSuccessfully(GetUnreachableContinueTerminatedBy(
- GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpUnreachable));
+ CompileSuccessfully(
+ GetUnreachableContinueTerminatedBy(GetParam(), SpvOpUnreachable));
if (GetParam() == SpvCapabilityShader) {
ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
@@ -883,16 +818,16 @@
}
TEST_F(ValidateCFG, UnreachableContinueTerminatedBySpvOpKill) {
- CompileSuccessfully(GetUnreachableContinueTerminatedBy(
- SpvCapabilityShader, SPV_ENV_UNIVERSAL_1_0, SpvOpKill));
+ CompileSuccessfully(
+ GetUnreachableContinueTerminatedBy(SpvCapabilityShader, SpvOpKill));
ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("targeted by 0 back-edge blocks"));
}
TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpReturn) {
- CompileSuccessfully(GetUnreachableContinueTerminatedBy(
- GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpReturn));
+ CompileSuccessfully(
+ GetUnreachableContinueTerminatedBy(GetParam(), SpvOpReturn));
if (GetParam() == SpvCapabilityShader) {
ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
@@ -903,48 +838,13 @@
}
TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpBranch) {
- CompileSuccessfully(GetUnreachableContinueTerminatedBy(
- GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpBranch));
+ CompileSuccessfully(
+ GetUnreachableContinueTerminatedBy(GetParam(), SpvOpBranch));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpUnreachable) {
- CompileSuccessfully(GetUnreachableContinueTerminatedBy(
- SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpUnreachable));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, unreachable continue-target must "
- "terminate with OpBranch.\n %12 = OpLabel\n"));
-}
-
-TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpKill) {
- CompileSuccessfully(GetUnreachableContinueTerminatedBy(
- SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpKill));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, unreachable continue-target must "
- "terminate with OpBranch.\n %12 = OpLabel\n"));
-}
-
-TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpReturn) {
- CompileSuccessfully(GetUnreachableContinueTerminatedBy(
- SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpReturn));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, unreachable continue-target must "
- "terminate with OpBranch.\n %12 = OpLabel\n"));
-}
-
-TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpBranch) {
- CompileSuccessfully(GetUnreachableContinueTerminatedBy(
- SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpBranch));
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block body("body", SpvOpReturn);
Block entry("entry");
@@ -955,16 +855,10 @@
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader)
branch.AppendBody("OpSelectionMerge %merge None\n");
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
str += body;
@@ -979,23 +873,12 @@
}
TEST_P(ValidateCFG, UnreachableMergeUnreachableMergeInst) {
- CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst(
- GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst(GetParam()));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableMergeUnreachableMergeInst) {
- CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst(
- SpvCapabilityShader, SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("must be referenced by a reachable merge instruction"));
-}
-
-std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block body("body", SpvOpReturn);
Block entry("entry");
@@ -1006,16 +889,10 @@
target >> branch;
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader)
branch.AppendBody("OpLoopMerge %merge %target None\n");
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
str += body;
@@ -1029,8 +906,7 @@
}
TEST_P(ValidateCFG, UnreachableContinueUnreachableLoopInst) {
- CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst(
- GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst(GetParam()));
if (GetParam() == SpvCapabilityShader) {
// Shader causes additional structured CFG checks that cause a failure.
ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
@@ -1043,18 +919,8 @@
}
}
-TEST_F(ValidateCFG, WebGPUUnreachableContinueUnreachableLoopInst) {
- CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst(
- SpvCapabilityShader, SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("must be referenced by a reachable loop instruction"));
-}
-
-std::string GetUnreachableMergeWithComplexBody(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableMergeWithComplexBody(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block branch("branch", SpvOpBranchConditional);
@@ -1062,23 +928,15 @@
Block f("f", SpvOpReturn);
Block merge("merge", SpvOpUnreachable);
- entry.AppendBody(spvIsWebGPUEnv(env)
- ? "%placeholder = OpVariable %intptrt Function %two\n"
- : "%placeholder = OpVariable %intptrt Function\n");
+ entry.AppendBody("%placeholder = OpVariable %intptrt Function\n");
entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n");
merge.AppendBody("OpStore %placeholder %one\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader)
branch.AppendBody("OpSelectionMerge %merge None\n");
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", std::make_pair("func", "Main"));
str += types_consts();
str += "%intptrt = OpTypePointer Function %intt\n";
str += "%func = OpFunction %voidt None %funct\n";
@@ -1093,24 +951,12 @@
}
TEST_P(ValidateCFG, UnreachableMergeWithComplexBody) {
- CompileSuccessfully(
- GetUnreachableMergeWithComplexBody(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableMergeWithComplexBody(GetParam()));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableMergeWithComplexBody) {
- CompileSuccessfully(GetUnreachableMergeWithComplexBody(SpvCapabilityShader,
- SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("must only contain an OpLabel and OpUnreachable instruction"));
-}
-
-std::string GetUnreachableContinueWithComplexBody(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableContinueWithComplexBody(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block branch("branch", SpvOpBranch);
@@ -1119,22 +965,14 @@
target >> branch;
- entry.AppendBody(spvIsWebGPUEnv(env)
- ? "%placeholder = OpVariable %intptrt Function %two\n"
- : "%placeholder = OpVariable %intptrt Function\n");
+ entry.AppendBody("%placeholder = OpVariable %intptrt Function\n");
target.AppendBody("OpStore %placeholder %one\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader)
branch.AppendBody("OpLoopMerge %merge %target None\n");
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
str += types_consts();
str += "%intptrt = OpTypePointer Function %intt\n";
str += "%func = OpFunction %voidt None %funct\n";
@@ -1148,24 +986,12 @@
}
TEST_P(ValidateCFG, UnreachableContinueWithComplexBody) {
- CompileSuccessfully(
- GetUnreachableContinueWithComplexBody(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableContinueWithComplexBody(GetParam()));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableContinueWithComplexBody) {
- CompileSuccessfully(GetUnreachableContinueWithComplexBody(SpvCapabilityShader,
- SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("must only contain an OpLabel and an OpBranch instruction"));
-}
-
-std::string GetUnreachableMergeWithBranchUse(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableMergeWithBranchUse(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block branch("branch", SpvOpBranchConditional);
@@ -1176,16 +1002,10 @@
entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader)
branch.AppendBody("OpSelectionMerge %merge None\n");
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
str += entry >> branch;
@@ -1199,15 +1019,12 @@
}
TEST_P(ValidateCFG, UnreachableMergeWithBranchUse) {
- CompileSuccessfully(
- GetUnreachableMergeWithBranchUse(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableMergeWithBranchUse(GetParam()));
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block branch("branch", SpvOpBranchConditional);
@@ -1219,18 +1036,12 @@
entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader) {
branch.AppendBody("OpSelectionMerge %merge None\n");
duplicate.AppendBody("OpSelectionMerge %merge None\n");
}
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
str += entry >> branch;
@@ -1245,8 +1056,7 @@
}
TEST_P(ValidateCFG, UnreachableMergeWithMultipleUses) {
- CompileSuccessfully(
- GetUnreachableMergeWithMultipleUses(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableMergeWithMultipleUses(GetParam()));
if (GetParam() == SpvCapabilityShader) {
ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
@@ -1256,18 +1066,8 @@
}
}
-TEST_F(ValidateCFG, WebGPUUnreachableMergeWithMultipleUses) {
- CompileSuccessfully(GetUnreachableMergeWithMultipleUses(SpvCapabilityShader,
- SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("is already a merge block for another header"));
-}
-
-std::string GetUnreachableContinueWithBranchUse(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableContinueWithBranchUse(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block foo("foo", SpvOpBranch);
@@ -1278,21 +1078,13 @@
foo >> target;
target >> branch;
- entry.AppendBody(spvIsWebGPUEnv(env)
- ? "%placeholder = OpVariable %intptrt Function %two\n"
- : "%placeholder = OpVariable %intptrt Function\n");
+ entry.AppendBody("%placeholder = OpVariable %intptrt Function\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader)
branch.AppendBody("OpLoopMerge %merge %target None\n");
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
+ str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
str += types_consts();
str += "%intptrt = OpTypePointer Function %intt\n";
str += "%func = OpFunction %voidt None %funct\n";
@@ -1307,23 +1099,12 @@
}
TEST_P(ValidateCFG, UnreachableContinueWithBranchUse) {
- CompileSuccessfully(
- GetUnreachableContinueWithBranchUse(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableContinueWithBranchUse(GetParam()));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableContinueWithBranchUse) {
- CompileSuccessfully(GetUnreachableContinueWithBranchUse(SpvCapabilityShader,
- SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("cannot be the target of a branch."));
-}
-
-std::string GetReachableMergeAndContinue(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetReachableMergeAndContinue(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block branch("branch", SpvOpBranch);
@@ -1339,20 +1120,13 @@
f >> target;
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader) {
branch.AppendBody("OpLoopMerge %merge %target None\n");
body.AppendBody("OpSelectionMerge %f None\n");
}
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", "target", "body", "t", "f",
- std::make_pair("func", "Main"));
-
+ str += nameOps("branch", "merge", "target", "body", "t", "f",
+ std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
str += entry >> branch;
@@ -1368,21 +1142,12 @@
}
TEST_P(ValidateCFG, ReachableMergeAndContinue) {
- CompileSuccessfully(
- GetReachableMergeAndContinue(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetReachableMergeAndContinue(GetParam()));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUReachableMergeAndContinue) {
- CompileSuccessfully(
- GetReachableMergeAndContinue(SpvCapabilityShader, SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-std::string GetUnreachableMergeAndContinue(SpvCapability cap,
- spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableMergeAndContinue(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block branch("branch", SpvOpBranch);
@@ -1396,20 +1161,13 @@
body.SetBody("%cond = OpSLessThan %boolt %one %two\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
if (cap == SpvCapabilityShader) {
branch.AppendBody("OpLoopMerge %merge %target None\n");
body.AppendBody("OpSelectionMerge %target None\n");
}
- if (!spvIsWebGPUEnv(env))
- str += nameOps("branch", "merge", "target", "body", "t", "f",
- std::make_pair("func", "Main"));
-
+ str += nameOps("branch", "merge", "target", "body", "t", "f",
+ std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
str += entry >> branch;
@@ -1425,36 +1183,19 @@
}
TEST_P(ValidateCFG, UnreachableMergeAndContinue) {
- CompileSuccessfully(
- GetUnreachableMergeAndContinue(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableMergeAndContinue(GetParam()));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableMergeAndContinue) {
- CompileSuccessfully(
- GetUnreachableMergeAndContinue(SpvCapabilityShader, SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("unreachable merge-blocks must terminate with OpUnreachable"));
-}
-
-std::string GetUnreachableBlock(SpvCapability cap, spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableBlock(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block unreachable("unreachable");
Block exit("exit", SpvOpReturn);
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
- if (!spvIsWebGPUEnv(env))
- str += nameOps("unreachable", "exit", std::make_pair("func", "Main"));
+ str += nameOps("unreachable", "exit", std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
str += entry >> exit;
@@ -1466,20 +1207,12 @@
}
TEST_P(ValidateCFG, UnreachableBlock) {
- CompileSuccessfully(GetUnreachableBlock(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableBlock(GetParam()));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableBlock) {
- CompileSuccessfully(
- GetUnreachableBlock(SpvCapabilityShader, SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(), HasSubstr("all blocks must be reachable"));
-}
-
-std::string GetUnreachableBranch(SpvCapability cap, spv_target_env env) {
- std::string header =
- spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap);
+std::string GetUnreachableBranch(SpvCapability cap) {
+ std::string header = GetDefaultHeader(cap);
Block entry("entry");
Block unreachable("unreachable", SpvOpBranchConditional);
@@ -1493,13 +1226,7 @@
unreachable.AppendBody("OpSelectionMerge %merge None\n");
std::string str = header;
- if (spvIsWebGPUEnv(env)) {
- str +=
- "OpEntryPoint Fragment %func \"func\"\n"
- "OpExecutionMode %func OriginUpperLeft\n";
- }
- if (!spvIsWebGPUEnv(env))
- str += nameOps("unreachable", "exit", std::make_pair("func", "Main"));
+ str += nameOps("unreachable", "exit", std::make_pair("func", "Main"));
str += types_consts();
str += "%func = OpFunction %voidt None %funct\n";
@@ -1516,17 +1243,10 @@
}
TEST_P(ValidateCFG, UnreachableBranch) {
- CompileSuccessfully(GetUnreachableBranch(GetParam(), SPV_ENV_UNIVERSAL_1_0));
+ CompileSuccessfully(GetUnreachableBranch(GetParam()));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateCFG, WebGPUUnreachableBranch) {
- CompileSuccessfully(
- GetUnreachableBranch(SpvCapabilityShader, SPV_ENV_WEBGPU_0));
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(), HasSubstr("all blocks must be reachable"));
-}
-
TEST_P(ValidateCFG, EmptyFunction) {
std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) +
R"(%func = OpFunction %voidt None %funct
@@ -4598,6 +4318,38 @@
EXPECT_THAT(getDiagnosticString(), HasSubstr("multiple times."));
}
+TEST_F(ValidateCFG, PhiOnVoid) {
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ OpName %4 "main"
+ OpName %6 "foo("
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpFunctionCall %2 %6
+ OpBranch %20
+ %20 = OpLabel
+ %21 = OpPhi %2 %8 %20
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpPhi must not have void result type"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_code_generator.cpp b/test/val/val_code_generator.cpp
index 62aae9c..f151f51 100644
--- a/test/val/val_code_generator.cpp
+++ b/test/val/val_code_generator.cpp
@@ -32,13 +32,6 @@
)";
}
-std::string GetWebGPUShaderCapabilities() {
- return R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-)";
-}
-
std::string GetDefaultShaderTypes() {
return R"(
%void = OpTypeVoid
@@ -115,55 +108,15 @@
%f32vec3arr3 = OpTypeArray %f32vec3 %u32_3
%f32vec4arr3 = OpTypeArray %f32vec4 %u32_3
%f64vec4arr3 = OpTypeArray %f64vec4 %u32_3
-)";
-}
-std::string GetWebGPUShaderTypes() {
- return R"(
-%void = OpTypeVoid
-%func = OpTypeFunction %void
-%bool = OpTypeBool
-%f32 = OpTypeFloat 32
-%u32 = OpTypeInt 32 0
-%f32vec2 = OpTypeVector %f32 2
-%f32vec3 = OpTypeVector %f32 3
-%f32vec4 = OpTypeVector %f32 4
-%u32vec2 = OpTypeVector %u32 2
-%u32vec3 = OpTypeVector %u32 3
-%u32vec4 = OpTypeVector %u32 4
-
-%f32_0 = OpConstant %f32 0
-%f32_1 = OpConstant %f32 1
-%f32_2 = OpConstant %f32 2
-%f32_3 = OpConstant %f32 3
-%f32_4 = OpConstant %f32 4
-%f32_h = OpConstant %f32 0.5
-%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1
-%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2
-%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2
-%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3
-%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3
-%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4
-
-%u32_0 = OpConstant %u32 0
-%u32_1 = OpConstant %u32 1
-%u32_2 = OpConstant %u32 2
-%u32_3 = OpConstant %u32 3
-%u32_4 = OpConstant %u32 4
-
-%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1
-%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2
-%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
-
-%u32arr2 = OpTypeArray %u32 %u32_2
-%u32arr3 = OpTypeArray %u32 %u32_3
-%u32arr4 = OpTypeArray %u32 %u32_4
-%f32arr2 = OpTypeArray %f32 %u32_2
-%f32arr3 = OpTypeArray %f32 %u32_3
-%f32arr4 = OpTypeArray %f32 %u32_4
-
-%f32vec3arr3 = OpTypeArray %f32vec3 %u32_3
-%f32vec4arr3 = OpTypeArray %f32vec4 %u32_3
+%f32mat22 = OpTypeMatrix %f32vec2 2
+%f32mat23 = OpTypeMatrix %f32vec2 3
+%f32mat32 = OpTypeMatrix %f32vec3 2
+%f32mat33 = OpTypeMatrix %f32vec3 3
+%f64mat22 = OpTypeMatrix %f64vec2 2
+%f32mat34 = OpTypeMatrix %f32vec3 4
+%f32mat43 = OpTypeMatrix %f32vec4 3
+%f32mat44 = OpTypeMatrix %f32vec4 4
)";
}
@@ -177,15 +130,6 @@
return generator;
}
-CodeGenerator CodeGenerator::GetWebGPUShaderCodeGenerator() {
- CodeGenerator generator;
- generator.capabilities_ = GetWebGPUShaderCapabilities();
- generator.memory_model_ = "OpMemoryModel Logical VulkanKHR\n";
- generator.extensions_ = "OpExtension \"SPV_KHR_vulkan_memory_model\"\n";
- generator.types_ = GetWebGPUShaderTypes();
- return generator;
-}
-
std::string CodeGenerator::Build() const {
std::ostringstream ss;
diff --git a/test/val/val_code_generator.h b/test/val/val_code_generator.h
index e580ddf..c69deee 100644
--- a/test/val/val_code_generator.h
+++ b/test/val/val_code_generator.h
@@ -31,7 +31,6 @@
class CodeGenerator {
public:
static CodeGenerator GetDefaultShaderCodeGenerator();
- static CodeGenerator GetWebGPUShaderCodeGenerator();
std::string Build() const;
diff --git a/test/val/val_composites_test.cpp b/test/val/val_composites_test.cpp
index e970562..bf7caa9 100644
--- a/test/val/val_composites_test.cpp
+++ b/test/val/val_composites_test.cpp
@@ -1994,6 +1994,36 @@
HasSubstr("Cannot transpose matrices of 16-bit floats"));
}
+TEST_F(ValidateComposites, CopyObjectVoid) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ OpName %4 "main"
+ OpName %6 "foo("
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpFunctionCall %2 %6
+ %20 = OpCopyObject %2 %8
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpCopyObject cannot have void result type"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_data_test.cpp b/test/val/val_data_test.cpp
index 30afd03..1d4c0e0 100644
--- a/test/val/val_data_test.cpp
+++ b/test/val/val_data_test.cpp
@@ -36,24 +36,6 @@
cap + " OpMemoryModel Logical GLSL450 ";
}
-std::string WebGPUHeaderWith(std::string cap) {
- return R"(
-OpCapability Shader
-OpCapability )" +
- cap + R"(
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-)";
-}
-
-std::string webgpu_header = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-)";
-
std::string header = R"(
OpCapability Shader
OpCapability Linkage
@@ -267,18 +249,6 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
}
-TEST_F(ValidateData, webgpu_int8_bad) {
- std::string str = WebGPUHeaderWith("Int8") + "%2 = OpTypeInt 8 0";
- CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Capability Int8 is not allowed by WebGPU specification (or "
- "requires extension)\n"
- " OpCapability Int8\n"));
-}
-
TEST_F(ValidateData, int16_good) {
std::string str = header_with_int16 + "%2 = OpTypeInt 16 1";
CompileSuccessfully(str.c_str());
@@ -338,34 +308,6 @@
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error));
}
-TEST_F(ValidateData, webgpu_int16_bad) {
- std::string str = WebGPUHeaderWith("Int16") + "%2 = OpTypeInt 16 1";
- CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Capability Int16 is not allowed by WebGPU specification (or "
- "requires extension)\n"
- " OpCapability Int16\n"));
-}
-
-TEST_F(ValidateData, webgpu_int32_good) {
- std::string str = webgpu_header + R"(
- OpEntryPoint Fragment %func "func"
- OpExecutionMode %func OriginUpperLeft
-%uint_t = OpTypeInt 32 0
- %void = OpTypeVoid
-%func_t = OpTypeFunction %void
- %func = OpFunction %void None %func_t
- %1 = OpLabel
- OpReturn
- OpFunctionEnd
-)";
- CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
TEST_F(ValidateData, int64_good) {
std::string str = header_with_int64 + "%2 = OpTypeInt 64 1";
CompileSuccessfully(str.c_str());
@@ -379,18 +321,6 @@
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error));
}
-TEST_F(ValidateData, webgpu_int64_bad) {
- std::string str = WebGPUHeaderWith("Int64") + "%2 = OpTypeInt 64 1";
- CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Capability Int64 is not allowed by WebGPU specification (or "
- "requires extension)\n"
- " OpCapability Int64\n"));
-}
-
// Number of bits in an integer may be only one of: {8,16,32,64}
TEST_F(ValidateData, int_invalid_num_bits) {
std::string str = header + "%2 = OpTypeInt 48 1";
@@ -418,34 +348,6 @@
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error));
}
-TEST_F(ValidateData, webgpu_float16_bad) {
- std::string str = WebGPUHeaderWith("Float16") + "%2 = OpTypeFloat 16";
- CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Capability Float16 is not allowed by WebGPU specification (or "
- "requires extension)\n"
- " OpCapability Float16\n"));
-}
-
-TEST_F(ValidateData, webgpu_float32_good) {
- std::string str = webgpu_header + R"(
- OpEntryPoint Fragment %func "func"
- OpExecutionMode %func OriginUpperLeft
-%float_t = OpTypeFloat 32
- %void = OpTypeVoid
- %func_t = OpTypeFunction %void
- %func = OpFunction %void None %func_t
- %1 = OpLabel
- OpReturn
- OpFunctionEnd
-)";
- CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
TEST_F(ValidateData, float64_good) {
std::string str = header_with_float64 + "%2 = OpTypeFloat 64";
CompileSuccessfully(str.c_str());
@@ -459,18 +361,6 @@
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error));
}
-TEST_F(ValidateData, webgpu_float64_bad) {
- std::string str = WebGPUHeaderWith("Float64") + "%2 = OpTypeFloat 64";
- CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Capability Float64 is not allowed by WebGPU specification (or "
- "requires extension)\n"
- " OpCapability Float64\n"));
-}
-
// Number of bits in a float may be only one of: {16,32,64}
TEST_F(ValidateData, float_invalid_num_bits) {
std::string str = header + "%2 = OpTypeFloat 48";
@@ -497,7 +387,7 @@
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("ID 3[%3] has not been defined"));
+ HasSubstr("Operand 3[%3] requires a previous definition"));
}
TEST_F(ValidateData, matrix_bad_column_type) {
@@ -882,66 +772,58 @@
"OpTypeStruct %_runtimearr_uint %uint\n"));
}
-TEST_F(ValidateData, webgpu_RTA_array_at_end_of_struct) {
- std::string str = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Fragment %func "func"
- OpExecutionMode %func OriginUpperLeft
- OpDecorate %array_t ArrayStride 4
- OpMemberDecorate %struct_t 0 Offset 0
- OpMemberDecorate %struct_t 1 Offset 4
- OpDecorate %struct_t Block
- %uint_t = OpTypeInt 32 0
- %array_t = OpTypeRuntimeArray %uint_t
- %struct_t = OpTypeStruct %uint_t %array_t
-%struct_ptr = OpTypePointer StorageBuffer %struct_t
- %2 = OpVariable %struct_ptr StorageBuffer
- %void = OpTypeVoid
- %func_t = OpTypeFunction %void
- %func = OpFunction %void None %func_t
- %1 = OpLabel
- OpReturn
- OpFunctionEnd
+TEST_F(ValidateData, TypeForwardReference) {
+ std::string test = R"(
+OpCapability Shader
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+OpTypeForwardPointer %1 PhysicalStorageBuffer
+%2 = OpTypeStruct
+%3 = OpTypeRuntimeArray %1
+%1 = OpTypePointer PhysicalStorageBuffer %2
)";
- CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
+ CompileSuccessfully(test, SPV_ENV_UNIVERSAL_1_5);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
}
-TEST_F(ValidateData, webgpu_RTA_not_at_end_of_struct) {
- std::string str = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Fragment %func "func"
- OpExecutionMode %func OriginUpperLeft
- OpDecorate %array_t ArrayStride 4
- OpMemberDecorate %struct_t 0 Offset 0
- OpMemberDecorate %struct_t 1 Offset 4
- OpDecorate %struct_t Block
- %uint_t = OpTypeInt 32 0
- %array_t = OpTypeRuntimeArray %uint_t
- %struct_t = OpTypeStruct %array_t %uint_t
-%struct_ptr = OpTypePointer StorageBuffer %struct_t
- %2 = OpVariable %struct_ptr StorageBuffer
- %void = OpTypeVoid
- %func_t = OpTypeFunction %void
- %func = OpFunction %void None %func_t
- %1 = OpLabel
- OpReturn
- OpFunctionEnd
+TEST_F(ValidateData, VulkanTypeForwardStorageClass) {
+ std::string test = R"(
+OpCapability Shader
+OpCapability PhysicalStorageBufferAddresses
+OpMemoryModel Logical GLSL450
+OpTypeForwardPointer %1 Uniform
+%2 = OpTypeStruct
+%3 = OpTypeRuntimeArray %1
+%1 = OpTypePointer Uniform %2
)";
- CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
+ CompileSuccessfully(test, SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("In WebGPU, OpTypeRuntimeArray must only be used for "
- "the last member of an OpTypeStruct\n %_struct_3 = "
- "OpTypeStruct %_runtimearr_uint %uint\n"));
+ AnyVUID("VUID-StandaloneSpirv-OpTypeForwardPointer-04711"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("In Vulkan, OpTypeForwardPointer must have "
+ "a storage class of PhysicalStorageBuffer."));
+}
+
+TEST_F(ValidateData, TypeForwardReferenceMustBeForwardPointer) {
+ std::string test = R"(
+OpCapability Shader
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%1 = OpTypeStruct
+%2 = OpTypeRuntimeArray %3
+%3 = OpTypePointer PhysicalStorageBuffer %1
+)";
+
+ CompileSuccessfully(test, SPV_ENV_UNIVERSAL_1_5);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Operand 3[%_ptr_PhysicalStorageBuffer__struct_1] "
+ "requires a previous definition"));
}
} // namespace
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index e646162..8fe1aa6 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -42,8 +42,8 @@
};
using ValidateDecorations = spvtest::ValidateBase<bool>;
-using ValidateWebGPUCombineDecorationResult =
- spvtest::ValidateBase<std::tuple<const char*, TestResult>>;
+using ValidateVulkanCombineDecorationResult =
+ spvtest::ValidateBase<std::tuple<const char*, const char*, TestResult>>;
TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) {
std::string spirv = R"(
@@ -163,44 +163,6 @@
EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations));
}
-TEST_F(ValidateDecorations, WebGPUOpDecorationGroupBad) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpDecorate %1 DescriptorSet 0
- OpDecorate %1 NonWritable
- OpDecorate %1 Restrict
- %1 = OpDecorationGroup
- OpGroupDecorate %1 %2 %3
- OpGroupDecorate %1 %4
- %float = OpTypeFloat 32
-%_runtimearr_float = OpTypeRuntimeArray %float
- %_struct_9 = OpTypeStruct %_runtimearr_float
-%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
- %2 = OpVariable %_ptr_Uniform__struct_9 Uniform
- %_struct_10 = OpTypeStruct %_runtimearr_float
-%_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10
- %3 = OpVariable %_ptr_Uniform__struct_10 Uniform
- %_struct_11 = OpTypeStruct %_runtimearr_float
-%_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11
- %4 = OpVariable %_ptr_Uniform__struct_11 Uniform
- )";
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("OpDecorationGroup is not allowed in the WebGPU "
- "execution environment.\n %1 = OpDecorationGroup\n"));
-}
-
-// For WebGPU, OpGroupDecorate does not have a test case, because it requires
-// being preceded by OpDecorationGroup, which will cause a validation error.
-
-// For WebGPU, OpGroupMemberDecorate does not have a test case, because it
-// requires being preceded by OpDecorationGroup, which will cause a validation
-// error.
-
TEST_F(ValidateDecorations, ValidateGroupMemberDecorateRegistration) {
std::string spirv = R"(
OpCapability Shader
@@ -4679,6 +4641,95 @@
"Object operand of an OpStore."));
}
+TEST_F(ValidateDecorations, VulkanFPRoundingModeGood) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability StorageBuffer16BitAccess
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 1 1 1
+ OpMemberDecorate %ssbo 0 Offset 0
+ OpDecorate %ssbo Block
+ OpDecorate %_ DescriptorSet 0
+ OpDecorate %_ Binding 0
+ OpDecorate %17 FPRoundingMode RTE
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+%_ptr_Function_float = OpTypePointer Function %float
+ %float_1 = OpConstant %float 1
+ %half = OpTypeFloat 16
+ %ssbo = OpTypeStruct %half
+%_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo
+ %_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %b = OpVariable %_ptr_Function_float Function
+ OpStore %b %float_1
+ %16 = OpLoad %float %b
+ %17 = OpFConvert %half %16
+ %19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0
+ OpStore %19 %17
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
+}
+
+TEST_F(ValidateDecorations, VulkanFPRoundingModeBadMode) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability StorageBuffer16BitAccess
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 1 1 1
+ OpMemberDecorate %ssbo 0 Offset 0
+ OpDecorate %ssbo Block
+ OpDecorate %_ DescriptorSet 0
+ OpDecorate %_ Binding 0
+ OpDecorate %17 FPRoundingMode RTP
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+%_ptr_Function_float = OpTypePointer Function %float
+ %float_1 = OpConstant %float 1
+ %half = OpTypeFloat 16
+ %ssbo = OpTypeStruct %half
+%_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo
+ %_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %b = OpVariable %_ptr_Function_float Function
+ OpStore %b %float_1
+ %16 = OpLoad %float %b
+ %17 = OpFConvert %half %16
+ %19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0
+ OpStore %19 %17
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID,
+ ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-FPRoundingMode-04675"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("In Vulkan, the FPRoundingMode mode must only by RTE or RTZ."));
+}
+
TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup) {
std::string spirv = R"(
OpCapability Shader
@@ -6299,11 +6350,12 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_P(ValidateWebGPUCombineDecorationResult, Decorate) {
+TEST_P(ValidateVulkanCombineDecorationResult, Decorate) {
const char* const decoration = std::get<0>(GetParam());
- const TestResult& test_result = std::get<1>(GetParam());
+ const char* const vuid = std::get<1>(GetParam());
+ const TestResult& test_result = std::get<2>(GetParam());
- CodeGenerator generator = CodeGenerator::GetWebGPUShaderCodeGenerator();
+ CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = "OpDecorate %u32 ";
generator.before_types_ += decoration;
generator.before_types_ += "\n";
@@ -6313,52 +6365,24 @@
entry_point.execution_model = "Vertex";
generator.entry_points_.push_back(std::move(entry_point));
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
+ CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(test_result.validation_result,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- if (test_result.error_str != "") {
- EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
- }
-}
-
-TEST_P(ValidateWebGPUCombineDecorationResult, DecorateMember) {
- const char* const decoration = std::get<0>(GetParam());
- const TestResult& test_result = std::get<1>(GetParam());
-
- CodeGenerator generator = CodeGenerator::GetWebGPUShaderCodeGenerator();
- generator.before_types_ = "OpMemberDecorate %struct_type 0 ";
- generator.before_types_ += decoration;
- generator.before_types_ += "\n";
-
- generator.after_types_ = "%struct_type = OpTypeStruct %u32\n";
-
- EntryPoint entry_point;
- entry_point.name = "main";
- entry_point.execution_model = "Vertex";
- generator.entry_points_.push_back(std::move(entry_point));
-
- CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
- ASSERT_EQ(test_result.validation_result,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
+ ValidateInstructions(SPV_ENV_VULKAN_1_0));
if (!test_result.error_str.empty()) {
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
}
+ if (vuid) {
+ EXPECT_THAT(getDiagnosticString(), AnyVUID(vuid));
+ }
}
INSTANTIATE_TEST_SUITE_P(
- DecorationCapabilityFailure, ValidateWebGPUCombineDecorationResult,
- Combine(Values("CPacked", "Patch", "Sample", "Constant",
- "SaturatedConversion", "NonUniformEXT"),
- Values(TestResult(SPV_ERROR_INVALID_CAPABILITY,
- "requires one of these capabilities"))));
-
-INSTANTIATE_TEST_SUITE_P(
- DecorationAllowListFailure, ValidateWebGPUCombineDecorationResult,
- Combine(Values("RelaxedPrecision", "BufferBlock", "GLSLShared",
- "GLSLPacked", "Invariant", "Volatile", "Coherent"),
+ DecorationAllowListFailure, ValidateVulkanCombineDecorationResult,
+ Combine(Values("GLSLShared", "GLSLPacked"),
+ Values("VUID-StandaloneSpirv-GLSLShared-04669"),
Values(TestResult(
SPV_ERROR_INVALID_ID,
- "is not valid for the WebGPU execution environment."))));
+ "is not valid for the Vulkan execution environment."))));
TEST_F(ValidateDecorations, NonWritableVarFunctionV13Bad) {
std::string spirv = ShaderWithNonWritableTarget("%var_func");
diff --git a/test/val/val_fixtures.h b/test/val/val_fixtures.h
index 5635c78..acbe0e5 100644
--- a/test/val/val_fixtures.h
+++ b/test/val/val_fixtures.h
@@ -183,4 +183,43 @@
} // namespace spvtest
+// For Vulkan testing.
+// Allows test parameter test to list all possible VUIDs with a delimiter that
+// is then split here to check if one VUID was in the error message
+MATCHER_P(AnyVUID, vuid_set, "VUID from the set is in error message") {
+ // use space as delimiter because clang-format will properly line break VUID
+ // strings which is important the entire VUID is in a single line for script
+ // to scan
+ std::string delimiter = " ";
+ std::string token;
+ std::string vuids = std::string(vuid_set);
+ size_t position;
+
+ // Catch case were someone accidentally left spaces by trimming string
+ // clang-format off
+ vuids.erase(std::find_if(vuids.rbegin(), vuids.rend(), [](unsigned char c) {
+ return (c != ' ');
+ }).base(), vuids.end());
+ vuids.erase(vuids.begin(), std::find_if(vuids.begin(), vuids.end(), [](unsigned char c) {
+ return (c != ' ');
+ }));
+ // clang-format on
+
+ do {
+ position = vuids.find(delimiter);
+ if (position != std::string::npos) {
+ token = vuids.substr(0, position);
+ vuids.erase(0, position + delimiter.length());
+ } else {
+ token = vuids.substr(0); // last item
+ }
+
+ // arg contains diagnostic message
+ if (arg.find(token) != std::string::npos) {
+ return true;
+ }
+ } while (position != std::string::npos);
+ return false;
+}
+
#endif // TEST_VAL_VAL_FIXTURES_H_
diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp
index adea563..c65d171 100644
--- a/test/val/val_id_test.cpp
+++ b/test/val/val_id_test.cpp
@@ -411,10 +411,10 @@
}
TEST_F(ValidateIdWithMessage, OpEntryPointParameterCountBad) {
std::string spirv = kGLSL450MemoryModel + R"(
- OpEntryPoint GLCompute %3 ""
-%1 = OpTypeVoid
-%2 = OpTypeFunction %1 %1
-%3 = OpFunction %1 None %2
+ OpEntryPoint GLCompute %1 ""
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2 %2
+%1 = OpFunction %2 None %3
%4 = OpLabel
OpReturn
OpFunctionEnd)";
@@ -426,11 +426,11 @@
}
TEST_F(ValidateIdWithMessage, OpEntryPointReturnTypeBad) {
std::string spirv = kGLSL450MemoryModel + R"(
- OpEntryPoint GLCompute %3 ""
-%1 = OpTypeInt 32 0
-%ret = OpConstant %1 0
-%2 = OpTypeFunction %1
-%3 = OpFunction %1 None %2
+ OpEntryPoint GLCompute %1 ""
+%2 = OpTypeInt 32 0
+%ret = OpConstant %2 0
+%3 = OpTypeFunction %2
+%1 = OpFunction %2 None %3
%4 = OpLabel
OpReturnValue %ret
OpFunctionEnd)";
@@ -440,6 +440,45 @@
HasSubstr("OpEntryPoint Entry Point <id> '1[%1]'s function "
"return type is not void."));
}
+TEST_F(ValidateIdWithMessage, OpEntryPointParameterCountBadInVulkan) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %1 ""
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2 %2
+%1 = OpFunction %2 None %3
+%4 = OpLabel
+ OpReturn
+ OpFunctionEnd)";
+ CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-None-04633"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpEntryPoint Entry Point <id> '1[%1]'s function "
+ "parameter count is not zero"));
+}
+TEST_F(ValidateIdWithMessage, OpEntryPointReturnTypeBadInVulkan) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %1 ""
+%2 = OpTypeInt 32 0
+%ret = OpConstant %2 0
+%3 = OpTypeFunction %2
+%1 = OpFunction %2 None %3
+%4 = OpLabel
+ OpReturnValue %ret
+ OpFunctionEnd)";
+ CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-None-04633"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpEntryPoint Entry Point <id> '1[%1]'s function "
+ "return type is not void."));
+}
TEST_F(ValidateIdWithMessage, OpEntryPointInterfaceIsNotVariableTypeBad) {
std::string spirv = R"(
@@ -915,31 +954,6 @@
}
}
-TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding0InWebGPU) {
- env_ = SPV_ENV_WEBGPU_0;
- const int width = GetParam();
- // WebGPU only has 32 bit integers.
- if (width != 32) return;
- const int max_int_width = 32;
- const auto module = CompileSuccessfully(MakeArrayLength(
- big_num_ending_0(width), kUnsigned, width, max_int_width, true));
- EXPECT_EQ(SPV_SUCCESS, Val(module));
-}
-
-TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding1InWebGPU) {
- env_ = SPV_ENV_WEBGPU_0;
- const int width = GetParam();
- // WebGPU only has 32 bit integers.
- if (width != 32) return;
- const int max_int_width = 32;
- const auto module = CompileSuccessfully(MakeArrayLength(
- big_num_ending_1(width), kUnsigned, width, max_int_width, true));
- EXPECT_EQ(SPV_ERROR_INVALID_ID,
- Val(module,
- "OpTypeArray Length <id> '3\\[%.*\\]' size exceeds max value "
- "2147483648 permitted by WebGPU: got 2147483649"));
-}
-
// The only valid widths for integers are 8, 16, 32, and 64.
// Since the Int8 capability requires the Kernel capability, and the Kernel
// capability prohibits usage of signed integers, we can skip 8-bit integers
@@ -2749,9 +2763,13 @@
%6 = OpVariable %3 Uniform
%7 = OpFunction %1 None %4
%8 = OpLabel
-%9 = OpUndef %1
+%9 = OpFunctionCall %1 %10
OpStore %6 %9
OpReturn
+ OpFunctionEnd
+%10 = OpFunction %1 None %4
+%11 = OpLabel
+ OpReturn
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
@@ -4688,39 +4706,6 @@
"size of 5."));
}
-TEST_F(ValidateIdWithMessage, WebGPUOpVectorShuffle0xFFFFFFFFLiteralBad) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
-%float = OpTypeFloat 32
-%vec2 = OpTypeVector %float 2
-%vec3 = OpTypeVector %float 3
-%vec4 = OpTypeVector %float 4
-%ptr_vec2 = OpTypePointer Function %vec2
-%ptr_vec3 = OpTypePointer Function %vec3
-%float_1 = OpConstant %float 1
-%float_2 = OpConstant %float 2
-%1 = OpConstantComposite %vec2 %float_2 %float_1
-%2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
-%3 = OpTypeFunction %vec4
-%4 = OpFunction %vec4 None %3
-%5 = OpLabel
-%var = OpVariable %ptr_vec2 Function %1
-%var2 = OpVariable %ptr_vec3 Function %2
-%6 = OpLoad %vec2 %var
-%7 = OpLoad %vec3 %var2
-%8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0xffffffff
- OpReturnValue %8
- OpFunctionEnd)";
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Component literal at operand 3 cannot be 0xFFFFFFFF in"
- " WebGPU execution environment."));
-}
-
// TODO: OpCompositeConstruct
// TODO: OpCompositeExtract
// TODO: OpCompositeInsert
diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp
index 2e84a29..ce4bf1b 100644
--- a/test/val/val_image_test.cpp
+++ b/test/val/val_image_test.cpp
@@ -66,9 +66,9 @@
%uniform_image_f32_1d_0001
%uniform_image_f32_1d_0002_rgba32f
%uniform_image_f32_2d_0001
-%uniform_image_f32_2d_0010
+%uniform_image_f32_2d_0011 ; multisampled sampled
%uniform_image_u32_2d_0001
-%uniform_image_u32_2d_0000
+%uniform_image_u32_2d_0002
%uniform_image_s32_3d_0001
%uniform_image_f32_2d_0002
%uniform_image_s32_2d_0002
@@ -99,12 +99,12 @@
OpDecorate %uniform_image_f32_1d_0002_rgba32f Binding 1
OpDecorate %uniform_image_f32_2d_0001 DescriptorSet 0
OpDecorate %uniform_image_f32_2d_0001 Binding 2
-OpDecorate %uniform_image_f32_2d_0010 DescriptorSet 0
-OpDecorate %uniform_image_f32_2d_0010 Binding 3
+OpDecorate %uniform_image_f32_2d_0011 DescriptorSet 0
+OpDecorate %uniform_image_f32_2d_0011 Binding 3
OpDecorate %uniform_image_u32_2d_0001 DescriptorSet 1
OpDecorate %uniform_image_u32_2d_0001 Binding 0
-OpDecorate %uniform_image_u32_2d_0000 DescriptorSet 1
-OpDecorate %uniform_image_u32_2d_0000 Binding 1
+OpDecorate %uniform_image_u32_2d_0002 DescriptorSet 1
+OpDecorate %uniform_image_u32_2d_0002 Binding 1
OpDecorate %uniform_image_s32_3d_0001 DescriptorSet 1
OpDecorate %uniform_image_s32_3d_0001 Binding 2
OpDecorate %uniform_image_f32_2d_0002 DescriptorSet 1
@@ -133,6 +133,7 @@
%u32 = OpTypeInt 32 0
%s32 = OpTypeInt 32 1
%u64 = OpTypeInt 64 0
+%s64 = OpTypeInt 64 1
%s32vec2 = OpTypeVector %s32 2
%u32vec2 = OpTypeVector %u32 2
%f32vec2 = OpTypeVector %f32 2
@@ -223,27 +224,25 @@
%type_image_f32_1d_0002_rgba32f = OpTypeImage %f32 1D 0 0 0 2 Rgba32f
%ptr_image_f32_1d_0002_rgba32f = OpTypePointer UniformConstant %type_image_f32_1d_0002_rgba32f
%uniform_image_f32_1d_0002_rgba32f = OpVariable %ptr_image_f32_1d_0002_rgba32f UniformConstant
-%type_sampled_image_f32_1d_0002_rgba32f = OpTypeSampledImage %type_image_f32_1d_0002_rgba32f
%type_image_f32_2d_0001 = OpTypeImage %f32 2D 0 0 0 1 Unknown
%ptr_image_f32_2d_0001 = OpTypePointer UniformConstant %type_image_f32_2d_0001
%uniform_image_f32_2d_0001 = OpVariable %ptr_image_f32_2d_0001 UniformConstant
%type_sampled_image_f32_2d_0001 = OpTypeSampledImage %type_image_f32_2d_0001
-%type_image_f32_2d_0010 = OpTypeImage %f32 2D 0 0 1 0 Unknown
-%ptr_image_f32_2d_0010 = OpTypePointer UniformConstant %type_image_f32_2d_0010
-%uniform_image_f32_2d_0010 = OpVariable %ptr_image_f32_2d_0010 UniformConstant
-%type_sampled_image_f32_2d_0010 = OpTypeSampledImage %type_image_f32_2d_0010
+%type_image_f32_2d_0011 = OpTypeImage %f32 2D 0 0 1 1 Unknown
+%ptr_image_f32_2d_0011 = OpTypePointer UniformConstant %type_image_f32_2d_0011
+%uniform_image_f32_2d_0011 = OpVariable %ptr_image_f32_2d_0011 UniformConstant
+%type_sampled_image_f32_2d_0011 = OpTypeSampledImage %type_image_f32_2d_0011
%type_image_u32_2d_0001 = OpTypeImage %u32 2D 0 0 0 1 Unknown
%ptr_image_u32_2d_0001 = OpTypePointer UniformConstant %type_image_u32_2d_0001
%uniform_image_u32_2d_0001 = OpVariable %ptr_image_u32_2d_0001 UniformConstant
%type_sampled_image_u32_2d_0001 = OpTypeSampledImage %type_image_u32_2d_0001
-%type_image_u32_2d_0000 = OpTypeImage %u32 2D 0 0 0 0 Unknown
-%ptr_image_u32_2d_0000 = OpTypePointer UniformConstant %type_image_u32_2d_0000
-%uniform_image_u32_2d_0000 = OpVariable %ptr_image_u32_2d_0000 UniformConstant
-%type_sampled_image_u32_2d_0000 = OpTypeSampledImage %type_image_u32_2d_0000
+%type_image_u32_2d_0002 = OpTypeImage %u32 2D 0 0 0 2 Unknown
+%ptr_image_u32_2d_0002 = OpTypePointer UniformConstant %type_image_u32_2d_0002
+%uniform_image_u32_2d_0002 = OpVariable %ptr_image_u32_2d_0002 UniformConstant
%type_image_s32_3d_0001 = OpTypeImage %s32 3D 0 0 0 1 Unknown
%ptr_image_s32_3d_0001 = OpTypePointer UniformConstant %type_image_s32_3d_0001
@@ -253,17 +252,14 @@
%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Unknown
%ptr_image_f32_2d_0002 = OpTypePointer UniformConstant %type_image_f32_2d_0002
%uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant
-%type_sampled_image_f32_2d_0002 = OpTypeSampledImage %type_image_f32_2d_0002
%type_image_s32_2d_0002 = OpTypeImage %s32 2D 0 0 0 2 Unknown
%ptr_image_s32_2d_0002 = OpTypePointer UniformConstant %type_image_s32_2d_0002
%uniform_image_s32_2d_0002 = OpVariable %ptr_image_s32_2d_0002 UniformConstant
-%type_sampled_image_s32_2d_0002 = OpTypeSampledImage %type_image_s32_2d_0002
%type_image_f32_spd_0002 = OpTypeImage %f32 SubpassData 0 0 0 2 Unknown
%ptr_image_f32_spd_0002 = OpTypePointer UniformConstant %type_image_f32_spd_0002
%uniform_image_f32_spd_0002 = OpVariable %ptr_image_f32_spd_0002 UniformConstant
-%type_sampled_image_f32_spd_0002 = OpTypeSampledImage %type_image_f32_spd_0002
%type_image_f32_3d_0111 = OpTypeImage %f32 3D 0 1 1 1 Unknown
%ptr_image_f32_3d_0111 = OpTypePointer UniformConstant %type_image_f32_3d_0111
@@ -278,7 +274,6 @@
%type_image_f32_cube_0102_rgba32f = OpTypeImage %f32 Cube 0 1 0 2 Rgba32f
%ptr_image_f32_cube_0102_rgba32f = OpTypePointer UniformConstant %type_image_f32_cube_0102_rgba32f
%uniform_image_f32_cube_0102_rgba32f = OpVariable %ptr_image_f32_cube_0102_rgba32f UniformConstant
-%type_sampled_image_f32_cube_0102_rgba32f = OpTypeSampledImage %type_image_f32_cube_0102_rgba32f
%type_sampler = OpTypeSampler
%ptr_sampler = OpTypePointer UniformConstant %type_sampler
@@ -311,7 +306,6 @@
%type_image_void_2d_0002 = OpTypeImage %void 2D 0 0 0 2 Unknown
%ptr_image_void_2d_0002 = OpTypePointer UniformConstant %type_image_void_2d_0002
%uniform_image_void_2d_0002 = OpVariable %ptr_image_void_2d_0002 UniformConstant
-%type_sampled_image_void_2d_0002 = OpTypeSampledImage %type_image_void_2d_0002
%type_image_f32_rect_0001 = OpTypeImage %f32 Rect 0 0 0 1 Unknown
%ptr_image_f32_rect_0001 = OpTypePointer UniformConstant %type_image_f32_rect_0001
@@ -400,15 +394,15 @@
%uniform_image_f32_2d_0001 = OpVariable %ptr_image_f32_2d_0001 UniformConstant
%type_sampled_image_f32_2d_0001 = OpTypeSampledImage %type_image_f32_2d_0001
-%type_image_f32_2d_0010 = OpTypeImage %f32 2D 0 0 1 0 Unknown
-%ptr_image_f32_2d_0010 = OpTypePointer UniformConstant %type_image_f32_2d_0010
-%uniform_image_f32_2d_0010 = OpVariable %ptr_image_f32_2d_0010 UniformConstant
-%type_sampled_image_f32_2d_0010 = OpTypeSampledImage %type_image_f32_2d_0010
+%type_image_f32_2d_0011 = OpTypeImage %f32 2D 0 0 1 1 Unknown
+%ptr_image_f32_2d_0011 = OpTypePointer UniformConstant %type_image_f32_2d_0011
+%uniform_image_f32_2d_0011 = OpVariable %ptr_image_f32_2d_0011 UniformConstant
+%type_sampled_image_f32_2d_0011 = OpTypeSampledImage %type_image_f32_2d_0011
-%type_image_f32_3d_0010 = OpTypeImage %f32 3D 0 0 1 0 Unknown
-%ptr_image_f32_3d_0010 = OpTypePointer UniformConstant %type_image_f32_3d_0010
-%uniform_image_f32_3d_0010 = OpVariable %ptr_image_f32_3d_0010 UniformConstant
-%type_sampled_image_f32_3d_0010 = OpTypeSampledImage %type_image_f32_3d_0010
+%type_image_f32_3d_0011 = OpTypeImage %f32 3D 0 0 1 1 Unknown
+%ptr_image_f32_3d_0011 = OpTypePointer UniformConstant %type_image_f32_3d_0011
+%uniform_image_f32_3d_0011 = OpVariable %ptr_image_f32_3d_0011 UniformConstant
+%type_sampled_image_f32_3d_0011 = OpTypeSampledImage %type_image_f32_3d_0011
%type_image_f32_rect_0001 = OpTypeImage %f32 Rect 0 0 0 1 Unknown
%ptr_image_f32_rect_0001 = OpTypePointer UniformConstant %type_image_f32_rect_0001
@@ -431,12 +425,35 @@
return ss.str();
}
+std::string GetKernelHeader() {
+ return R"(
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Physical32 OpenCL
+ %void = OpTypeVoid
+ %func = OpTypeFunction %void
+ %f32 = OpTypeFloat 32
+ %u32 = OpTypeInt 32 0
+ )";
+}
+
+std::string TrivialMain() {
+ return R"(
+ %main = OpFunction %void None %func
+ %entry = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+}
+
std::string GetShaderHeader(const std::string& capabilities_and_extensions = "",
bool include_entry_point = true) {
std::ostringstream ss;
ss << R"(
OpCapability Shader
OpCapability Int64
+OpCapability Float64
)";
ss << capabilities_and_extensions;
@@ -457,9 +474,11 @@
%func = OpTypeFunction %void
%bool = OpTypeBool
%f32 = OpTypeFloat 32
+%f64 = OpTypeFloat 64
%u32 = OpTypeInt 32 0
%u64 = OpTypeInt 64 0
%s32 = OpTypeInt 32 1
+%s64 = OpTypeInt 64 1
)";
return ss.str();
@@ -481,8 +500,7 @@
TEST_F(ValidateImage, TypeImageVoidSampledTypeVulkan) {
const std::string code = GetShaderHeader() + R"(
%img_type = OpTypeImage %void 2D 0 0 0 1 Unknown
-%void_func = OpTypeFunction %void
-%main = OpFunction %void None %void_func
+%main = OpFunction %void None %func
%main_lab = OpLabel
OpReturn
OpFunctionEnd
@@ -492,15 +510,131 @@
CompileSuccessfully(code, env);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Expected Sampled Type to be a 32-bit int "
- "or float scalar type for Vulkan environment"));
+ AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04656"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Sampled Type to be a 32-bit int, 64-bit int "
+ "or 32-bit float scalar type for Vulkan environment"));
+}
+
+TEST_F(ValidateImage, TypeImageU32SampledTypeVulkan) {
+ const std::string code = GetShaderHeader() + R"(
+%img_type = OpTypeImage %u32 2D 0 0 0 1 Unknown
+%main = OpFunction %void None %func
+%main_lab = OpLabel
+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, TypeImageI32SampledTypeVulkan) {
+ const std::string code = GetShaderHeader() + R"(
+%img_type = OpTypeImage %s32 2D 0 0 0 1 Unknown
+%main = OpFunction %void None %func
+%main_lab = OpLabel
+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, TypeImageI64SampledTypeNoCapabilityVulkan) {
+ const std::string code = GetShaderHeader() + R"(
+%img_type = OpTypeImage %s64 2D 0 0 0 1 Unknown
+%main = OpFunction %void None %func
+%main_lab = OpLabel
+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 Int64ImageEXT is required when using "
+ "Sampled Type of 64-bit int"));
+}
+
+TEST_F(ValidateImage, TypeImageI64SampledTypeVulkan) {
+ const std::string code = GetShaderHeader(
+ "OpCapability Int64ImageEXT\nOpExtension "
+ "\"SPV_EXT_shader_image_int64\"\n") +
+ R"(
+%img_type = OpTypeImage %s64 2D 0 0 0 1 Unknown
+%main = OpFunction %void None %func
+%main_lab = OpLabel
+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, TypeImageU64SampledTypeNoCapabilityVulkan) {
+ const std::string code = GetShaderHeader() + R"(
+%img_type = OpTypeImage %u64 2D 0 0 0 1 Unknown
+%main = OpFunction %void None %func
+%main_lab = OpLabel
+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 Int64ImageEXT is required when using "
+ "Sampled Type of 64-bit int"));
}
TEST_F(ValidateImage, TypeImageU64SampledTypeVulkan) {
- const std::string code = GetShaderHeader() + R"(
+ const std::string code = GetShaderHeader(
+ "OpCapability Int64ImageEXT\nOpExtension "
+ "\"SPV_EXT_shader_image_int64\"\n") +
+ R"(
%img_type = OpTypeImage %u64 2D 0 0 0 1 Unknown
-%void_func = OpTypeFunction %void
-%main = OpFunction %void None %void_func
+%main = OpFunction %void None %func
+%main_lab = OpLabel
+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, TypeImageF32SampledTypeVulkan) {
+ const std::string code = GetShaderHeader() + R"(
+%img_type = OpTypeImage %f32 2D 0 0 0 1 Unknown
+%main = OpFunction %void None %func
+%main_lab = OpLabel
+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, TypeImageF64SampledTypeVulkan) {
+ const std::string code = GetShaderHeader() + R"(
+%img_type = OpTypeImage %f64 2D 0 0 0 1 Unknown
+%main = OpFunction %void None %func
%main_lab = OpLabel
OpReturn
OpFunctionEnd
@@ -510,8 +644,32 @@
CompileSuccessfully(code, env);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Expected Sampled Type to be a 32-bit int "
- "or float scalar type for Vulkan environment"));
+ AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04656"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Sampled Type to be a 32-bit int, 64-bit int "
+ "or 32-bit float scalar type for Vulkan environment"));
+}
+
+TEST_F(ValidateImage, TypeImageF64SampledTypeWithInt64Vulkan) {
+ const std::string code = GetShaderHeader(
+ "OpCapability Int64ImageEXT\nOpExtension "
+ "\"SPV_EXT_shader_image_int64\"\n") +
+ R"(
+%img_type = OpTypeImage %f64 2D 0 0 0 1 Unknown
+%main = OpFunction %void None %func
+%main_lab = OpLabel
+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(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04656"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Sampled Type to be a 32-bit int, 64-bit int "
+ "or 32-bit float scalar type for Vulkan environment"));
}
TEST_F(ValidateImage, TypeImageWrongDepth) {
@@ -571,6 +729,83 @@
HasSubstr("Dim SubpassData requires Sampled to be 2"));
}
+TEST_F(ValidateImage, TypeImage_OpenCL_Sampled0_OK) {
+ const std::string code = GetKernelHeader() + R"(
+%img_type = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
+)";
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_1));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateImage, TypeImage_OpenCL_Sampled1_Invalid) {
+ const std::string code = GetKernelHeader() + R"(
+%img_type = OpTypeImage %void 2D 0 0 0 1 Unknown ReadOnly
+)";
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_2_1));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Sampled must be 0 in the OpenCL environment."));
+}
+
+TEST_F(ValidateImage, TypeImage_OpenCL_Sampled2_Invalid) {
+ const std::string code = GetKernelHeader() + R"(
+%img_type = OpTypeImage %void 2D 0 0 0 2 Unknown ReadOnly
+)";
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_2_1));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Sampled must be 0 in the OpenCL environment."));
+}
+
+TEST_F(ValidateImage, TypeImage_OpenCL_AccessQualifierMissing) {
+ const std::string code = GetKernelHeader() + R"(
+%img_type = OpTypeImage %void 2D 0 0 0 0 Unknown
+)";
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_2_1));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("In the OpenCL environment, the optional Access "
+ "Qualifier must be present"));
+}
+
+TEST_F(ValidateImage, TypeImage_Vulkan_Sampled1_OK) {
+ const std::string code = GetShaderHeader() + R"(
+%img_type = OpTypeImage %f32 2D 0 0 0 1 Unknown
+)" + TrivialMain();
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateImage, TypeImage_Vulkan_Sampled2_OK) {
+ const std::string code = GetShaderHeader() + R"(
+%img_type = OpTypeImage %f32 2D 0 0 0 2 Rgba32f
+)" + TrivialMain();
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateImage, TypeImage_Vulkan_Sampled0_Invalid) {
+ const std::string code = GetShaderHeader() + R"(
+%img_type = OpTypeImage %f32 2D 0 0 0 0 Unknown
+)" + TrivialMain();
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04657"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Sampled must be 1 or 2 in the Vulkan environment."));
+}
+
TEST_F(ValidateImage, TypeImageWrongFormatForSubpassData) {
const std::string code =
GetShaderHeader("OpCapability InputAttachment\n", false) +
@@ -584,7 +819,44 @@
HasSubstr("Dim SubpassData requires format Unknown"));
}
-TEST_F(ValidateImage, TypeSampledImageNotImage) {
+TEST_F(ValidateImage, TypeImageMultisampleStorageImage_MissingCapability) {
+ const std::string code = GetShaderHeader("", false) +
+ R"(
+%img_type = OpTypeImage %f32 2D 0 0 1 2 Rgba32f
+)";
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()) << code;
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Capability StorageImageMultisample is required when "
+ "using multisampled storage image"));
+}
+
+TEST_F(ValidateImage, TypeImageMultisampleStorageImage_UsesCapability) {
+ const std::string code =
+ GetShaderHeader("OpCapability StorageImageMultisample\n", false) +
+ R"(
+%img_type = OpTypeImage %f32 2D 0 0 1 2 Rgba32f
+)";
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << code;
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateImage, TypeImageMultisampleSubpassData_OK) {
+ const std::string code =
+ GetShaderHeader("OpCapability InputAttachment\n", false) +
+ R"(
+%img_type = OpTypeImage %f32 SubpassData 0 0 1 2 Unknown
+)";
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << code;
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateImage, TypeSampledImage_NotImage_Error) {
const std::string code = GetShaderHeader("", false) + R"(
%simg_type = OpTypeSampledImage %f32
)";
@@ -595,6 +867,43 @@
HasSubstr("Expected Image to be of type OpTypeImage"));
}
+TEST_F(ValidateImage, TypeSampledImage_Sampled0_Success) {
+ // This is ok in the OpenCL and universal environments.
+ // Vulkan will reject an OpTypeImage with Sampled=0, checked elsewhere.
+ const std::string code = GetShaderHeader() + R"(
+%imty = OpTypeImage %f32 2D 0 0 0 0 Unknown
+%simg_type = OpTypeSampledImage %imty
+)" + TrivialMain();
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+ EXPECT_EQ(getDiagnosticString(), "");
+}
+
+TEST_F(ValidateImage, TypeSampledImage_Sampled2_Error) {
+ const std::string code = GetShaderHeader() + R"(
+%storage_image = OpTypeImage %f32 2D 0 0 0 2 Rgba32f
+%simg_type = OpTypeSampledImage %storage_image
+)" + TrivialMain();
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Sampled image type requires an image type with "
+ "\"Sampled\" operand set to 0 or 1"));
+}
+
+TEST_F(ValidateImage, TypeSampledImage_Sampled1_Success) {
+ const std::string code = GetShaderHeader() + R"(
+%im = OpTypeImage %f32 2D 0 0 0 1 Unknown
+%simg_type = OpTypeSampledImage %im
+)" + TrivialMain();
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+ EXPECT_EQ(getDiagnosticString(), "");
+}
+
TEST_F(ValidateImage, SampledImageSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -646,31 +955,32 @@
}
TEST_F(ValidateImage, SampledImageImageNotForSampling) {
- const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
-%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_2d_0002 %img %sampler
+ const std::string code = GetShaderHeader() + R"(
+%im_ty = OpTypeImage %f32 2D 0 0 0 2 Unknown
+%sampler_ty = OpTypeSampler
+%sampled_image_ty = OpTypeSampledImage %im_ty ; will fail here first!
+
+%ptr_im_ty = OpTypePointer UniformConstant %im_ty
+%var_im = OpVariable %ptr_im_ty UniformConstant
+
+%ptr_sampler_ty = OpTypePointer UniformConstant %sampler_ty
+%var_sampler = OpVariable %ptr_sampler_ty UniformConstant
+
+%main = OpFunction %void None %func
+%entry = OpLabel
+%im = OpLoad %im_ty %var_im
+%sampler = OpLoad %sampler_ty %var_sampler
+%sampled_image = OpSampledImage %sampled_image_ty %im %sampler
+OpReturn
+OpFunctionEnd
)";
- CompileSuccessfully(GenerateShaderCode(body).c_str());
+ CompileSuccessfully(code.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Expected Image 'Sampled' parameter to be 0 or 1"));
-}
-
-TEST_F(ValidateImage, SampledImageVulkanUnknownSampled) {
- const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_u32_2d_0000 %img %sampler
-)";
-
- const spv_target_env env = SPV_ENV_VULKAN_1_0;
- CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env), env);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Expected Image 'Sampled' parameter to "
- "be 1 for Vulkan environment."));
+ HasSubstr("Sampled image type requires an image type with "
+ "\"Sampled\" operand set to 0 or 1"))
+ << code;
}
TEST_F(ValidateImage, SampledImageNotSampler) {
@@ -743,7 +1053,7 @@
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 141[%141] cannot be a "
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 136[%136] cannot be a "
"type"));
}
@@ -801,7 +1111,7 @@
TEST_F(ValidateImage, ImageTexelPointerImageCoordSizeBad) {
const std::string body = R"(
-%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_u32_2d_0000 %u32vec3_012 %u32_0
+%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_u32_2d_0002 %u32vec3_012 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
@@ -902,6 +1212,20 @@
HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage"));
}
+TEST_F(ValidateImage, SampleImplicitLodMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec2_hh Sample %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Sampling operation is invalid for multisample image"));
+}
+
TEST_F(ValidateImage, SampleImplicitLodWrongSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -1050,6 +1374,20 @@
HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage"));
}
+TEST_F(ValidateImage, SampleExplicitLodMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh Lod|Sample %f32_0 %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Sampling operation is invalid for multisample image"));
+}
+
TEST_F(ValidateImage, SampleExplicitLodWrongSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -1182,19 +1520,6 @@
"2D, 3D or Cube"));
}
-TEST_F(ValidateImage, LodMultisampled) {
- const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
-%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_2d_0010 %img %sampler
-%res1 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec2_00 Lod %f32_0)";
-
- CompileSuccessfully(GenerateShaderCode(body).c_str());
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Image Operand Lod requires 'MS' parameter to be 0"));
-}
-
TEST_F(ValidateImage, MinLodIncompatible) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -1227,20 +1552,6 @@
"Image Operand Grad can only be used with ExplicitLod opcodes"));
}
-TEST_F(ValidateImage, SampleImplicitLod3DArrayedMultisampledSuccess) {
- const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
-%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
-%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000
-%res2 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset %s32vec3_012
-%res3 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %s32vec3_012
-)";
-
- CompileSuccessfully(GenerateShaderCode(body).c_str());
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
-}
-
TEST_F(ValidateImage, SampleImplicitLodCubeArrayedSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101
@@ -1285,20 +1596,6 @@
"2D, 3D or Cube"));
}
-TEST_F(ValidateImage, SampleImplicitLodBiasMultisampled) {
- const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
-%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
-%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Bias %f32_0_25
-)";
-
- CompileSuccessfully(GenerateShaderCode(body).c_str());
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Image Operand Bias requires 'MS' parameter to be 0"));
-}
-
TEST_F(ValidateImage, SampleExplicitLodGradDxWrongType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101
@@ -1361,20 +1658,6 @@
"Expected Image Operand Grad dy to have 3 components, but given 2"));
}
-TEST_F(ValidateImage, SampleExplicitLodGradMultisampled) {
- const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
-%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
-%res1 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec4_0000 Grad %f32vec3_000 %f32vec3_000
-)";
-
- CompileSuccessfully(GenerateShaderCode(body).c_str());
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Image Operand Grad requires 'MS' parameter to be 0"));
-}
-
TEST_F(ValidateImage, SampleImplicitLodConstOffsetCubeDim) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101
@@ -1393,10 +1676,10 @@
TEST_F(ValidateImage, SampleImplicitLodConstOffsetWrongType) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
+%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
-%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset %f32vec3_000
+%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
+%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_00 ConstOffset %f32vec2_00
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -1409,26 +1692,26 @@
TEST_F(ValidateImage, SampleImplicitLodConstOffsetWrongSize) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
+%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
-%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset %s32vec2_01
+%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
+%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_00 ConstOffset %s32vec3_012
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Expected Image Operand ConstOffset to have 3 "
- "components, but given 2"));
+ HasSubstr("Expected Image Operand ConstOffset to have 2 "
+ "components, but given 3"));
}
TEST_F(ValidateImage, SampleImplicitLodConstOffsetNotConst) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
+%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%offset = OpSNegate %s32vec3 %s32vec3_012
-%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset %offset
+%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_00 ConstOffset %offset
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -1455,10 +1738,10 @@
TEST_F(ValidateImage, SampleImplicitLodOffsetWrongType) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
+%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
-%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %f32vec3_000
+%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
+%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %f32vec2_00
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -1470,10 +1753,10 @@
TEST_F(ValidateImage, SampleImplicitLodOffsetWrongSize) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
+%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
-%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %s32vec2_01
+%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
+%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %s32vec3_012
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -1481,15 +1764,15 @@
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
- "Expected Image Operand Offset to have 3 components, but given 2"));
+ "Expected Image Operand Offset to have 2 components, but given 3"));
}
TEST_F(ValidateImage, SampleImplicitLodMoreThanOneOffset) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
+%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
-%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset|Offset %s32vec3_012 %s32vec3_012
+%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
+%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset|Offset %s32vec2_01 %s32vec2_01
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -1528,21 +1811,6 @@
"1D, 2D, 3D or Cube"));
}
-TEST_F(ValidateImage, SampleImplicitLodMinLodMultisampled) {
- const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111
-%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler
-%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 MinLod %f32_0_25
-)";
-
- CompileSuccessfully(GenerateShaderCode(body).c_str());
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Image Operand MinLod requires 'MS' parameter to be 0"));
-}
-
TEST_F(ValidateImage, SampleProjExplicitLodSuccess2D) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -1620,6 +1888,20 @@
HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage"));
}
+TEST_F(ValidateImage, SampleProjExplicitLodMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageSampleProjExplicitLod %f32vec4 %simg %f32vec2_hh Lod|Sample %f32_1 %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Image 'MS' parameter to be 0"));
+}
+
TEST_F(ValidateImage, SampleProjExplicitLodWrongSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -1741,6 +2023,20 @@
HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage"));
}
+TEST_F(ValidateImage, SampleProjImplicitLodMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageSampleProjImplicitLod %f32vec4 %simg %f32vec2_hh Sample %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Image 'MS' parameter to be 0"));
+}
+
TEST_F(ValidateImage, SampleProjImplicitLodWrongSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -1848,6 +2144,21 @@
HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage"));
}
+TEST_F(ValidateImage, SampleDrefImplicitLodMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageSampleDrefImplicitLod %f32 %simg %f32vec2_hh %f32_1 Sample %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Dref sampling operation is invalid for multisample image"));
+}
+
TEST_F(ValidateImage, SampleDrefImplicitLodWrongSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0001 %uniform_image_u32_2d_0001
@@ -1971,6 +2282,21 @@
HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage"));
}
+TEST_F(ValidateImage, SampleDrefExplicitLodMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageSampleDrefExplicitLod %f32 %simg %f32vec2_hh %f32_1 Lod|Sample %f32_1 %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Dref sampling operation is invalid for multisample image"));
+}
+
TEST_F(ValidateImage, SampleDrefExplicitLodWrongSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_s32_3d_0001 %uniform_image_s32_3d_0001
@@ -2095,6 +2421,21 @@
HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage"));
}
+TEST_F(ValidateImage, SampleProjDrefImplicitLodMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageSampleDrefExplicitLod %f32 %simg %f32vec2_hh %f32_1 Sample %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Dref sampling operation is invalid for multisample image"));
+}
+
TEST_F(ValidateImage, SampleProjDrefImplicitLodWrongSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -2218,6 +2559,21 @@
HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage"));
}
+TEST_F(ValidateImage, SampleProjDrefExplicitLodMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageSampleDrefExplicitLod %f32 %simg %f32vec2_hh %f32_1 Lod|Sample %f32_1 %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Dref sampling operation is invalid for multisample image"));
+}
+
TEST_F(ValidateImage, SampleProjDrefExplicitLodWrongSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_1d_0001 %uniform_image_f32_1d_0001
@@ -2294,6 +2650,23 @@
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
+TEST_F(ValidateImage, FetchMultisampledSuccess) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%res1 = OpImageFetch %f32vec4 %img %u32vec2_01 Sample %u32_1
+%res2 = OpImageFetch %f32vec4 %img %u32vec2_01 Sample|NonPrivateTexelKHR %u32_1
+)";
+
+ const std::string extra = R"(
+OpCapability VulkanMemoryModelKHR
+OpExtension "SPV_KHR_vulkan_memory_model"
+)";
+ CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "",
+ SPV_ENV_UNIVERSAL_1_3, "VulkanKHR")
+ .c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+}
+
TEST_F(ValidateImage, FetchWrongResultType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
@@ -2349,7 +2722,7 @@
TEST_F(ValidateImage, FetchNotSampled) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageFetch %u32vec4 %img %u32vec2_01
)";
@@ -2433,6 +2806,21 @@
"with OpImageFetch"));
}
+TEST_F(ValidateImage, FetchMultisampledMissingSample) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%res1 = OpImageFetch %f32vec4 %img %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions())
+ << GenerateShaderCode(body);
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Image Operand Sample is required for operation on "
+ "multi-sampled image"))
+ << getDiagnosticString();
+}
+
TEST_F(ValidateImage, GatherSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -2494,6 +2882,20 @@
HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage"));
}
+TEST_F(ValidateImage, GatherMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageGather %f32vec4 %simg %f32vec4_0000 %u32_1 Sample %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Gather operation is invalid for multisample image"));
+}
+
TEST_F(ValidateImage, GatherWrongSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101
@@ -2709,6 +3111,20 @@
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
+TEST_F(ValidateImage, DrefGatherMultisampleError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
+%res1 = OpImageDrefGather %f32vec4 %simg %f32vec4_0000 %f32_1 Sample %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Gather operation is invalid for multisample image"));
+}
+
TEST_F(ValidateImage, DrefGatherVoidSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_void_2d_0001 %uniform_image_void_2d_0001
@@ -2740,7 +3156,7 @@
TEST_F(ValidateImage, ReadSuccess1) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01
)";
@@ -2783,7 +3199,7 @@
TEST_F(ValidateImage, ReadNeedCapabilityStorageImageReadWithoutFormat) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01
)";
@@ -2793,7 +3209,7 @@
TEST_F(ValidateImage, ReadNeedCapabilityStorageImageReadWithoutFormatVulkan) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01
)";
@@ -2836,7 +3252,7 @@
// TODO(atgoo@github.com) Disabled until the spec is clarified.
TEST_F(ValidateImage, DISABLED_ReadWrongResultType) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %f32 %img %u32vec2_01
)";
@@ -2847,16 +3263,41 @@
HasSubstr("Expected Result Type to be int or float vector type"));
}
-// TODO(atgoo@github.com) Disabled until the spec is clarified.
-TEST_F(ValidateImage, DISABLED_ReadWrongNumComponentsResultType) {
+TEST_F(ValidateImage, ReadScalarResultType_Universal) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageRead %f32vec3 %img %u32vec2_01
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
+%res1 = OpImageRead %u32 %img %u32vec2_01
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateImage, ReadUnusualNumComponentsResultType_Universal) {
+ const std::string body = R"(
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
+%res1 = OpImageRead %u32vec3 %img %u32vec2_01
+)";
+
+ const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
+ CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateImage, ReadWrongNumComponentsResultType_Vulkan) {
+ const std::string body = R"(
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
+%res1 = OpImageRead %u32vec3 %img %u32vec2_01
+)";
+
+ const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
+ CompileSuccessfully(
+ GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_VULKAN_1_0)
+ .c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type to have 4 components"));
}
@@ -2889,7 +3330,7 @@
TEST_F(ValidateImage, ReadWrongSampledType) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %f32vec4 %img %u32vec2_01
)";
@@ -2916,7 +3357,7 @@
TEST_F(ValidateImage, ReadWrongCoordinateType) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %f32vec2_00
)";
@@ -2929,7 +3370,7 @@
TEST_F(ValidateImage, ReadCoordinateSizeTooSmall) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32_1
)";
@@ -2943,7 +3384,7 @@
TEST_F(ValidateImage, WriteSuccess1) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %u32vec4_0123
)";
@@ -2976,14 +3417,24 @@
TEST_F(ValidateImage, WriteSuccess4) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
-;TODO(atgoo@github.com) Is it legal to write to MS image without sample index?
-OpImageWrite %img %u32vec2_01 %f32vec4_0000
+%img = OpLoad %type_image_f32_2d_0012 %uniform_image_f32_2d_0012
OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1
)";
- const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
- CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
+ const std::string extra = R"(
+ OpCapability StorageImageWriteWithoutFormat
+ OpCapability StorageImageMultisample
+ )";
+
+ const std::string declarations = R"(
+%type_image_f32_2d_0012 = OpTypeImage %f32 2D 0 0 1 2 Unknown
+%ptr_image_f32_2d_0012 = OpTypePointer UniformConstant %type_image_f32_2d_0012
+%uniform_image_f32_2d_0012 = OpVariable %ptr_image_f32_2d_0012 UniformConstant
+ )";
+ CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "",
+ SPV_ENV_UNIVERSAL_1_0, "GLSL450",
+ declarations)
+ .c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
@@ -3001,7 +3452,7 @@
TEST_F(ValidateImage, WriteNeedCapabilityStorageImageWriteWithoutFormat) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %u32vec4_0123
)";
@@ -3011,7 +3462,7 @@
TEST_F(ValidateImage, WriteNeedCapabilityStorageImageWriteWithoutFormatVulkan) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %u32vec4_0123
)";
@@ -3080,7 +3531,7 @@
TEST_F(ValidateImage, WriteWrongCoordinateType) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %f32vec2_00 %u32vec4_0123
)";
@@ -3093,7 +3544,7 @@
TEST_F(ValidateImage, WriteCoordinateSizeTooSmall) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32_1 %u32vec4_0123
)";
@@ -3107,7 +3558,7 @@
TEST_F(ValidateImage, WriteTexelWrongType) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %img
)";
@@ -3120,7 +3571,7 @@
TEST_F(ValidateImage, DISABLED_WriteTexelNotVector4) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %u32vec3_012
)";
@@ -3133,7 +3584,7 @@
TEST_F(ValidateImage, WriteTexelWrongComponentType) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %f32vec4_0000
)";
@@ -3148,18 +3599,29 @@
TEST_F(ValidateImage, WriteSampleNotInteger) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
+%img = OpLoad %type_image_f32_2d_0012 %uniform_image_f32_2d_0012
OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %f32_1
)";
- const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
- CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
+ const std::string extra = R"(
+ OpCapability StorageImageWriteWithoutFormat
+ OpCapability StorageImageMultisample
+ )";
+ const std::string declarations = R"(
+%type_image_f32_2d_0012 = OpTypeImage %f32 2D 0 0 1 2 Unknown
+%ptr_image_f32_2d_0012 = OpTypePointer UniformConstant %type_image_f32_2d_0012
+%uniform_image_f32_2d_0012 = OpVariable %ptr_image_f32_2d_0012 UniformConstant
+ )";
+ CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "",
+ SPV_ENV_UNIVERSAL_1_0, "GLSL450",
+ declarations)
+ .c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Image Operand Sample to be int scalar"));
}
-TEST_F(ValidateImage, SampleNotMultisampled) {
+TEST_F(ValidateImage, WriteSampleNotMultisampled) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1
@@ -3175,18 +3637,16 @@
TEST_F(ValidateImage, SampleWrongOpcode) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
%sampler = OpLoad %type_sampler %uniform_sampler
-%simg = OpSampledImage %type_sampled_image_f32_2d_0010 %img %sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler
%res1 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec2_00 Sample %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Image Operand Sample can only be used with "
- "OpImageFetch, OpImageRead, OpImageWrite, "
- "OpImageSparseFetch and OpImageSparseRead"));
+ HasSubstr("Sampling operation is invalid for multisample image"));
}
TEST_F(ValidateImage, SampleImageToImageSuccess) {
@@ -3379,6 +3839,67 @@
"for OpImageQuerySizeLod"));
}
+TEST_F(ValidateImage, QuerySizeLodMultisampledError) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
+%res1 = OpImageQuerySizeLod %u32vec2 %img %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Image 'MS' must be 0"));
+}
+
+TEST_F(ValidateImage, QuerySizeLodNonSampledUniversalSuccess) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
+%res1 = OpImageQuerySizeLod %u32vec2 %img %u32_1
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+ EXPECT_EQ(getDiagnosticString(), "");
+}
+
+TEST_F(ValidateImage, QuerySizeLodVulkanNonSampledError) {
+ // Create a whole shader module. Avoid Vulkan incompatibility with
+ // SampledRrect images inserted by helper function GenerateShaderCode.
+ const std::string body = R"(
+OpCapability Shader
+OpCapability ImageQuery
+OpMemoryModel Logical Simple
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+
+%f32 = OpTypeFloat 32
+%u32 = OpTypeInt 32 0
+%u32_0 = OpConstant %u32 0
+%u32vec2 = OpTypeVector %u32 2
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+
+; Test with a storage image.
+%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Rgba32f
+%ptr_image_f32_2d_0002 = OpTypePointer UniformConstant %type_image_f32_2d_0002
+%uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant
+
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
+%res1 = OpImageQuerySizeLod %u32vec2 %img %u32_0
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpImageQuerySizeLod must only consume an \"Image\" operand whose "
+ "type has its \"Sampled\" operand set to 1"));
+}
+
TEST_F(ValidateImage, QuerySizeLodWrongImageDim) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
@@ -3391,17 +3912,6 @@
HasSubstr("Image 'Dim' must be 1D, 2D, 3D or Cube"));
}
-TEST_F(ValidateImage, QuerySizeLodMultisampled) {
- const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
-%res1 = OpImageQuerySizeLod %u32vec2 %img %u32_1
-)";
-
- CompileSuccessfully(GenerateKernelCode(body).c_str());
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(), HasSubstr("Image 'MS' must be 0"));
-}
-
TEST_F(ValidateImage, QuerySizeLodWrongLodType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -3416,7 +3926,7 @@
TEST_F(ValidateImage, QuerySizeSuccess) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
%res1 = OpImageQuerySize %u32vec2 %img
)";
@@ -3426,7 +3936,7 @@
TEST_F(ValidateImage, QuerySizeWrongResultType) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
%res1 = OpImageQuerySize %f32vec2 %img
)";
@@ -3439,7 +3949,7 @@
TEST_F(ValidateImage, QuerySizeNotImage) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageQuerySize %u32vec2 %sampler
@@ -3453,7 +3963,7 @@
TEST_F(ValidateImage, QuerySizeSampledImageDirectly) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageQuerySize %u32vec2 %simg
@@ -3676,9 +4186,56 @@
HasSubstr("Image 'Dim' must be 1D, 2D, 3D or Cube"));
}
+TEST_F(ValidateImage, QuerySizeLevelsNonSampledUniversalSuccess) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
+%res1 = OpImageQueryLevels %u32 %img
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body).c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+ EXPECT_EQ(getDiagnosticString(), "");
+}
+
+TEST_F(ValidateImage, QuerySizeLevelsVulkanNonSampledError) {
+ // Create a whole shader module. Avoid Vulkan incompatibility with
+ // SampledRrect images inserted by helper function GenerateShaderCode.
+ const std::string body = R"(
+OpCapability Shader
+OpCapability ImageQuery
+OpMemoryModel Logical Simple
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+
+%f32 = OpTypeFloat 32
+%u32 = OpTypeInt 32 0
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+
+; Test with a storage image.
+%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Rgba32f
+%ptr_image_f32_2d_0002 = OpTypePointer UniformConstant %type_image_f32_2d_0002
+%uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant
+
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
+%res1 = OpImageQueryLevels %u32 %img
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpImageQueryLevels must only consume an \"Image\" operand "
+ "whose type has its \"Sampled\" operand set to 1"));
+}
+
TEST_F(ValidateImage, QuerySamplesSuccess) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
+%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011
%res1 = OpImageQuerySamples %u32 %img
)";
@@ -3688,7 +4245,7 @@
TEST_F(ValidateImage, QuerySamplesNot2D) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_3d_0010 %uniform_image_f32_3d_0010
+%img = OpLoad %type_image_f32_3d_0011 %uniform_image_f32_3d_0011
%res1 = OpImageQuerySamples %u32 %img
)";
@@ -3766,6 +4323,100 @@
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
+TEST_F(ValidateImage, QueryLodUniversalSuccess) {
+ // Create a whole shader module. Avoid Vulkan incompatibility with
+ // SampledRrect images inserted by helper function GenerateShaderCode.
+ const std::string body = R"(
+OpCapability Shader
+OpCapability ImageQuery
+OpMemoryModel Logical Simple
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+
+OpDecorate %uniform_image_f32_2d_0000 DescriptorSet 0
+OpDecorate %uniform_image_f32_2d_0000 Binding 0
+OpDecorate %sampler DescriptorSet 0
+OpDecorate %sampler Binding 1
+
+%f32 = OpTypeFloat 32
+%f32vec2 = OpTypeVector %f32 2
+%f32vec2_null = OpConstantNull %f32vec2
+%u32 = OpTypeInt 32 0
+%u32vec2 = OpTypeVector %u32 2
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+
+; Test with an image with sampled = 0
+%type_image_f32_2d_0000 = OpTypeImage %f32 2D 0 0 0 0 Rgba32f
+%ptr_image_f32_2d_0000 = OpTypePointer UniformConstant %type_image_f32_2d_0000
+%uniform_image_f32_2d_0000 = OpVariable %ptr_image_f32_2d_0000 UniformConstant
+%sampled_image_ty = OpTypeSampledImage %type_image_f32_2d_0000
+
+%sampler_ty = OpTypeSampler
+%ptr_sampler_ty = OpTypePointer UniformConstant %sampler_ty
+%sampler = OpVariable %ptr_sampler_ty UniformConstant
+
+
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%img = OpLoad %type_image_f32_2d_0000 %uniform_image_f32_2d_0000
+%s = OpLoad %sampler_ty %sampler
+%simg = OpSampledImage %sampled_image_ty %img %s
+%res1 = OpImageQueryLod %f32vec2 %simg %f32vec2_null
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateImage, QueryLodVulkanNonSampledError) {
+ // Create a whole shader module. Avoid Vulkan incompatibility with
+ // SampledRrect images inserted by helper function GenerateShaderCode.
+ const std::string body = R"(
+OpCapability Shader
+OpCapability ImageQuery
+OpMemoryModel Logical Simple
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+
+OpDecorate %sampled_image DescriptorSet 0
+OpDecorate %sampled_image Binding 0
+
+%f32 = OpTypeFloat 32
+%f32vec2 = OpTypeVector %f32 2
+%f32vec2_null = OpConstantNull %f32vec2
+%u32 = OpTypeInt 32 0
+%u32vec2 = OpTypeVector %u32 2
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+
+; Test with an image with Sampled = 2
+; In Vulkan it Sampled must be 1 or 2, checked in another part of the
+; validation flow.
+%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Rgba32f
+
+; Expect to fail here.
+%sampled_image_ty = OpTypeSampledImage %type_image_f32_2d_0002
+%ptr_sampled_image_ty = OpTypePointer UniformConstant %sampled_image_ty
+%sampled_image = OpVariable %ptr_sampled_image_ty UniformConstant
+
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%simg = OpLoad %sampled_image_ty %sampled_image
+%res1 = OpImageQueryLod %f32vec2 %simg %f32vec2_null
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Sampled image type requires an image type with "
+ "\"Sampled\" operand set to 0 or 1"));
+}
+
TEST_F(ValidateImage, QueryLodComputeShaderDerivativesMissingMode) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
@@ -4453,7 +5104,7 @@
TEST_F(ValidateImage, MakeTexelVisibleKHRSuccessImageRead) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_2
)";
@@ -4511,7 +5162,7 @@
TEST_F(ValidateImage, MakeTexelVisibleKHRFailureMissingNonPrivate) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR %u32_1
)";
@@ -4532,7 +5183,7 @@
TEST_F(ValidateImage, MakeTexelAvailableKHRSuccessImageWrite) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_2
)";
@@ -4572,7 +5223,7 @@
TEST_F(ValidateImage, MakeTexelAvailableKHRFailureMissingNonPrivate) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR %u32_1
)";
@@ -4593,7 +5244,7 @@
TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageWriteBad) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1
)";
@@ -4615,7 +5266,7 @@
TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageWriteGood) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1
)";
@@ -4633,7 +5284,7 @@
TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageReadBad) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_1
)";
@@ -4655,7 +5306,7 @@
TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageReadGood) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_1
)";
@@ -4708,7 +5359,7 @@
TEST_F(ValidateImage, SignExtendV13Bad) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 SignExtend
)";
@@ -4719,7 +5370,7 @@
TEST_F(ValidateImage, ZeroExtendV13Bad) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 ZeroExtend
)";
@@ -4731,7 +5382,7 @@
TEST_F(ValidateImage, SignExtendScalarUIntTexelV14Good) {
// Unsigned int sampled type
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32 %img %u32vec2_01 SignExtend
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
@@ -4760,7 +5411,7 @@
TEST_F(ValidateImage, SignExtendScalarVectorUIntTexelV14Good) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 SignExtend
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
@@ -4792,7 +5443,7 @@
TEST_F(ValidateImage, ZeroExtendScalarUIntTexelV14Good) {
// Unsigned int sampled type
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32 %img %u32vec2_01 ZeroExtend
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
@@ -4821,7 +5472,7 @@
TEST_F(ValidateImage, ZeroExtendScalarVectorUIntTexelV14Good) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 ZeroExtend
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
@@ -4849,7 +5500,7 @@
TEST_F(ValidateImage, ReadLodAMDSuccess1) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 Lod %u32_0
)";
@@ -4914,7 +5565,7 @@
TEST_F(ValidateImage, WriteLodAMDSuccess1) {
const std::string body = R"(
-%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
+%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
OpImageWrite %img %u32vec2_01 %u32vec4_0123 Lod %u32_0
)";
@@ -5088,6 +5739,12 @@
%ptr_image_u64_buffer_0002_r64ui = OpTypePointer Private %type_image_u64_buffer_0002_r64ui
%private_image_u64_buffer_0002_r64ui = OpVariable %ptr_image_u64_buffer_0002_r64ui Private
)";
+static const std::string declarations_image64i = R"(
+%type_image_s64_buffer_0002_r64i = OpTypeImage %s64 Buffer 0 0 0 2 R64i
+%ptr_Image_s64 = OpTypePointer Image %s64
+%ptr_image_s64_buffer_0002_r64i = OpTypePointer Private %type_image_s64_buffer_0002_r64i
+%private_image_s64_buffer_0002_r64i = OpVariable %ptr_image_s64_buffer_0002_r64i Private
+)";
TEST_F(ValidateImage, Image64MissingCapability) {
CompileSuccessfully(GenerateShaderCode("", "", "Fragment", "",
@@ -5173,6 +5830,134 @@
"<id> for the value 0"));
}
+TEST_F(ValidateImage, ImageTexelPointerR32uiSuccessVulkan) {
+ const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0
+)";
+
+ spv_target_env env = SPV_ENV_VULKAN_1_0;
+ CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env).c_str(),
+ env);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env));
+}
+
+TEST_F(ValidateImage, ImageTexelPointerR32iSuccessVulkan) {
+ const std::string& declarations = R"(
+%type_image_s32_buffer_0002_r32i = OpTypeImage %s32 Buffer 0 0 0 2 R32i
+%ptr_Image_s32 = OpTypePointer Image %s32
+%ptr_image_s32_buffer_0002_r32i = OpTypePointer Private %type_image_s32_buffer_0002_r32i
+%private_image_s32_buffer_0002_r32i = OpVariable %ptr_image_s32_buffer_0002_r32i Private
+)";
+
+ const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_Image_s32 %private_image_s32_buffer_0002_r32i %u32_0 %u32_0
+)";
+
+ spv_target_env env = SPV_ENV_VULKAN_1_0;
+ CompileSuccessfully(
+ GenerateShaderCode(body, "", "Fragment", "", env, "GLSL450", declarations)
+ .c_str(),
+ env);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env));
+}
+
+TEST_F(ValidateImage, ImageTexelPointerR64uiSuccessVulkan) {
+ const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_Image_u64 %private_image_u64_buffer_0002_r64ui %u32_0 %u32_0
+)";
+
+ spv_target_env env = SPV_ENV_VULKAN_1_0;
+ CompileSuccessfully(
+ GenerateShaderCode(body, capabilities_and_extensions_image64, "Fragment",
+ "", env, "GLSL450", declarations_image64)
+ .c_str(),
+ env);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env));
+}
+
+TEST_F(ValidateImage, ImageTexelPointerR64iSuccessVulkan) {
+ const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_Image_s64 %private_image_s64_buffer_0002_r64i %u32_0 %u32_0
+)";
+
+ spv_target_env env = SPV_ENV_VULKAN_1_0;
+ CompileSuccessfully(
+ GenerateShaderCode(body, capabilities_and_extensions_image64, "Fragment",
+ "", env, "GLSL450", declarations_image64i)
+ .c_str(),
+ env);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env));
+}
+
+TEST_F(ValidateImage, ImageTexelPointerR32fSuccessVulkan) {
+ const std::string& declarations = R"(
+%type_image_f32_buffer_0002_r32f = OpTypeImage %f32 Buffer 0 0 0 2 R32f
+%ptr_image_f32_buffer_0002_r32f = OpTypePointer Private %type_image_f32_buffer_0002_r32f
+%private_image_f32_buffer_0002_r32f = OpVariable %ptr_image_f32_buffer_0002_r32f Private
+)";
+
+ const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_Image_f32 %private_image_f32_buffer_0002_r32f %u32_0 %u32_0
+)";
+
+ spv_target_env env = SPV_ENV_VULKAN_1_0;
+ CompileSuccessfully(
+ GenerateShaderCode(body, "", "Fragment", "", env, "GLSL450", declarations)
+ .c_str(),
+ env);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env));
+}
+
+TEST_F(ValidateImage, ImageTexelPointerRgba32iVulkan) {
+ const std::string& declarations = R"(
+%type_image_s32_buffer_0002_rgba32i = OpTypeImage %s32 Buffer 0 0 0 2 Rgba32i
+%ptr_Image_s32 = OpTypePointer Image %s32
+%ptr_image_s32_buffer_0002_rgba32i = OpTypePointer Private %type_image_s32_buffer_0002_rgba32i
+%private_image_s32_buffer_0002_rgba32i = OpVariable %ptr_image_s32_buffer_0002_rgba32i Private
+)";
+
+ const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_Image_s32 %private_image_s32_buffer_0002_rgba32i %u32_0 %u32_0
+)";
+
+ spv_target_env env = SPV_ENV_VULKAN_1_0;
+ CompileSuccessfully(
+ GenerateShaderCode(body, "", "Fragment", "", env, "GLSL450", declarations)
+ .c_str(),
+ env);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpImageTexelPointer-04658"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected the Image Format in Image to be R64i, R64ui, "
+ "R32f, R32i, or R32ui for Vulkan environment"));
+}
+
+TEST_F(ValidateImage, ImageTexelPointerRgba16fVulkan) {
+ const std::string& declarations = R"(
+%type_image_s32_buffer_0002_rgba16f = OpTypeImage %s32 Buffer 0 0 0 2 Rgba16f
+%ptr_Image_s32 = OpTypePointer Image %s32
+%ptr_image_s32_buffer_0002_rgba16f = OpTypePointer Private %type_image_s32_buffer_0002_rgba16f
+%private_image_s32_buffer_0002_rgba16f = OpVariable %ptr_image_s32_buffer_0002_rgba16f Private
+)";
+
+ const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_Image_s32 %private_image_s32_buffer_0002_rgba16f %u32_0 %u32_0
+)";
+
+ spv_target_env env = SPV_ENV_VULKAN_1_0;
+ CompileSuccessfully(
+ GenerateShaderCode(body, "", "Fragment", "", env, "GLSL450", declarations)
+ .c_str(),
+ env);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpImageTexelPointer-04658"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected the Image Format in Image to be R64i, R64ui, "
+ "R32f, R32i, or R32ui for Vulkan environment"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_layout_test.cpp b/test/val/val_layout_test.cpp
index 43fa046..d34c97f 100644
--- a/test/val/val_layout_test.cpp
+++ b/test/val/val_layout_test.cpp
@@ -667,57 +667,6 @@
HasSubstr("ModuleProcessed cannot appear in a function declaration"));
}
-TEST_F(ValidateLayout, WebGPUCallerBeforeCalleeBad) {
- char str[] = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint GLCompute %main "main"
-%void = OpTypeVoid
-%voidfn = OpTypeFunction %void
-%main = OpFunction %void None %voidfn
-%1 = OpLabel
-%2 = OpFunctionCall %void %callee
- OpReturn
- OpFunctionEnd
-%callee = OpFunction %void None %voidfn
-%3 = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(str, SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, functions need to be defined before being "
- "called.\n %5 = OpFunctionCall %void %6\n"));
-}
-
-TEST_F(ValidateLayout, WebGPUCalleeBeforeCallerGood) {
- char str[] = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint GLCompute %main "main"
-%void = OpTypeVoid
-%voidfn = OpTypeFunction %void
-%callee = OpFunction %void None %voidfn
-%3 = OpLabel
- OpReturn
- OpFunctionEnd
-%main = OpFunction %void None %voidfn
-%1 = OpLabel
-%2 = OpFunctionCall %void %callee
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(str, SPV_ENV_WEBGPU_0);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
// TODO(umar): Test optional instructions
} // namespace
diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp
index e541890..8142f85 100644
--- a/test/val/val_memory_test.cpp
+++ b/test/val/val_memory_test.cpp
@@ -362,192 +362,6 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateMemory, WebGPUInitializerWithOutputStorageClassesGood) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%float = OpTypeFloat 32
-%float_ptr = OpTypePointer Output %float
-%init_val = OpConstant %float 1.0
-%1 = OpVariable %float_ptr Output %init_val
-%void = OpTypeVoid
-%functy = OpTypeFunction %void
-%func = OpFunction %void None %functy
-%2 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateMemory, WebGPUInitializerWithFunctionStorageClassesGood) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%float = OpTypeFloat 32
-%float_ptr = OpTypePointer Function %float
-%init_val = OpConstant %float 1.0
-%void = OpTypeVoid
-%functy = OpTypeFunction %void
-%func = OpFunction %void None %functy
-%1 = OpLabel
-%2 = OpVariable %float_ptr Function %init_val
-OpReturn
-OpFunctionEnd
-)";
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateMemory, WebGPUInitializerWithPrivateStorageClassesGood) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%float = OpTypeFloat 32
-%float_ptr = OpTypePointer Private %float
-%init_val = OpConstant %float 1.0
-%1 = OpVariable %float_ptr Private %init_val
-%void = OpTypeVoid
-%functy = OpTypeFunction %void
-%func = OpFunction %void None %functy
-%2 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateMemory, WebGPUInitializerWithDisallowedStorageClassesBad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%float = OpTypeFloat 32
-%float_ptr = OpTypePointer Uniform %float
-%init_val = OpConstant %float 1.0
-%1 = OpVariable %float_ptr Uniform %init_val
-%void = OpTypeVoid
-%functy = OpTypeFunction %void
-%func = OpFunction %void None %functy
-%2 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("OpVariable, <id> '5[%5]', has a disallowed initializer & "
- "storage class combination.\nFrom WebGPU spec:\nVariable "
- "declarations that include initializers must have one of the "
- "following storage classes: Output, Private, or Function\n %5 "
- "= OpVariable %_ptr_Uniform_float Uniform %float_1\n"));
-}
-
-TEST_F(ValidateMemory, WebGPUOutputStorageClassWithoutInitializerBad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%float = OpTypeFloat 32
-%float_ptr = OpTypePointer Output %float
-%1 = OpVariable %float_ptr Output
-%void = OpTypeVoid
-%functy = OpTypeFunction %void
-%func = OpFunction %void None %functy
-%2 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("OpVariable, <id> '4[%4]', must have an initializer.\n"
- "From WebGPU execution environment spec:\n"
- "All variables in the following storage classes must have an "
- "initializer: Output, Private, or Function\n"
- " %4 = OpVariable %_ptr_Output_float Output\n"));
-}
-
-TEST_F(ValidateMemory, WebGPUFunctionStorageClassWithoutInitializerBad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%float = OpTypeFloat 32
-%float_ptr = OpTypePointer Function %float
-%void = OpTypeVoid
-%functy = OpTypeFunction %void
-%func = OpFunction %void None %functy
-%1 = OpLabel
-%2 = OpVariable %float_ptr Function
-OpReturn
-OpFunctionEnd
-)";
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("OpVariable, <id> '7[%7]', must have an initializer.\n"
- "From WebGPU execution environment spec:\n"
- "All variables in the following storage classes must have an "
- "initializer: Output, Private, or Function\n"
- " %7 = OpVariable %_ptr_Function_float Function\n"));
-}
-
-TEST_F(ValidateMemory, WebGPUPrivateStorageClassWithoutInitializerBad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%float = OpTypeFloat 32
-%float_ptr = OpTypePointer Private %float
-%1 = OpVariable %float_ptr Private
-%void = OpTypeVoid
-%functy = OpTypeFunction %void
-%func = OpFunction %void None %functy
-%2 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("OpVariable, <id> '4[%4]', must have an initializer.\n"
- "From WebGPU execution environment spec:\n"
- "All variables in the following storage classes must have an "
- "initializer: Output, Private, or Function\n"
- " %4 = OpVariable %_ptr_Private_float Private\n"));
-}
-
TEST_F(ValidateMemory, VulkanInitializerWithOutputStorageClassesGood) {
std::string spirv = R"(
OpCapability Shader
@@ -630,6 +444,8 @@
)";
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpVariable-04651"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("OpVariable, <id> '5[%5]', has a disallowed initializer & "
@@ -2280,38 +2096,6 @@
"%_ptr_UniformConstant__runtimearr_2 UniformConstant\n"));
}
-TEST_F(ValidateMemory, WebGPURTAOutsideOfStructBad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%sampler_t = OpTypeSampler
-%array_t = OpTypeRuntimeArray %sampler_t
-%array_ptr = OpTypePointer UniformConstant %array_t
-%2 = OpVariable %array_ptr UniformConstant
-%void = OpTypeVoid
-%func_t = OpTypeFunction %void
-%func = OpFunction %void None %func_t
-%1 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr(
- "OpVariable, <id> '5[%5]', is attempting to create memory for an "
- "illegal type, OpTypeRuntimeArray.\nFor WebGPU OpTypeRuntimeArray "
- "can only appear as the final member of an OpTypeStruct, thus cannot "
- "be instantiated via OpVariable\n %5 = OpVariable "
- "%_ptr_UniformConstant__runtimearr_2 UniformConstant\n"));
-}
-
TEST_F(ValidateMemory, VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayGood) {
std::string spirv = R"(
OpCapability Shader
@@ -2401,34 +2185,6 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
}
-TEST_F(ValidateMemory, WebGPURTAInsideStorageBufferStructGood) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-OpDecorate %array_t ArrayStride 4
-OpMemberDecorate %struct_t 0 Offset 0
-OpDecorate %struct_t Block
-%uint_t = OpTypeInt 32 0
-%array_t = OpTypeRuntimeArray %uint_t
-%struct_t = OpTypeStruct %array_t
-%struct_ptr = OpTypePointer StorageBuffer %struct_t
-%2 = OpVariable %struct_ptr StorageBuffer
-%void = OpTypeVoid
-%func_t = OpTypeFunction %void
-%func = OpFunction %void None %func_t
-%1 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
TEST_F(ValidateMemory, VulkanRTAInsideWrongStorageClassStructBad) {
std::string spirv = R"(
OpCapability Shader
@@ -2458,36 +2214,6 @@
"OpVariable %_ptr_Workgroup__struct_4 Workgroup\n"));
}
-TEST_F(ValidateMemory, WebGPURTAInsideWrongStorageClassStructBad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%uint_t = OpTypeInt 32 0
-%array_t = OpTypeRuntimeArray %uint_t
-%struct_t = OpTypeStruct %array_t
-%struct_ptr = OpTypePointer Workgroup %struct_t
-%2 = OpVariable %struct_ptr Workgroup
-%void = OpTypeVoid
-%func_t = OpTypeFunction %void
-%func = OpFunction %void None %func_t
-%1 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("For WebGPU, OpTypeStruct variables containing "
- "OpTypeRuntimeArray must have storage class of StorageBuffer\n "
- " %6 = OpVariable %_ptr_Workgroup__struct_4 Workgroup\n"));
-}
-
TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructWithoutBlockBad) {
std::string spirv = R"(
OpCapability Shader
@@ -2516,36 +2242,6 @@
"%_ptr_StorageBuffer__struct_4 StorageBuffer\n"));
}
-TEST_F(ValidateMemory, WebGPURTAInsideStorageBufferStructWithoutBlockBad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%uint_t = OpTypeInt 32 0
-%array_t = OpTypeRuntimeArray %uint_t
-%struct_t = OpTypeStruct %array_t
-%struct_ptr = OpTypePointer StorageBuffer %struct_t
-%2 = OpVariable %struct_ptr StorageBuffer
-%void = OpTypeVoid
-%func_t = OpTypeFunction %void
-%func = OpFunction %void None %func_t
-%1 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, an OpTypeStruct variable containing an "
- "OpTypeRuntimeArray must be decorated with Block if it "
- "has storage class StorageBuffer.\n %6 = OpVariable "
- "%_ptr_StorageBuffer__struct_4 StorageBuffer\n"));
-}
-
TEST_F(ValidateMemory, VulkanRTAInsideUniformStructGood) {
std::string spirv = R"(
OpCapability Shader
@@ -2572,39 +2268,6 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
}
-TEST_F(ValidateMemory, WebGPURTAInsideUniformStructBad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-OpDecorate %array_t ArrayStride 4
-OpMemberDecorate %struct_t 0 Offset 0
-OpDecorate %struct_t Block
-%uint_t = OpTypeInt 32 0
-%array_t = OpTypeRuntimeArray %uint_t
-%struct_t = OpTypeStruct %array_t
-%struct_ptr = OpTypePointer Uniform %struct_t
-%2 = OpVariable %struct_ptr Uniform
-%void = OpTypeVoid
-%func_t = OpTypeFunction %void
-%func = OpFunction %void None %func_t
-%1 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("For WebGPU, OpTypeStruct variables containing "
- "OpTypeRuntimeArray must have storage class of StorageBuffer\n "
- " %6 = OpVariable %_ptr_Uniform__struct_3 Uniform\n"));
-}
-
TEST_F(ValidateMemory, VulkanRTAInsideUniformStructWithoutBufferBlockBad) {
std::string spirv = R"(
OpCapability Shader
@@ -2662,37 +2325,6 @@
"OpTypeRuntimeArray %_runtimearr_2\n"));
}
-TEST_F(ValidateMemory, WebGPURTAInsideRTABad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%sampler_t = OpTypeSampler
-%inner_array_t = OpTypeRuntimeArray %sampler_t
-%array_t = OpTypeRuntimeArray %inner_array_t
-%array_ptr = OpTypePointer UniformConstant %array_t
-%2 = OpVariable %array_ptr UniformConstant
-%void = OpTypeVoid
-%func_t = OpTypeFunction %void
-%func = OpFunction %void None %func_t
-%1 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr(
- "OpTypeRuntimeArray Element Type <id> '3[%_runtimearr_2]' is not "
- "valid in WebGPU environments.\n %_runtimearr__runtimearr_2 = "
- "OpTypeRuntimeArray %_runtimearr_2\n"));
-}
-
TEST_F(ValidateMemory, VulkanRTAInsideRTAWithRuntimeDescriptorArrayBad) {
std::string spirv = R"(
OpCapability RuntimeDescriptorArrayEXT
@@ -2853,38 +2485,6 @@
"OpTypeArray %_runtimearr_4 %uint_1\n"));
}
-TEST_F(ValidateMemory, WebGPURTAInsideArrayBad) {
- std::string spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%uint_t = OpTypeInt 32 0
-%dim = OpConstant %uint_t 1
-%sampler_t = OpTypeSampler
-%inner_array_t = OpTypeRuntimeArray %sampler_t
-%array_t = OpTypeArray %inner_array_t %dim
-%array_ptr = OpTypePointer UniformConstant %array_t
-%2 = OpVariable %array_ptr UniformConstant
-%void = OpTypeVoid
-%func_t = OpTypeFunction %void
-%func = OpFunction %void None %func_t
-%1 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("OpTypeArray Element Type <id> '5[%_runtimearr_4]' is not "
- "valid in WebGPU environments.\n %_arr__runtimearr_4_uint_1 = "
- "OpTypeArray %_runtimearr_4 %uint_1\n"));
-}
-
TEST_F(ValidateMemory, VulkanRTAInsideArrayWithRuntimeDescriptorArrayBad) {
std::string spirv = R"(
OpCapability RuntimeDescriptorArrayEXT
diff --git a/test/val/val_misc_test.cpp b/test/val/val_misc_test.cpp
index 9395484..499b5b2 100644
--- a/test/val/val_misc_test.cpp
+++ b/test/val/val_misc_test.cpp
@@ -226,6 +226,53 @@
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Scope must be Subgroup or Device"));
}
+
+TEST_F(ValidateMisc, VulkanShaderClockWorkgroupScope) {
+ const std::string spirv = ShaderClockSpriv + R"(
+%3 = OpTypeFunction %void
+%ulong = OpTypeInt 64 0
+%uint = OpTypeInt 32 0
+%_ptr_Function_ulong = OpTypePointer Function %ulong
+%workgroup = OpConstant %uint 2
+%uint_1 = OpConstant %uint 1
+%main = OpFunction %void None %3
+%5 = OpLabel
+%time1 = OpVariable %_ptr_Function_ulong Function
+%11 = OpReadClockKHR %ulong %workgroup
+OpStore %time1 %11
+OpReturn
+OpFunctionEnd)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpReadClockKHR-04652"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Scope must be Subgroup or Device"));
+}
+
+TEST_F(ValidateMisc, UndefVoid) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ %2 = OpTypeVoid
+ %10 = OpUndef %2
+ %3 = OpTypeFunction %2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Cannot create undefined values with void type"));
+}
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp
index 0a1476e..7b23159 100644
--- a/test/val/val_modes_test.cpp
+++ b/test/val/val_modes_test.cpp
@@ -111,6 +111,8 @@
CompileSuccessfully(spirv, env);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OriginLowerLeft-04653"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("In the Vulkan environment, the OriginLowerLeft "
"execution mode must not be used."));
}
@@ -128,6 +130,8 @@
CompileSuccessfully(spirv, env);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PixelCenterInteger-04654"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("In the Vulkan environment, the PixelCenterInteger "
"execution mode must not be used."));
}
@@ -531,24 +535,16 @@
std::ostringstream sstr;
sstr << "OpCapability Shader\n";
- if (!spvIsWebGPUEnv(env)) {
- sstr << "OpCapability Geometry\n";
- sstr << "OpCapability Tessellation\n";
- sstr << "OpCapability TransformFeedback\n";
- }
- if (!spvIsVulkanOrWebGPUEnv(env)) {
+ sstr << "OpCapability Geometry\n";
+ sstr << "OpCapability Tessellation\n";
+ sstr << "OpCapability TransformFeedback\n";
+ if (!spvIsVulkanEnv(env)) {
sstr << "OpCapability Kernel\n";
if (env == SPV_ENV_UNIVERSAL_1_3) {
sstr << "OpCapability SubgroupDispatch\n";
}
}
- if (spvIsWebGPUEnv(env)) {
- sstr << "OpCapability VulkanMemoryModelKHR\n";
- sstr << "OpExtension \"SPV_KHR_vulkan_memory_model\"\n";
- sstr << "OpMemoryModel Logical VulkanKHR\n";
- } else {
- sstr << "OpMemoryModel Logical GLSL450\n";
- }
+ sstr << "OpMemoryModel Logical GLSL450\n";
sstr << "OpEntryPoint " << model << " %main \"main\"\n";
if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 ||
mode.find("SubgroupsPerWorkgroupId") == 0) {
@@ -714,39 +710,6 @@
"SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"),
Values(SPV_ENV_UNIVERSAL_1_3)));
-INSTANTIATE_TEST_SUITE_P(ValidateModeGLComputeWebGPUAllowListGood,
- ValidateModeExecution,
- Combine(Values(SPV_SUCCESS), Values(""),
- Values("GLCompute"), Values("LocalSize 1 1 1"),
- Values(SPV_ENV_WEBGPU_0)));
-
-INSTANTIATE_TEST_SUITE_P(
- ValidateModeGLComputeWebGPUAllowListBad, ValidateModeExecution,
- Combine(Values(SPV_ERROR_INVALID_DATA),
- Values("Execution mode must be one of OriginUpperLeft, "
- "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, "
- "LocalSize, or LocalSizeHint for WebGPU environment"),
- Values("GLCompute"), Values("LocalSizeId %int1 %int1 %int1"),
- Values(SPV_ENV_WEBGPU_0)));
-
-INSTANTIATE_TEST_SUITE_P(
- ValidateModeFragmentWebGPUAllowListGood, ValidateModeExecution,
- Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"),
- Values("OriginUpperLeft", "DepthReplacing", "DepthGreater",
- "DepthLess", "DepthUnchanged"),
- Values(SPV_ENV_WEBGPU_0)));
-
-INSTANTIATE_TEST_SUITE_P(
- ValidateModeFragmentWebGPUAllowListBad, ValidateModeExecution,
- Combine(Values(SPV_ERROR_INVALID_DATA),
- Values("Execution mode must be one of OriginUpperLeft, "
- "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, "
- "LocalSize, or LocalSizeHint for WebGPU environment"),
- Values("Fragment"),
- Values("PixelCenterInteger", "OriginLowerLeft",
- "EarlyFragmentTests"),
- Values(SPV_ENV_WEBGPU_0)));
-
TEST_F(ValidateModeExecution, MeshNVLocalSize) {
const std::string spirv = R"(
OpCapability Shader
diff --git a/test/val/val_non_uniform_test.cpp b/test/val/val_non_uniform_test.cpp
index fbd11a9..3840eec 100644
--- a/test/val/val_non_uniform_test.cpp
+++ b/test/val/val_non_uniform_test.cpp
@@ -100,6 +100,7 @@
SpvScope scopes[] = {SpvScopeCrossDevice, SpvScopeDevice, SpvScopeWorkgroup,
SpvScopeSubgroup, SpvScopeInvocation};
+using ValidateGroupNonUniform = spvtest::ValidateBase<bool>;
using GroupNonUniform = spvtest::ValidateBase<
std::tuple<std::string, std::string, SpvScope, std::string, std::string>>;
@@ -140,6 +141,8 @@
EXPECT_EQ(SPV_SUCCESS, result);
} else {
EXPECT_EQ(SPV_ERROR_INVALID_DATA, result);
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-None-04642"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
@@ -288,6 +291,41 @@
Values("Expected Value to be a vector of four "
"components of integer type scalar")));
+TEST_F(ValidateGroupNonUniform, VulkanGroupNonUniformBallotBitCountOperation) {
+ std::string test = R"(
+OpCapability Shader
+OpCapability GroupNonUniform
+OpCapability GroupNonUniformBallot
+OpCapability GroupNonUniformClustered
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%u32 = OpTypeInt 32 0
+%u32vec4 = OpTypeVector %u32 4
+%u32_0 = OpConstant %u32 0
+%u32vec4_null = OpConstantComposite %u32vec4 %u32_0 %u32_0 %u32_0 %u32_0
+%subgroup = OpConstant %u32 3
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+%result = OpGroupNonUniformBallotBitCount %u32 %subgroup ClusteredReduce %u32vec4_null
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(test, SPV_ENV_VULKAN_1_1);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "In Vulkan: The OpGroupNonUniformBallotBitCount group operation must "
+ "be only: Reduce, InclusiveScan, or ExclusiveScan."));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_opencl_test.cpp b/test/val/val_opencl_test.cpp
index 1064158..9dab931 100644
--- a/test/val/val_opencl_test.cpp
+++ b/test/val/val_opencl_test.cpp
@@ -23,6 +23,7 @@
namespace val {
namespace {
+using testing::Eq;
using testing::HasSubstr;
using ValidateOpenCL = spvtest::ValidateBase<bool>;
@@ -91,7 +92,7 @@
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr("MS must be 0 in the OpenCL environement."
+ HasSubstr("MS must be 0 in the OpenCL environment."
"\n %2 = OpTypeImage %void 2D 0 0 1 0 Unknown ReadOnly\n"));
}
@@ -224,6 +225,264 @@
"\n %call = OpImageRead %v4uint %img %coord ConstOffset %coord\n"));
}
+TEST_F(ValidateOpenCL, ImageRead_NonDepthScalarFloatResult_Bad) {
+ std::string spirv = R"(
+ OpCapability Addresses
+ OpCapability Kernel
+ OpCapability ImageBasic
+ OpMemoryModel Physical64 OpenCL
+ OpEntryPoint Kernel %5 "image_kernel"
+ OpName %img "img"
+ OpName %coord "coord"
+ OpName %call "call"
+ %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+ %coord = OpConstantNull %v2uint
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
+ %4 = OpTypeFunction %void %3
+ %5 = OpFunction %void None %4
+ %img = OpFunctionParameter %3
+ %entry = OpLabel
+ %call = OpImageRead %float %img %coord
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Result Type to have 4 components"));
+}
+
+TEST_F(ValidateOpenCL, ImageRead_NonDepthScalarIntResult_Bad) {
+ std::string spirv = R"(
+ OpCapability Addresses
+ OpCapability Kernel
+ OpCapability ImageBasic
+ OpMemoryModel Physical64 OpenCL
+ OpEntryPoint Kernel %5 "image_kernel"
+ OpName %img "img"
+ OpName %coord "coord"
+ OpName %call "call"
+ %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+ %coord = OpConstantNull %v2uint
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
+ %4 = OpTypeFunction %void %3
+ %5 = OpFunction %void None %4
+ %img = OpFunctionParameter %3
+ %entry = OpLabel
+ %call = OpImageRead %uint %img %coord
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Result Type to have 4 components"));
+}
+
+TEST_F(ValidateOpenCL, ImageRead_NonDepthVector3FloatResult_Bad) {
+ std::string spirv = R"(
+ OpCapability Addresses
+ OpCapability Kernel
+ OpCapability ImageBasic
+ OpMemoryModel Physical64 OpenCL
+ OpEntryPoint Kernel %5 "image_kernel"
+ OpName %img "img"
+ OpName %coord "coord"
+ OpName %call "call"
+ %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+ %coord = OpConstantNull %v2uint
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+ %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
+ %4 = OpTypeFunction %void %3
+ %5 = OpFunction %void None %4
+ %img = OpFunctionParameter %3
+ %entry = OpLabel
+ %call = OpImageRead %v3float %img %coord
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Result Type to have 4 components"));
+}
+
+TEST_F(ValidateOpenCL, ImageRead_NonDepthVector4FloatResult_Ok) {
+ std::string spirv = R"(
+ OpCapability Addresses
+ OpCapability Kernel
+ OpCapability ImageBasic
+ OpMemoryModel Physical64 OpenCL
+ OpEntryPoint Kernel %5 "image_kernel"
+ OpName %img "img"
+ OpName %coord "coord"
+ OpName %call "call"
+ %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+ %coord = OpConstantNull %v2uint
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
+ %4 = OpTypeFunction %void %3
+ %5 = OpFunction %void None %4
+ %img = OpFunctionParameter %3
+ %entry = OpLabel
+ %call = OpImageRead %v4float %img %coord
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateOpenCL, ImageRead_NonDepthVector4IntResult_Ok) {
+ std::string spirv = R"(
+ OpCapability Addresses
+ OpCapability Kernel
+ OpCapability ImageBasic
+ OpMemoryModel Physical64 OpenCL
+ OpEntryPoint Kernel %5 "image_kernel"
+ OpName %img "img"
+ OpName %coord "coord"
+ OpName %call "call"
+ %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+ %coord = OpConstantNull %v2uint
+ %void = OpTypeVoid
+ %v4uint = OpTypeVector %uint 4
+ %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
+ %4 = OpTypeFunction %void %3
+ %5 = OpFunction %void None %4
+ %img = OpFunctionParameter %3
+ %entry = OpLabel
+ %call = OpImageRead %v4uint %img %coord
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateOpenCL, ImageRead_DepthScalarFloatResult_Ok) {
+ std::string spirv = R"(
+ OpCapability Addresses
+ OpCapability Kernel
+ OpCapability ImageBasic
+ OpMemoryModel Physical64 OpenCL
+ OpEntryPoint Kernel %5 "image_kernel"
+ OpName %img "img"
+ OpName %coord "coord"
+ OpName %call "call"
+ %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+ %coord = OpConstantNull %v2uint
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %3 = OpTypeImage %void 2D 1 0 0 0 Unknown ReadOnly
+ %4 = OpTypeFunction %void %3
+ %5 = OpFunction %void None %4
+ %img = OpFunctionParameter %3
+ %entry = OpLabel
+ %call = OpImageRead %float %img %coord
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateOpenCL, ImageRead_DepthScalarIntResult_Bad) {
+ std::string spirv = R"(
+ OpCapability Addresses
+ OpCapability Kernel
+ OpCapability ImageBasic
+ OpMemoryModel Physical64 OpenCL
+ OpEntryPoint Kernel %5 "image_kernel"
+ OpName %img "img"
+ OpName %coord "coord"
+ OpName %call "call"
+ %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+ %coord = OpConstantNull %v2uint
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %3 = OpTypeImage %void 2D 1 0 0 0 Unknown ReadOnly
+ %4 = OpTypeFunction %void %3
+ %5 = OpFunction %void None %4
+ %img = OpFunctionParameter %3
+ %entry = OpLabel
+ %call = OpImageRead %uint %img %coord
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Result Type from a depth image "
+ "read to result in a scalar float value"));
+}
+
+TEST_F(ValidateOpenCL, ImageRead_DepthVectorFloatResult_Bad) {
+ std::string spirv = R"(
+ OpCapability Addresses
+ OpCapability Kernel
+ OpCapability ImageBasic
+ OpMemoryModel Physical64 OpenCL
+ OpEntryPoint Kernel %5 "image_kernel"
+ OpName %img "img"
+ OpName %coord "coord"
+ OpName %call "call"
+ %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+ %coord = OpConstantNull %v2uint
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %3 = OpTypeImage %void 2D 1 0 0 0 Unknown ReadOnly
+ %4 = OpTypeFunction %void %3
+ %5 = OpFunction %void None %4
+ %img = OpFunctionParameter %3
+ %entry = OpLabel
+ %call = OpImageRead %v4float %img %coord
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv);
+
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Result Type from a depth image "
+ "read to result in a scalar float value"));
+}
+
TEST_F(ValidateOpenCL, ImageSampleExplicitLodWithConstOffsetBad) {
std::string spirv = R"(
OpCapability Addresses
@@ -236,18 +495,16 @@
OpName %coord "coord"
OpName %call "call"
%uint = OpTypeInt 32 0
- %uint_7 = OpConstant %uint 7
- %uint_3 = OpConstant %uint 3
+ %v2uint = OpTypeVector %uint 2
+ %coord = OpConstantNull %v2uint
%void = OpTypeVoid
%3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
%4 = OpTypeFunction %void %3
%8 = OpTypeSampler
%10 = OpTypeSampledImage %3
%v4uint = OpTypeVector %uint 4
- %v2uint = OpTypeVector %uint 2
%float = OpTypeFloat 32
%9 = OpConstantSampler %8 None 0 Nearest
- %coord = OpConstantComposite %v2uint %uint_7 %uint_3
%float_0 = OpConstant %float 0
%5 = OpFunction %void None %4
%6 = OpFunctionParameter %3
diff --git a/test/val/val_storage_test.cpp b/test/val/val_storage_test.cpp
index fe37a93..e6f98bf 100644
--- a/test/val/val_storage_test.cpp
+++ b/test/val/val_storage_test.cpp
@@ -250,70 +250,6 @@
HasSubstr("OpFunctionCall Argument <id> '"));
}
-std::string GetVarDeclStr(const std::string& storage_class) {
- if (storage_class != "Output" && storage_class != "Private" &&
- storage_class != "Function") {
- return "%var = OpVariable %ptrt " + storage_class + "\n";
- } else {
- return "%var = OpVariable %ptrt " + storage_class + " %null\n";
- }
-}
-
-TEST_P(ValidateStorageClass, WebGPU) {
- std::string storage_class = std::get<0>(GetParam());
- bool is_local = std::get<1>(GetParam());
- bool is_valid = std::get<2>(GetParam());
- std::string error = std::get<3>(GetParam());
-
- std::string str = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Fragment %func "func"
- OpExecutionMode %func OriginUpperLeft
-%intt = OpTypeInt 32 1
-%voidt = OpTypeVoid
-%vfunct = OpTypeFunction %voidt
-%null = OpConstantNull %intt
-)";
- str += "%ptrt = OpTypePointer " + storage_class + " %intt\n";
- if (!is_local) str += GetVarDeclStr(storage_class);
- str += R"(
-%func = OpFunction %voidt None %vfunct
-%funcl = OpLabel
-)";
- if (is_local) str += GetVarDeclStr(storage_class);
- str += R"(
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(str, SPV_ENV_WEBGPU_0);
- if (is_valid) {
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
- } else {
- ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(), HasSubstr(error));
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(
- StorageClass, ValidateStorageClass,
- Values(std::make_tuple("UniformConstant", false, true, ""),
- std::make_tuple("Uniform", false, true, ""),
- std::make_tuple("StorageBuffer", false, true, ""),
- std::make_tuple("Input", false, true, ""),
- std::make_tuple("Output", false, true, ""),
- std::make_tuple("Image", false, true, ""),
- std::make_tuple("Workgroup", false, true, ""),
- std::make_tuple("Private", false, true, ""),
- std::make_tuple("Function", true, true, ""),
- std::make_tuple("CrossWorkgroup", false, false,
- "Invalid storage class for target environment"),
- std::make_tuple("PushConstant", false, false,
- "Invalid storage class for target environment")));
-
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_validation_state_test.cpp b/test/val/val_validation_state_test.cpp
index 4581579..7a38d3a 100644
--- a/test/val/val_validation_state_test.cpp
+++ b/test/val/val_validation_state_test.cpp
@@ -245,12 +245,6 @@
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
}
-TEST_F(ValidationStateTest, CheckWebGPUNonRecursiveBodyGood) {
- std::string spirv = std::string(kVulkanMemoryHeader) + kNonRecursiveBody;
- CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
-}
-
TEST_F(ValidationStateTest, CheckDirectlyRecursiveBodyGood) {
std::string spirv = std::string(kHeader) + kDirectlyRecursiveBody;
CompileSuccessfully(spirv);
@@ -267,16 +261,6 @@
" %1 = OpFunction %void Pure|Const %3\n"));
}
-TEST_F(ValidationStateTest, CheckWebGPUDirectlyRecursiveBodyBad) {
- std::string spirv = std::string(kVulkanMemoryHeader) + kDirectlyRecursiveBody;
- CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
- ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Entry points may not have a call graph with cycles.\n "
- " %1 = OpFunction %void Pure|Const %3\n"));
-}
-
TEST_F(ValidationStateTest, CheckIndirectlyRecursiveBodyGood) {
std::string spirv = std::string(kHeader) + kIndirectlyRecursiveBody;
CompileSuccessfully(spirv);
@@ -294,68 +278,6 @@
" %1 = OpFunction %void Pure|Const %3\n"));
}
-// Indirectly recursive functions are caught by the function definition layout
-// rules, because they cause a situation where there are 2 functions that have
-// to be before each other, and layout is checked earlier.
-TEST_F(ValidationStateTest, CheckWebGPUIndirectlyRecursiveBodyBad) {
- std::string spirv =
- std::string(kVulkanMemoryHeader) + kIndirectlyRecursiveBody;
- CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, functions need to be defined before being "
- "called.\n %10 = OpFunctionCall %_struct_5 %11\n"));
-}
-
-TEST_F(ValidationStateTest,
- CheckWebGPUDuplicateEntryNamesDifferentFunctionsBad) {
- std::string spirv = std::string(kVulkanMemoryHeader) + R"(
-OpEntryPoint Fragment %func_1 "main"
-OpEntryPoint Vertex %func_2 "main"
-OpExecutionMode %func_1 OriginUpperLeft
-%void = OpTypeVoid
-%void_f = OpTypeFunction %void
-%func_1 = OpFunction %void None %void_f
-%label_1 = OpLabel
- OpReturn
- OpFunctionEnd
-%func_2 = OpFunction %void None %void_f
-%label_2 = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
- ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Entry point name \"main\" is not unique, which is not allow "
- "in WebGPU env.\n %1 = OpFunction %void None %4\n"));
-}
-
-TEST_F(ValidationStateTest, CheckWebGPUDuplicateEntryNamesSameFunctionBad) {
- std::string spirv = std::string(kVulkanMemoryHeader) + R"(
-OpEntryPoint GLCompute %func_1 "main"
-OpEntryPoint Vertex %func_1 "main"
-%void = OpTypeVoid
-%void_f = OpTypeFunction %void
-%func_1 = OpFunction %void None %void_f
-%label_1 = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
- EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
- ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Entry point name \"main\" is not unique, which is not allow "
- "in WebGPU env.\n %1 = OpFunction %void None %3\n"));
-}
-
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_version_test.cpp b/test/val/val_version_test.cpp
index 2b9542a..98565dd 100644
--- a/test/val/val_version_test.cpp
+++ b/test/val/val_version_test.cpp
@@ -40,21 +40,6 @@
OpFunctionEnd
)";
-const std::string webgpu_spirv = R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
-OpEntryPoint Fragment %func "func"
-OpExecutionMode %func OriginUpperLeft
-%void = OpTypeVoid
-%functy = OpTypeFunction %void
-%func = OpFunction %void None %functy
-%1 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
const std::string opencl_spirv = R"(
OpCapability Addresses
OpCapability Kernel
@@ -85,7 +70,6 @@
return "1.2";
case SPV_ENV_UNIVERSAL_1_3:
case SPV_ENV_VULKAN_1_1:
- case SPV_ENV_WEBGPU_0:
return "1.3";
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
@@ -126,7 +110,6 @@
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_2, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_3, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_5, vulkan_spirv, true),
- std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_WEBGPU_0, webgpu_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, true),
@@ -139,7 +122,6 @@
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_5, vulkan_spirv, false),
- std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_WEBGPU_0, webgpu_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
@@ -152,7 +134,6 @@
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_5, vulkan_spirv, false),
- std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_WEBGPU_0, webgpu_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
@@ -164,8 +145,7 @@
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
- std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_5, vulkan_spirv, false),
- std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_WEBGPU_0, webgpu_spirv, true)
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_5, vulkan_spirv, false)
)
);
diff --git a/test/val/val_webgpu_test.cpp b/test/val/val_webgpu_test.cpp
deleted file mode 100644
index 62fa6a7..0000000
--- a/test/val/val_webgpu_test.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-// Copyright (c) 2018 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.
-
-// Validation tests for WebGPU env specific checks
-
-#include <string>
-
-#include "gmock/gmock.h"
-#include "test/val/val_fixtures.h"
-
-namespace spvtools {
-namespace val {
-namespace {
-
-using testing::HasSubstr;
-
-using ValidateWebGPU = spvtest::ValidateBase<bool>;
-
-TEST_F(ValidateWebGPU, OpUndefIsDisallowed) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
-%float = OpTypeFloat 32
-%1 = OpUndef %float
-%void = OpTypeVoid
-%void_f = OpTypeFunction %void
-%func = OpFunction %void None %void_f
-%label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
-
- // Control case: OpUndef is allowed in SPIR-V 1.3
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
-
- // Control case: OpUndef is disallowed in the WebGPU env
- EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(), HasSubstr("OpUndef is disallowed"));
-}
-
-TEST_F(ValidateWebGPU, OpNameIsAllowed) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
- OpName %1 "foo"
- %1 = OpTypeFloat 32
- %void = OpTypeVoid
- %void_f = OpTypeFunction %void
- %func = OpFunction %void None %void_f
- %label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, OpMemberNameIsAllowed) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
- OpMemberName %2 0 "foo"
- %1 = OpTypeFloat 32
- %2 = OpTypeStruct %1
- %void = OpTypeVoid
- %void_f = OpTypeFunction %void
- %func = OpFunction %void None %void_f
- %label = OpLabel
- OpReturn
- OpFunctionEnd
-
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, OpSourceIsAllowed) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
- OpSource GLSL 450
- %void = OpTypeVoid
- %void_f = OpTypeFunction %void
- %func = OpFunction %void None %void_f
- %label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, OpSourceContinuedIsAllowed) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
- OpSource GLSL 450
- OpSourceContinued "I am a happy shader! Yay! ;"
- %void = OpTypeVoid
- %void_f = OpTypeFunction %void
- %func = OpFunction %void None %void_f
- %label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, OpSourceExtensionIsAllowed) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
- OpSourceExtension "bar"
- %void = OpTypeVoid
- %void_f = OpTypeFunction %void
- %func = OpFunction %void None %void_f
- %label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, OpStringIsAllowed) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
- %1 = OpString "foo"
- %void = OpTypeVoid
- %void_f = OpTypeFunction %void
- %func = OpFunction %void None %void_f
- %label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, OpLineIsAllowed) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
- %1 = OpString "minimal.vert"
- OpLine %1 1 1
- %void = OpTypeVoid
- %void_f = OpTypeFunction %void
- %func = OpFunction %void None %void_f
- %label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, OpNoLineIsAllowed) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
- OpNoLine
- %void = OpTypeVoid
- %void_f = OpTypeFunction %void
- %func = OpFunction %void None %void_f
- %label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, LogicalAddressingVulkanKHRMemoryGood) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
-%void = OpTypeVoid
-%void_f = OpTypeFunction %void
-%func = OpFunction %void None %void_f
-%label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, LogicalAddressingGLSL450MemoryGood) {
- std::string spirv = R"(
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint Vertex %func "shader"
-%void = OpTypeVoid
-%void_f = OpTypeFunction %void
-%func = OpFunction %void None %void_f
-%label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, LogicalAddressingSimpleMemoryGood) {
- std::string spirv = R"(
- OpCapability Shader
- OpMemoryModel Logical Simple
- OpEntryPoint Vertex %func "shader"
-%void = OpTypeVoid
-%void_f = OpTypeFunction %void
-%func = OpFunction %void None %void_f
-%label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, KernelIsBad) {
- std::string spirv = R"(
- OpCapability Kernel
- OpMemoryModel Logical Simple
- OpNoLine
-)";
-
- CompileSuccessfully(spirv);
-
- EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Capability Kernel is not allowed by WebGPU "
- "specification (or requires extension)"));
-}
-
-TEST_F(ValidateWebGPU, OpenCLMemoryModelBad) {
- std::string spirv = R"(
- OpCapability Shader
- OpMemoryModel Logical OpenCL
- OpNoLine
-)";
-
- CompileSuccessfully(spirv);
-
- EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY,
- ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Operand 2 of MemoryModel requires one of these "
- "capabilities: Kernel"));
-}
-
-TEST_F(ValidateWebGPU, AllowListedExtendedInstructionsImportGood) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
-%1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical VulkanKHR
- OpEntryPoint Vertex %func "shader"
-%void = OpTypeVoid
-%void_f = OpTypeFunction %void
-%func = OpFunction %void None %void_f
-%label = OpLabel
- OpReturn
- OpFunctionEnd
-)";
-
- CompileSuccessfully(spirv);
-
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, NonAllowListedExtendedInstructionsImportBad) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
-%1 = OpExtInstImport "OpenCL.std"
- OpMemoryModel Logical VulkanKHR
-)";
-
- CompileSuccessfully(spirv);
-
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, the only valid parameter to "
- "OpExtInstImport is \"GLSL.std.450\".\n %1 = "
- "OpExtInstImport \"OpenCL.std\"\n"));
-}
-
-TEST_F(ValidateWebGPU, NonVulkanKHRMemoryModelExtensionBad) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_8bit_storage"
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Logical VulkanKHR
-)";
-
- CompileSuccessfully(spirv);
-
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("For WebGPU, the only valid parameter to OpExtension "
- "is \"SPV_KHR_vulkan_memory_model\".\n OpExtension "
- "\"SPV_KHR_8bit_storage\"\n"));
-}
-
-spv_binary GenerateTrivialBinary(bool need_little_endian) {
- // Smallest possible valid WebGPU SPIR-V binary in little endian. Contains all
- // the required boilerplate and a trivial entry point function.
- static const uint8_t binary_bytes[] = {
- // clang-format off
- 0x03, 0x02, 0x23, 0x07, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0xE1, 0x14, 0x00, 0x00,
- 0x0A, 0x00, 0x08, 0x00, 0x53, 0x50, 0x56, 0x5F, 0x4B, 0x48, 0x52, 0x5F,
- 0x76, 0x75, 0x6C, 0x6B, 0x61, 0x6E, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72,
- 0x79, 0x5F, 0x6D, 0x6F, 0x64, 0x65, 0x6C, 0x00, 0x0E, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x68, 0x61, 0x64,
- 0x65, 0x72, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00
- // clang-format on
- };
- static const size_t word_count = sizeof(binary_bytes) / sizeof(uint32_t);
- std::unique_ptr<spv_binary_t> result(new spv_binary_t);
- if (!result) return nullptr;
-
- result->wordCount = word_count;
- result->code = new uint32_t[word_count];
- if (!result->code) return nullptr;
-
- if (need_little_endian) {
- memcpy(result->code, binary_bytes, sizeof(binary_bytes));
- } else {
- uint8_t* code_bytes = reinterpret_cast<uint8_t*>(result->code);
- for (size_t word = 0; word < word_count; ++word) {
- code_bytes[4 * word] = binary_bytes[4 * word + 3];
- code_bytes[4 * word + 1] = binary_bytes[4 * word + 2];
- code_bytes[4 * word + 2] = binary_bytes[4 * word + 1];
- code_bytes[4 * word + 3] = binary_bytes[4 * word];
- }
- }
-
- return result.release();
-}
-
-TEST_F(ValidateWebGPU, LittleEndianGood) {
- DestroyBinary();
- binary_ = GenerateTrivialBinary(true);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
-}
-
-TEST_F(ValidateWebGPU, BigEndianBad) {
- DestroyBinary();
- binary_ = GenerateTrivialBinary(false);
- EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("WebGPU requires SPIR-V to be little endian."));
-}
-
-} // namespace
-} // namespace val
-} // namespace spvtools
diff --git a/tools/link/linker.cpp b/tools/link/linker.cpp
index 82d430e..1956f59 100644
--- a/tools/link/linker.cpp
+++ b/tools/link/linker.cpp
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "spirv-tools/linker.hpp"
+
#include <cstring>
#include <iostream>
#include <vector>
@@ -19,42 +21,56 @@
#include "source/spirv_target_env.h"
#include "source/table.h"
#include "spirv-tools/libspirv.hpp"
-#include "spirv-tools/linker.hpp"
#include "tools/io.h"
-void print_usage(char* argv0) {
- std::string target_env_list = spvTargetEnvList(27, 95);
+namespace {
+
+const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
+
+void print_usage(const char* program) {
+ std::string target_env_list = spvTargetEnvList(16, 80);
+ // NOTE: Please maintain flags in lexicographical order.
printf(
R"(%s - Link SPIR-V binary files together.
-USAGE: %s [options] <filename> [<filename> ...]
+USAGE: %s [options] [-o <output>] <input>...
-The SPIR-V binaries are read from the different <filename>.
+The SPIR-V binaries are read from the different <input>(s).
+The SPIR-V resulting linked binary module is written to the file "out.spv"
+unless the -o option is used; if <output> is "-", it is written to the standard
+output.
NOTE: The linker is a work in progress.
-Options:
- -h, --help Print this help.
- -o Name of the resulting linked SPIR-V binary.
- --create-library Link the binaries into a library, keeping all exported symbols.
- --allow-partial-linkage Allow partial linkage by accepting imported symbols to be unresolved.
- --verify-ids Verify that IDs in the resulting modules are truly unique.
- --version Display linker version information
- --target-env {%s}
- Use validation rules from the specified environment.
+Options (in lexicographical order):
+ --allow-partial-linkage
+ Allow partial linkage by accepting imported symbols to be
+ unresolved.
+ --create-library
+ Link the binaries into a library, keeping all exported symbols.
+ -h, --help
+ Print this help.
+ --target-env <env>
+ Set the target environment. Without this flag the target
+ environment defaults to spv1.5. <env> must be one of
+ {%s}
+ --verify-ids
+ Verify that IDs in the resulting modules are truly unique.
+ --version
+ Display linker version information
)",
- argv0, argv0, target_env_list.c_str());
+ program, program, target_env_list.c_str());
}
+} // namespace
+
int main(int argc, char** argv) {
std::vector<const char*> inFiles;
const char* outFile = nullptr;
- spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0;
+ spv_target_env target_env = kDefaultEnvironment;
spvtools::LinkerOptions options;
- bool continue_processing = true;
- int return_code = 0;
- for (int argi = 1; continue_processing && argi < argc; ++argi) {
+ for (int argi = 1; argi < argc; ++argi) {
const char* cur_arg = argv[argi];
if ('-' == cur_arg[0]) {
if (0 == strcmp(cur_arg, "-o")) {
@@ -63,55 +79,48 @@
outFile = argv[++argi];
} else {
fprintf(stderr, "error: More than one output file specified\n");
- continue_processing = false;
- return_code = 1;
+ return 1;
}
} else {
fprintf(stderr, "error: Missing argument to %s\n", cur_arg);
- continue_processing = false;
- return_code = 1;
+ return 1;
}
- } else if (0 == strcmp(cur_arg, "--create-library")) {
- options.SetCreateLibrary(true);
- } else if (0 == strcmp(cur_arg, "--verify-ids")) {
- options.SetVerifyIds(true);
} else if (0 == strcmp(cur_arg, "--allow-partial-linkage")) {
options.SetAllowPartialLinkage(true);
- } else if (0 == strcmp(cur_arg, "--version")) {
- printf("%s\n", spvSoftwareVersionDetailsString());
- // TODO(dneto): Add OpenCL 2.2 at least.
- printf("Targets:\n %s\n %s\n %s\n",
- spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1),
- spvTargetEnvDescription(SPV_ENV_VULKAN_1_0),
- spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2));
- continue_processing = false;
- return_code = 0;
+ } else if (0 == strcmp(cur_arg, "--create-library")) {
+ options.SetCreateLibrary(true);
} else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
print_usage(argv[0]);
- continue_processing = false;
- return_code = 0;
+ return 0;
} else if (0 == strcmp(cur_arg, "--target-env")) {
if (argi + 1 < argc) {
const auto env_str = argv[++argi];
if (!spvParseTargetEnv(env_str, &target_env)) {
fprintf(stderr, "error: Unrecognized target env: %s\n", env_str);
- continue_processing = false;
- return_code = 1;
+ return 1;
}
} else {
fprintf(stderr, "error: Missing argument to --target-env\n");
- continue_processing = false;
- return_code = 1;
+ return 1;
}
+ } else if (0 == strcmp(cur_arg, "--verify-ids")) {
+ options.SetVerifyIds(true);
+ } else if (0 == strcmp(cur_arg, "--version")) {
+ printf("%s\n", spvSoftwareVersionDetailsString());
+ printf("Target: %s\n", spvTargetEnvDescription(target_env));
+ return 0;
+ } else {
+ fprintf(stderr, "error: Unrecognized option: %s\n\n", argv[argi]);
+ print_usage(argv[0]);
+ return 1;
}
} else {
inFiles.push_back(cur_arg);
}
}
- // Exit if command line parsing was not successful.
- if (!continue_processing) {
- return return_code;
+ if (!outFile) {
+ outFile = "out.spv";
}
if (inFiles.empty()) {
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index 66f9228..e7e5899 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -79,18 +79,6 @@
return GetListOfPassesAsString(optimizer);
}
-std::string GetVulkanToWebGPUPasses() {
- spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1);
- optimizer.RegisterVulkanToWebGPUPasses();
- return GetListOfPassesAsString(optimizer);
-}
-
-std::string GetWebGPUToVulkanPasses() {
- spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0);
- optimizer.RegisterWebGPUToVulkanPasses();
- return GetListOfPassesAsString(optimizer);
-}
-
void PrintUsage(const char* program) {
std::string target_env_list = spvTargetEnvList(16, 80);
// NOTE: Please maintain flags in lexicographical order.
@@ -239,10 +227,6 @@
values, providing guarantees that satisfy Vulkan's
robustBufferAccess rules.)");
printf(R"(
- --generate-webgpu-initializers
- Adds initial values to OpVariable instructions that are missing
- them, due to their storage type requiring them for WebGPU.)");
- printf(R"(
--if-conversion
Convert if-then-else like assignments into OpSelect.)");
printf(R"(
@@ -261,11 +245,6 @@
option --relax-logical-pointer to the validator.)",
GetLegalizationPasses().c_str());
printf(R"(
- --legalize-vector-shuffle
- Converts any usages of 0xFFFFFFFF for the literals in
- OpVectorShuffle to a literal 0. This is done since 0xFFFFFFFF is
- forbidden in WebGPU.)");
- printf(R"(
--local-redundancy-elimination
Looks for instructions in the same basic block that compute the
same value, and deletes the redundant ones.)");
@@ -463,13 +442,6 @@
Forwards this option to the validator. See the validator help
for details.)");
printf(R"(
- --split-invalid-unreachable
- Attempts to legalize for WebGPU cases where an unreachable
- merge-block is also a continue-target by splitting it into two
- separate blocks. There exist legal, for Vulkan, instances of this
- pattern that cannot be converted into legal WebGPU, so this
- conversion may not succeed.)");
- printf(R"(
--skip-validation
Will not validate the SPIR-V before optimizing. If the SPIR-V
is invalid, the optimizer may fail or generate incorrect code.
@@ -513,34 +485,6 @@
removes them from the vector. Note this would still leave around
lots of dead code that a pass of ADCE will be able to remove.)");
printf(R"(
- --vulkan-to-webgpu
- Turns on the prescribed passes for converting from Vulkan to
- WebGPU and sets the target environment to webgpu0. Other passes
- may be turned on via additional flags, but such combinations are
- not tested.
- Using --target-env with this flag is not allowed.
-
- This flag is the equivalent of passing in --target-env=webgpu0
- and specifying the following optimization code names:
- %s
-
- NOTE: This flag is a WIP and its behaviour is subject to change.)",
- GetVulkanToWebGPUPasses().c_str());
- printf(R"(
- --webgpu-to-vulkan
- Turns on the prescribed passes for converting from WebGPU to
- Vulkan and sets the target environment to vulkan1.1. Other passes
- may be turned on via additional flags, but such combinations are
- not tested.
- Using --target-env with this flag is not allowed.
-
- This flag is the equivalent of passing in --target-env=vulkan1.1
- and specifying the following optimization code names:
- %s
-
- NOTE: This flag is a WIP and its behaviour is subject to change.)",
- GetWebGPUToVulkanPasses().c_str());
- printf(R"(
--workaround-1209
Rewrites instructions for which there are known driver bugs to
avoid triggering those bugs.
@@ -714,9 +658,6 @@
spvtools::ValidatorOptions* validator_options,
spvtools::OptimizerOptions* optimizer_options) {
std::vector<std::string> pass_flags;
- bool target_env_set = false;
- bool vulkan_to_webgpu_set = false;
- bool webgpu_to_vulkan_set = false;
for (int argi = 1; argi < argc; ++argi) {
const char* cur_arg = argv[argi];
if ('-' == cur_arg[0]) {
@@ -781,19 +722,6 @@
max_id_bound);
} else if (0 == strncmp(cur_arg,
"--target-env=", sizeof("--target-env=") - 1)) {
- target_env_set = true;
- if (vulkan_to_webgpu_set) {
- spvtools::Error(opt_diagnostic, nullptr, {},
- "--vulkan-to-webgpu defines the target environment, "
- "so --target-env cannot be set at the same time");
- return {OPT_STOP, 1};
- }
- if (webgpu_to_vulkan_set) {
- spvtools::Error(opt_diagnostic, nullptr, {},
- "--webgpu-to-vulkan defines the target environment, "
- "so --target-env cannot be set at the same time");
- return {OPT_STOP, 1};
- }
const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
const auto target_env_str = split_flag.second.c_str();
spv_target_env target_env;
@@ -803,42 +731,6 @@
return {OPT_STOP, 1};
}
optimizer->SetTargetEnv(target_env);
- } else if (0 == strcmp(cur_arg, "--vulkan-to-webgpu")) {
- vulkan_to_webgpu_set = true;
- if (target_env_set) {
- spvtools::Error(opt_diagnostic, nullptr, {},
- "--vulkan-to-webgpu defines the target environment, "
- "so --target-env cannot be set at the same time");
- return {OPT_STOP, 1};
- }
- if (webgpu_to_vulkan_set) {
- spvtools::Error(opt_diagnostic, nullptr, {},
- "Cannot use both --webgpu-to-vulkan and "
- "--vulkan-to-webgpu at the same time, invoke twice "
- "if you are wanting to go to and from");
- return {OPT_STOP, 1};
- }
-
- optimizer->SetTargetEnv(SPV_ENV_VULKAN_1_1);
- optimizer->RegisterVulkanToWebGPUPasses();
- } else if (0 == strcmp(cur_arg, "--webgpu-to-vulkan")) {
- webgpu_to_vulkan_set = true;
- if (target_env_set) {
- spvtools::Error(opt_diagnostic, nullptr, {},
- "--webgpu-to-vulkan defines the target environment, "
- "so --target-env cannot be set at the same time");
- return {OPT_STOP, 1};
- }
- if (vulkan_to_webgpu_set) {
- spvtools::Error(opt_diagnostic, nullptr, {},
- "Cannot use both --webgpu-to-vulkan and "
- "--vulkan-to-webgpu at the same time, invoke twice "
- "if you are wanting to go to and from");
- return {OPT_STOP, 1};
- }
-
- optimizer->SetTargetEnv(SPV_ENV_WEBGPU_0);
- optimizer->RegisterWebGPUToVulkanPasses();
} else if (0 == strcmp(cur_arg, "--validate-after-all")) {
optimizer->SetValidateAfterAll(true);
} else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) {
diff --git a/tools/sva/yarn.lock b/tools/sva/yarn.lock
index 34a1808..c46b901 100644
--- a/tools/sva/yarn.lock
+++ b/tools/sva/yarn.lock
@@ -795,9 +795,9 @@
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
ini@~1.3.0:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
- integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
+ integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
inquirer@^6.4.1:
version "6.5.2"
diff --git a/tools/val/val.cpp b/tools/val/val.cpp
index 19b8c77..da63245 100644
--- a/tools/val/val.cpp
+++ b/tools/val/val.cpp
@@ -108,7 +108,7 @@
printf("%s\n", spvSoftwareVersionDetailsString());
printf(
"Targets:\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n "
- "%s\n %s\n",
+ "%s\n",
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2),
@@ -118,8 +118,7 @@
spvTargetEnvDescription(SPV_ENV_OPENCL_2_2),
spvTargetEnvDescription(SPV_ENV_VULKAN_1_0),
spvTargetEnvDescription(SPV_ENV_VULKAN_1_1),
- spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4),
- spvTargetEnvDescription(SPV_ENV_WEBGPU_0));
+ spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4));
continue_processing = false;
return_code = 0;
} else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
diff --git a/utils/check_copyright.py b/utils/check_copyright.py
index 39d27cb..b15bc20 100755
--- a/utils/check_copyright.py
+++ b/utils/check_copyright.py
@@ -39,7 +39,7 @@
'Stefano Milizia']
CURRENT_YEAR='2020'
-YEARS = '(2014-2016|2015-2016|2015-2020|2016|2016-2017|2017|2017-2019|2018|2019|2020)'
+YEARS = '(2014-2016|2015-2016|2015-2020|2016|2016-2017|2017|2017-2019|2018|2019|2020|2021)'
COPYRIGHT_RE = re.compile(
'Copyright \(c\) {} ({})'.format(YEARS, '|'.join(AUTHORS)))
diff --git a/utils/git-sync-deps b/utils/git-sync-deps
index 0575641..eecfbe9 100755
--- a/utils/git-sync-deps
+++ b/utils/git-sync-deps
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2014 Google Inc.
#
# Redistribution and use in source and binary forms, with or without