aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-prod (mdb) <android-build-team-robot@google.com>2021-02-27 05:49:55 +0000
committerandroid-build-prod (mdb) <android-build-team-robot@google.com>2021-02-27 05:49:55 +0000
commit0d8be8af319b1c2d59b5d75a49a7eaf98de5fd8d (patch)
treecdf8cf856b8b694d560e88ba23590539c76c6e4f
parent6f12baac0b877d2d3ca91035d645507310466410 (diff)
parent47df6daa2cea78e737c171aa9dda5fdd5353f87a (diff)
downloadspirv-tools-busytown-mac1010-release.tar.gz
Snap for 7174163 from 47df6daa2cea78e737c171aa9dda5fdd5353f87a to busytown-mac1010-releasebusytown-mac1010-release
Change-Id: I87536067a8a8fba3327e7eee23bd2bda7af373c1
-rw-r--r--Android.mk5
-rw-r--r--BUILD.gn10
-rw-r--r--CHANGES56
-rw-r--r--DEPS2
-rw-r--r--README.md1
-rw-r--r--android_test/jni/Application.mk2
-rw-r--r--build_overrides/build.gni3
-rw-r--r--include/spirv-tools/instrument.hpp5
-rw-r--r--include/spirv-tools/libspirv.h13
-rw-r--r--include/spirv-tools/libspirv.hpp6
-rw-r--r--include/spirv-tools/optimizer.hpp41
-rwxr-xr-x[-rw-r--r--]kokoro/android/build.sh32
-rwxr-xr-x[-rw-r--r--]kokoro/linux-clang-asan/build.sh2
-rwxr-xr-x[-rw-r--r--]kokoro/linux-clang-debug/build.sh2
-rwxr-xr-x[-rw-r--r--]kokoro/linux-clang-release-bazel/build.sh23
-rwxr-xr-x[-rw-r--r--]kokoro/linux-clang-release/build.sh2
-rwxr-xr-x[-rw-r--r--]kokoro/linux-gcc-debug/build.sh2
-rwxr-xr-x[-rw-r--r--]kokoro/linux-gcc-release/build.sh2
-rwxr-xr-x[-rw-r--r--]kokoro/ndk-build/build.sh37
-rwxr-xr-xkokoro/scripts/linux/build-docker.sh196
-rw-r--r--kokoro/scripts/linux/build.sh113
-rw-r--r--kokoro/scripts/windows/build.bat2
-rwxr-xr-x[-rw-r--r--]kokoro/shaderc-smoketest/build.sh53
-rw-r--r--source/binary.cpp4
-rw-r--r--source/disassemble.cpp4
-rw-r--r--source/ext_inst.cpp1
-rw-r--r--source/fuzz/transformation_duplicate_region_with_selection.cpp156
-rw-r--r--source/fuzz/transformation_duplicate_region_with_selection.h11
-rw-r--r--source/libspirv.cpp6
-rw-r--r--source/link/linker.cpp5
-rw-r--r--source/opcode.cpp21
-rw-r--r--source/opcode.h8
-rw-r--r--source/operand.cpp14
-rw-r--r--source/opt/CMakeLists.txt9
-rw-r--r--source/opt/aggressive_dead_code_elim_pass.cpp1
-rw-r--r--source/opt/basic_block.cpp2
-rw-r--r--source/opt/convert_to_half_pass.cpp12
-rw-r--r--source/opt/convert_to_half_pass.h2
-rw-r--r--source/opt/debug_info_manager.cpp8
-rw-r--r--source/opt/debug_info_manager.h11
-rw-r--r--source/opt/decompose_initialized_variables_pass.cpp112
-rw-r--r--source/opt/decompose_initialized_variables_pass.h57
-rw-r--r--source/opt/decoration_manager.cpp9
-rw-r--r--source/opt/decoration_manager.h11
-rw-r--r--source/opt/desc_sroa.cpp31
-rw-r--r--source/opt/desc_sroa.h5
-rw-r--r--source/opt/fix_storage_class.cpp10
-rw-r--r--source/opt/generate_webgpu_initializers_pass.cpp116
-rw-r--r--source/opt/generate_webgpu_initializers_pass.h62
-rw-r--r--source/opt/inline_pass.cpp7
-rw-r--r--source/opt/inst_bindless_check_pass.cpp44
-rw-r--r--source/opt/inst_bindless_check_pass.h1
-rw-r--r--source/opt/instruction.h12
-rw-r--r--source/opt/instruction_list.h2
-rw-r--r--source/opt/ir_loader.cpp11
-rw-r--r--source/opt/legalize_vector_shuffle_pass.cpp39
-rw-r--r--source/opt/legalize_vector_shuffle_pass.h53
-rw-r--r--source/opt/local_single_store_elim_pass.cpp2
-rw-r--r--source/opt/module.cpp2
-rw-r--r--source/opt/module.h14
-rw-r--r--source/opt/optimizer.cpp64
-rw-r--r--source/opt/passes.h5
-rw-r--r--source/opt/reflect.h4
-rw-r--r--source/opt/scalar_replacement_pass.cpp3
-rw-r--r--source/opt/split_invalid_unreachable_pass.cpp95
-rw-r--r--source/opt/split_invalid_unreachable_pass.h51
-rw-r--r--source/opt/ssa_rewrite_pass.cpp9
-rw-r--r--source/opt/strip_atomic_counter_memory_pass.cpp57
-rw-r--r--source/opt/strip_atomic_counter_memory_pass.h51
-rw-r--r--source/spirv_target_env.cpp61
-rw-r--r--source/spirv_target_env.h8
-rw-r--r--source/spirv_validator_options.cpp5
-rw-r--r--source/spirv_validator_options.h2
-rw-r--r--source/table.cpp1
-rw-r--r--source/val/validate.cpp77
-rw-r--r--source/val/validate_annotation.cpp69
-rw-r--r--source/val/validate_atomics.cpp14
-rw-r--r--source/val/validate_builtins.cpp698
-rw-r--r--source/val/validate_capability.cpp21
-rw-r--r--source/val/validate_cfg.cpp121
-rw-r--r--source/val/validate_composites.cpp8
-rw-r--r--source/val/validate_conversion.cpp38
-rw-r--r--source/val/validate_decorations.cpp85
-rw-r--r--source/val/validate_extensions.cpp24
-rw-r--r--source/val/validate_id.cpp2
-rw-r--r--source/val/validate_image.cpp311
-rw-r--r--source/val/validate_memory.cpp140
-rw-r--r--source/val/validate_memory_semantics.cpp55
-rw-r--r--source/val/validate_misc.cpp6
-rw-r--r--source/val/validate_mode_setting.cpp40
-rw-r--r--source/val/validate_non_uniform.cpp13
-rw-r--r--source/val/validate_scopes.cpp89
-rw-r--r--source/val/validate_type.cpp46
-rw-r--r--source/val/validation_state.cpp169
-rw-r--r--source/val/validation_state.h4
-rw-r--r--test/fuzz/transformation_duplicate_region_with_selection_test.cpp204
-rw-r--r--test/fuzzers/BUILD.gn46
-rw-r--r--test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp38
-rw-r--r--test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp38
-rw-r--r--test/fuzzers/spvtools_val_webgpu_fuzzer.cpp36
-rw-r--r--test/opt/CMakeLists.txt5
-rw-r--r--test/opt/convert_relaxed_to_half_test.cpp66
-rw-r--r--test/opt/debug_info_manager_test.cpp77
-rw-r--r--test/opt/decompose_initialized_variables_test.cpp252
-rw-r--r--test/opt/desc_sroa_test.cpp41
-rw-r--r--test/opt/fix_storage_class_test.cpp42
-rw-r--r--test/opt/generate_webgpu_initializers_test.cpp347
-rw-r--r--test/opt/inline_test.cpp57
-rw-r--r--test/opt/inst_bindless_check_test.cpp506
-rw-r--r--test/opt/legalize_vector_shuffle_test.cpp81
-rw-r--r--test/opt/local_single_store_elim_test.cpp6
-rw-r--r--test/opt/local_ssa_elim_test.cpp14
-rw-r--r--test/opt/optimizer_test.cpp592
-rw-r--r--test/opt/split_invalid_unreachable_test.cpp155
-rw-r--r--test/opt/strip_atomic_counter_memory_test.cpp406
-rw-r--r--test/target_env_test.cpp1
-rw-r--r--test/tools/opt/flags.py51
-rw-r--r--test/unit_spirv.h2
-rw-r--r--test/val/CMakeLists.txt1
-rw-r--r--test/val/val_atomics_test.cpp218
-rw-r--r--test/val/val_barriers_test.cpp262
-rw-r--r--test/val/val_builtins_test.cpp963
-rw-r--r--test/val/val_capability_test.cpp41
-rw-r--r--test/val/val_cfg_test.cpp426
-rw-r--r--test/val/val_code_generator.cpp65
-rw-r--r--test/val/val_code_generator.h1
-rw-r--r--test/val/val_conversion_test.cpp91
-rw-r--r--test/val/val_data_test.cpp210
-rw-r--r--test/val/val_decoration_test.cpp647
-rw-r--r--test/val/val_fixtures.h39
-rw-r--r--test/val/val_id_test.cpp115
-rw-r--r--test/val/val_image_test.cpp1295
-rw-r--r--test/val/val_layout_test.cpp51
-rw-r--r--test/val/val_memory_test.cpp664
-rw-r--r--test/val/val_misc_test.cpp24
-rw-r--r--test/val/val_modes_test.cpp57
-rw-r--r--test/val/val_non_uniform_test.cpp38
-rw-r--r--test/val/val_opencl_test.cpp267
-rw-r--r--test/val/val_storage_test.cpp64
-rw-r--r--test/val/val_validation_state_test.cpp78
-rw-r--r--test/val/val_version_test.cpp22
-rw-r--r--test/val/val_webgpu_test.cpp424
-rw-r--r--tools/link/linker.cpp99
-rw-r--r--tools/opt/opt.cpp114
-rw-r--r--tools/sva/yarn.lock6
-rw-r--r--tools/val/val.cpp8
-rwxr-xr-xutils/check_copyright.py2
-rwxr-xr-xutils/git-sync-deps2
148 files changed, 5632 insertions, 7656 deletions
diff --git a/Android.mk b/Android.mk
index 0b64ea6d..1000f422 100644
--- a/Android.mk
+++ b/Android.mk
@@ -93,7 +93,6 @@ SPVTOOLS_OPT_SRC_FILES := \
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 @@ SPVTOOLS_OPT_SRC_FILES := \
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 @@ SPVTOOLS_OPT_SRC_FILES := \
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 @@ SPVTOOLS_OPT_SRC_FILES := \
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 2387fc6a..845eb29e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -539,8 +539,6 @@ static_library("spvtools_opt") {
"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 @@ static_library("spvtools_opt") {
"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 @@ static_library("spvtools_opt") {
"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 @@ static_library("spvtools_opt") {
"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 7ad7b661..19eb18c4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,11 +1,65 @@
Revision history for SPIRV-Tools
-v2020.6-dev 2020-12-02
+v2021.0-dev 2021-02-16
+ - Start SPIRV-Tools v2021.0-dev
+
+v2020.7 2021-02-16
+ - General
+ - Support pending Intel extensions (#4116)
+ - Remove WebGPU support (#4108)
+ - Validator
+ - Vulkan image gather constant component (#4133)
+ - Add Vulkan PSB64 convert VUID (#4122)
+ - Validate SPV_KHR_workgroup_memory_explicit_layout (#4128)
+ - Validate VK_KHR_zero_initialize_workgroup_memory (#4124)
+ - Add Vulkan image gather offset VUID (#4118)
+ - Label Vulkan atomic semantics VUIDs (#4120)
+ - Label VUID 04662 (#4123)
+ - Label VUID 04683 (#4121)
+ - Add Vulkan EXT builtins (#4115)
+ - Validate Sampled=1 for Vulkan ImageQuerySizeLod, ImageQueryLevels, ImageQueryLod (#4103)
+ - Add Vulkan Memory Scope VUs (#4106)
+ - Add Vulkan Addressing Model check (#4107)
+ - Vulkan atomic storage class (#4079)
+ - Label standalone Vulkan VUID (#4091)
+ - Add Vulkan decroation VUID (#4090)
+ - Add Vulkan FP Mode VUID (#4088)
+ - Fix Vulkan image sampled check (#4085)
+ - Add Vulkan ForwardPointer VUID (#4089)
+ - Add Vulkan ImageTexelPointer format check (#4087)
+ - Add Vulkan Group Operation VUID (#4086)
+ - Add first StandAlone VUID 04633 (#4077)
+ - Add Subgroup VUIDs (#4074)
+ - validate return type of OpImageRead (#4072)
+ - tighter validation of multisampled images (#4059)
+ - validate OpTypeImage Sampled values for environemnts (#4064)
+ - validate StorageImageMultisampled capability (#4062)
+ - Add last TessLevelOuter and TessLevelInner VUID (#4055)
+ - Add last ClipDistance and CullDistance VUID (#4054)
+ - Add last ViewportIndex and Layer VUID (#4053)
+ - Add last Position VUID (#4052)
+ - Allow forward pointer to be used in types generally (#4044)
+ - Optimizer
+ - Mark module as modified if convert-to-half removes decorations. (#4127)
+ - Fix binding number calculation in desc sroa (#4095)
+ - Run DCE when SPV_KHR_shader_clock is used (#4049)
+ - Debug Info
+ - Set correct scope and line info for DebugValue (#4125)
+ - Avoid integrity check failures caused by propagating line instructions (#4096)
+ - Linker
+ - Linker usability improvements (#4084)
+ - Instrumentation
+ - Generate differentiated error codes for buffer oob checking (#4097)
+ - Fuzz
+ - Fix OpPhi handling in DuplicateRegionWithSelection (#4065)
+
+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)
diff --git a/DEPS b/DEPS
index 3762681d..75581c5a 100644
--- a/DEPS
+++ b/DEPS
@@ -6,7 +6,7 @@ vars = {
'effcee_revision': '2ec8f8738118cc483b67c04a759fee53496c5659',
'googletest_revision': '3af06fe1664d30f98de1e78c53a7087e842a2547',
're2_revision': 'ca11026a032ce2a3de4b3c389ee53d2bdc8794d6',
- 'spirv_headers_revision': 'f027d53ded7e230e008d37c8b47ede7cd308e19d',
+ 'spirv_headers_revision': 'faa570afbc91ac73d594d787486bcf8f2df1ace0',
}
deps = {
diff --git a/README.md b/README.md
index 44f582fb..3637305b 100644
--- a/README.md
+++ b/README.md
@@ -136,7 +136,6 @@ As of this writing, there are 67 transforms including examples such as:
* 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 d7ccd349..4e664659 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/build_overrides/build.gni b/build_overrides/build.gni
index 833fcd34..cf3d6b79 100644
--- a/build_overrides/build.gni
+++ b/build_overrides/build.gni
@@ -16,9 +16,6 @@
# Chromium specific targets in a client project's GN file etc.
build_with_chromium = false
-# Don't use Chromium's third_party/binutils.
-linux_use_bundled_binutils_override = false
-
declare_args() {
# Android 32-bit non-component, non-clang builds cannot have symbol_level=2
# due to 4GiB file size limit, see https://crbug.com/648948.
diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp
index 2b47a564..05a0472e 100644
--- a/include/spirv-tools/instrument.hpp
+++ b/include/spirv-tools/instrument.hpp
@@ -170,7 +170,10 @@ static const int kInstMaxOutCnt = kInstStageOutCnt + 4;
static const int kInstErrorBindlessBounds = 0;
static const int kInstErrorBindlessUninit = 1;
static const int kInstErrorBuffAddrUnallocRef = 2;
-static const int kInstErrorBindlessBuffOOB = 3;
+// Deleted: static const int kInstErrorBindlessBuffOOB = 3;
+// This comment will will remain for 2 releases to allow
+// for the transition of all builds. Buffer OOB is
+// generating the following four differentiated codes instead:
static const int kInstErrorBuffOOBUniform = 4;
static const int kInstErrorBuffOOBStorage = 5;
static const int kInstErrorBuffOOBUniformTexel = 6;
diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h
index a0114c3f..658c4dd5 100644
--- a/include/spirv-tools/libspirv.h
+++ b/include/spirv-tools/libspirv.h
@@ -260,6 +260,11 @@ typedef enum spv_operand_type_t {
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 @@ typedef enum {
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.
@@ -620,6 +625,12 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetUniformBufferStandardLayout(
SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetScalarBlockLayout(
spv_validator_options options, bool val);
+// Records whether the validator should use "scalar" block layout
+// rules (as defined above) for Workgroup blocks. See Vulkan
+// extension VK_KHR_workgroup_memory_explicit_layout.
+SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetWorkgroupScalarBlockLayout(
+ spv_validator_options options, bool val);
+
// Records whether or not the validator should skip validating standard
// uniform/storage block layout.
SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetSkipBlockLayout(
diff --git a/include/spirv-tools/libspirv.hpp b/include/spirv-tools/libspirv.hpp
index 2018e461..e7e7fc7a 100644
--- a/include/spirv-tools/libspirv.hpp
+++ b/include/spirv-tools/libspirv.hpp
@@ -104,6 +104,12 @@ class ValidatorOptions {
spvValidatorOptionsSetScalarBlockLayout(options_, val);
}
+ // Enables scalar layout when validating Workgroup blocks. See
+ // VK_KHR_workgroup_memory_explicit_layout.
+ void SetWorkgroupScalarBlockLayout(bool val) {
+ spvValidatorOptionsSetWorkgroupScalarBlockLayout(options_, val);
+ }
+
// Skips validating standard uniform/storage buffer/push-constant layout.
void SetSkipBlockLayout(bool val) {
spvValidatorOptionsSetSkipBlockLayout(options_, val);
diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
index 27352b25..1683d077 100644
--- a/include/spirv-tools/optimizer.hpp
+++ b/include/spirv-tools/optimizer.hpp
@@ -68,11 +68,6 @@ class Optimizer {
// 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 @@ class Optimizer {
// 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 @@ class Optimizer {
// 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.
@@ -802,30 +780,11 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass();
// 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
index c05c139a..22c9117a 100644..100755
--- a/kokoro/android/build.sh
+++ b/kokoro/android/build.sh
@@ -20,33 +20,5 @@ set -e
# 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
index 8f86e6ec..5cca362d 100644..100755
--- a/kokoro/linux-clang-asan/build.sh
+++ b/kokoro/linux-clang-asan/build.sh
@@ -21,4 +21,4 @@ set -e
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
index 11b2968a..785a6e3b 100644..100755
--- a/kokoro/linux-clang-debug/build.sh
+++ b/kokoro/linux-clang-debug/build.sh
@@ -21,4 +21,4 @@ set -e
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
index 05a9bbb4..238ef52b 100644..100755
--- a/kokoro/linux-clang-release-bazel/build.sh
+++ b/kokoro/linux-clang-release-bazel/build.sh
@@ -20,24 +20,5 @@ set -e
# 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
index 47643317..6a9e0136 100644..100755
--- a/kokoro/linux-clang-release/build.sh
+++ b/kokoro/linux-clang-release/build.sh
@@ -21,4 +21,4 @@ set -e
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
index 3ef1e251..c60447e3 100644..100755
--- a/kokoro/linux-gcc-debug/build.sh
+++ b/kokoro/linux-gcc-debug/build.sh
@@ -21,4 +21,4 @@ set -e
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
index 3e97d8d3..441ab728 100644..100755
--- a/kokoro/linux-gcc-release/build.sh
+++ b/kokoro/linux-gcc-release/build.sh
@@ -21,4 +21,4 @@ set -e
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
index f1f167d8..89c55659 100644..100755
--- a/kokoro/ndk-build/build.sh
+++ b/kokoro/ndk-build/build.sh
@@ -20,38 +20,5 @@ set -e
# 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 00000000..ba216987
--- /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 347f353a..4731ebdc 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.
-
-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
+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"
+
+
+# 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
+}
+
+chown_dir "${ROOT_DIR}/build"
+chown_dir "${ROOT_DIR}/external"
diff --git a/kokoro/scripts/windows/build.bat b/kokoro/scripts/windows/build.bat
index fa7a71a0..a4ce792a 100644
--- a/kokoro/scripts/windows/build.bat
+++ b/kokoro/scripts/windows/build.bat
@@ -22,7 +22,7 @@ set BUILD_TYPE=%1
set VS_VERSION=%2
:: Force usage of python 3.6
-set PATH=C:\python36;%PATH%
+set PATH=C:\python36;"C:\Program Files\CMake\bin";%PATH%
cd %SRC%
git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers
diff --git a/kokoro/shaderc-smoketest/build.sh b/kokoro/shaderc-smoketest/build.sh
index 0856c9b2..60c816d4 100644..100755
--- a/kokoro/shaderc-smoketest/build.sh
+++ b/kokoro/shaderc-smoketest/build.sh
@@ -18,54 +18,5 @@ set -e
# 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 75a997d3..7448721b 100644
--- a/source/binary.cpp
+++ b/source/binary.cpp
@@ -655,7 +655,9 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
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 e7632512..966a59c7 100644
--- a/source/disassemble.cpp
+++ b/source/disassemble.cpp
@@ -326,7 +326,9 @@ void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst,
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 3471ebe0..795cb0f3 100644
--- a/source/ext_inst.cpp
+++ b/source/ext_inst.cpp
@@ -89,7 +89,6 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable,
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 07758cd3..2ac6259d 100644
--- a/source/fuzz/transformation_duplicate_region_with_selection.cpp
+++ b/source/fuzz/transformation_duplicate_region_with_selection.cpp
@@ -209,7 +209,7 @@ bool TransformationDuplicateRegionWithSelection::IsApplicable(
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 @@ bool TransformationDuplicateRegionWithSelection::IsApplicable(
return false;
}
}
- for (auto instr : *block) {
+ for (auto& instr : *block) {
if (!instr.HasResultId()) {
continue;
}
@@ -228,7 +228,7 @@ bool TransformationDuplicateRegionWithSelection::IsApplicable(
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 @@ bool TransformationDuplicateRegionWithSelection::IsApplicable(
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,
+ &region_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 @@ void TransformationDuplicateRegionWithSelection::Apply(
{block->id(),
transformation_context->GetOverflowIdSource()->GetNextOverflowId()});
}
- for (auto instr : *block) {
+ for (auto& instr : *block) {
if (!instr.HasResultId()) {
continue;
}
@@ -338,9 +343,8 @@ void TransformationDuplicateRegionWithSelection::Apply(
{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 @@ void TransformationDuplicateRegionWithSelection::Apply(
}
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 @@ void TransformationDuplicateRegionWithSelection::Apply(
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 @@ void TransformationDuplicateRegionWithSelection::Apply(
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 @@ void TransformationDuplicateRegionWithSelection::Apply(
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 @@ void TransformationDuplicateRegionWithSelection::Apply(
{{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 @@ TransformationDuplicateRegionWithSelection::GetFreshIds() const {
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 d6f0ad9a..a2b9a433 100644
--- a/source/fuzz/transformation_duplicate_region_with_selection.h
+++ b/source/fuzz/transformation_duplicate_region_with_selection.h
@@ -66,6 +66,17 @@ class TransformationDuplicateRegionWithSelection : public Transformation {
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 a1ed11d3..0bc09350 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 @@ struct SpirvTools::Impl {
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 da6f0a78..8da4a98d 100644
--- a/source/link/linker.cpp
+++ b/source/link/linker.cpp
@@ -676,14 +676,15 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries,
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 c80e3a00..d87e8287 100644
--- a/source/opcode.cpp
+++ b/source/opcode.cpp
@@ -444,15 +444,32 @@ bool spvOpcodeIsReturn(SpvOp opcode) {
}
}
+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 3702cb35..c8525a25 100644
--- a/source/opcode.h
+++ b/source/opcode.h
@@ -110,10 +110,18 @@ bool spvOpcodeIsBranch(SpvOp opcode);
// 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 d4b64a8b..5a69fb24 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 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
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 @@ bool spvOperandIsConcrete(spv_operand_type_t 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_FPDENORM_MODE:
+ case SPV_OPERAND_TYPE_FPOPERATION_MODE:
return true;
default:
break;
@@ -491,6 +499,11 @@ bool spvIsInIdType(spv_operand_type_t type) {
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 @@ std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
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 f3ac5906..14a6bee7 100644
--- a/source/opt/CMakeLists.txt
+++ b/source/opt/CMakeLists.txt
@@ -32,7 +32,6 @@ set(SPIRV_TOOLS_OPT_SOURCES
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 @@ set(SPIRV_TOOLS_OPT_SOURCES
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 @@ set(SPIRV_TOOLS_OPT_SOURCES
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 @@ set(SPIRV_TOOLS_OPT_SOURCES
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 @@ set(SPIRV_TOOLS_OPT_SOURCES
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 @@ set(SPIRV_TOOLS_OPT_SOURCES
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 @@ set(SPIRV_TOOLS_OPT_SOURCES
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 94451a29..81b2232f 100644
--- a/source/opt/aggressive_dead_code_elim_pass.cpp
+++ b/source/opt/aggressive_dead_code_elim_pass.cpp
@@ -995,6 +995,7 @@ void AggressiveDCEPass::InitExtensions() {
"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 b7e122c4..e82a744a 100644
--- a/source/opt/basic_block.cpp
+++ b/source/opt/basic_block.cpp
@@ -230,7 +230,7 @@ std::string BasicBlock::PrettyPrint(uint32_t options) const {
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/convert_to_half_pass.cpp b/source/opt/convert_to_half_pass.cpp
index 5022e1b6..6b3b540a 100644
--- a/source/opt/convert_to_half_pass.cpp
+++ b/source/opt/convert_to_half_pass.cpp
@@ -147,8 +147,8 @@ bool ConvertToHalfPass::MatConvertCleanup(Instruction* inst) {
return true;
}
-void ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) {
- context()->get_decoration_mgr()->RemoveDecorationsFrom(
+bool ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) {
+ return context()->get_decoration_mgr()->RemoveDecorationsFrom(
id, [](const Instruction& dec) {
if (dec.opcode() == SpvOpDecorate &&
dec.GetSingleWordInOperand(1u) == SpvDecorationRelaxedPrecision)
@@ -344,10 +344,14 @@ Pass::Status ConvertToHalfPass::ProcessImpl() {
// If modified, make sure module has Float16 capability
if (modified) context()->AddCapability(SpvCapabilityFloat16);
// Remove all RelaxedPrecision decorations from instructions and globals
- for (auto c_id : relaxed_ids_set_) RemoveRelaxedDecoration(c_id);
+ for (auto c_id : relaxed_ids_set_) {
+ modified |= RemoveRelaxedDecoration(c_id);
+ }
for (auto& val : get_module()->types_values()) {
uint32_t v_id = val.result_id();
- if (v_id != 0) RemoveRelaxedDecoration(v_id);
+ if (v_id != 0) {
+ modified |= RemoveRelaxedDecoration(v_id);
+ }
}
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
diff --git a/source/opt/convert_to_half_pass.h b/source/opt/convert_to_half_pass.h
index 143aebfa..b647dd4a 100644
--- a/source/opt/convert_to_half_pass.h
+++ b/source/opt/convert_to_half_pass.h
@@ -74,7 +74,7 @@ class ConvertToHalfPass : public Pass {
void GenConvert(uint32_t* val_idp, uint32_t width, Instruction* inst);
// Remove RelaxedPrecision decoration of |id|.
- void RemoveRelaxedDecoration(uint32_t id);
+ bool RemoveRelaxedDecoration(uint32_t id);
// Add |inst| to relaxed instruction set if warranted. Specifically, if
// it is float32 and either decorated relaxed or a composite or phi
diff --git a/source/opt/debug_info_manager.cpp b/source/opt/debug_info_manager.cpp
index 11b5131d..e782641f 100644
--- a/source/opt/debug_info_manager.cpp
+++ b/source/opt/debug_info_manager.cpp
@@ -500,14 +500,15 @@ bool DebugInfoManager::AddDebugValueIfVarDeclIsVisible(
insert_before->opcode() == SpvOpVariable) {
insert_before = insert_before->NextNode();
}
- modified |= AddDebugValueForDecl(dbg_decl_or_val, value_id,
- insert_before) != nullptr;
+ modified |= AddDebugValueForDecl(dbg_decl_or_val, value_id, insert_before,
+ scope_and_line) != nullptr;
}
return modified;
}
Instruction* DebugInfoManager::AddDebugValueForDecl(
- Instruction* dbg_decl, uint32_t value_id, Instruction* insert_before) {
+ Instruction* dbg_decl, uint32_t value_id, Instruction* insert_before,
+ Instruction* scope_and_line) {
if (dbg_decl == nullptr || !IsDebugDeclare(dbg_decl)) return nullptr;
std::unique_ptr<Instruction> dbg_val(dbg_decl->Clone(context()));
@@ -517,6 +518,7 @@ Instruction* DebugInfoManager::AddDebugValueForDecl(
dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id});
dbg_val->SetOperand(kDebugValueOperandExpressionIndex,
{GetEmptyDebugExpression()->result_id()});
+ dbg_val->UpdateDebugInfoFrom(scope_and_line);
auto* added_dbg_val = insert_before->InsertBefore(std::move(dbg_val));
AnalyzeDebugInst(added_dbg_val);
diff --git a/source/opt/debug_info_manager.h b/source/opt/debug_info_manager.h
index 92b38183..776e9baa 100644
--- a/source/opt/debug_info_manager.h
+++ b/source/opt/debug_info_manager.h
@@ -152,11 +152,14 @@ class DebugInfoManager {
std::unordered_set<Instruction*>* invisible_decls);
// Creates a DebugValue for DebugDeclare |dbg_decl| and inserts it before
- // |insert_before|. The new DebugValue has the same line, scope, and
- // operands with DebugDeclare but it uses |value_id| for value. Returns
- // the added DebugValue, or nullptr if it does not add a DebugValue.
+ // |insert_before|. The new DebugValue has the same line and scope as
+ // |scope_and_line|, or no scope and line information if |scope_and_line|
+ // is nullptr. The new DebugValue has the same operands as DebugDeclare
+ // but it uses |value_id| for the value. Returns the created DebugValue,
+ // or nullptr if fails to create one.
Instruction* AddDebugValueForDecl(Instruction* dbg_decl, uint32_t value_id,
- Instruction* insert_before);
+ Instruction* insert_before,
+ Instruction* scope_and_line);
// Erases |instr| from data structures of this class.
void ClearDebugInfo(Instruction* instr);
diff --git a/source/opt/decompose_initialized_variables_pass.cpp b/source/opt/decompose_initialized_variables_pass.cpp
deleted file mode 100644
index 875bf7e8..00000000
--- 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 c0bd35e7..00000000
--- 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/decoration_manager.cpp b/source/opt/decoration_manager.cpp
index 8b4aee58..4bf026ef 100644
--- a/source/opt/decoration_manager.cpp
+++ b/source/opt/decoration_manager.cpp
@@ -53,11 +53,12 @@ namespace spvtools {
namespace opt {
namespace analysis {
-void DecorationManager::RemoveDecorationsFrom(
+bool DecorationManager::RemoveDecorationsFrom(
uint32_t id, std::function<bool(const Instruction&)> pred) {
+ bool was_modified = false;
const auto ids_iter = id_to_decoration_insts_.find(id);
if (ids_iter == id_to_decoration_insts_.end()) {
- return;
+ return was_modified;
}
TargetData& decorations_info = ids_iter->second;
@@ -99,7 +100,6 @@ void DecorationManager::RemoveDecorationsFrom(
// Otherwise, remove |id| from the targets of |group_id|
const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
- bool was_modified = false;
for (uint32_t i = 1u; i < inst->NumInOperands();) {
if (inst->GetSingleWordInOperand(i) != id) {
i += stride;
@@ -155,6 +155,7 @@ void DecorationManager::RemoveDecorationsFrom(
}),
indirect_decorations.end());
+ was_modified |= !insts_to_kill.empty();
for (Instruction* inst : insts_to_kill) context->KillInst(inst);
insts_to_kill.clear();
@@ -165,6 +166,7 @@ void DecorationManager::RemoveDecorationsFrom(
for (Instruction* inst : decorations_info.decorate_insts)
insts_to_kill.push_back(inst);
}
+ was_modified |= !insts_to_kill.empty();
for (Instruction* inst : insts_to_kill) context->KillInst(inst);
if (decorations_info.direct_decorations.empty() &&
@@ -172,6 +174,7 @@ void DecorationManager::RemoveDecorationsFrom(
decorations_info.decorate_insts.empty()) {
id_to_decoration_insts_.erase(ids_iter);
}
+ return was_modified;
}
std::vector<Instruction*> DecorationManager::GetDecorationsFor(
diff --git a/source/opt/decoration_manager.h b/source/opt/decoration_manager.h
index e1ae8d57..b753e6be 100644
--- a/source/opt/decoration_manager.h
+++ b/source/opt/decoration_manager.h
@@ -36,8 +36,9 @@ class DecorationManager {
}
DecorationManager() = delete;
- // Changes all of the decorations (direct and through groups) where |pred| is
- // true and that apply to |id| so that they no longer apply to |id|.
+ // Removes all decorations (direct and through groups) where |pred| is
+ // true and that apply to |id| so that they no longer apply to |id|. Returns
+ // true if something changed.
//
// If |id| is part of a group, it will be removed from the group if it
// does not use all of the group's decorations, or, if there are no
@@ -52,9 +53,9 @@ class DecorationManager {
// removed, then the |OpGroupDecorate| and
// |OpGroupMemberDecorate| for the group will be killed, but not the defining
// |OpDecorationGroup| instruction.
- void RemoveDecorationsFrom(uint32_t id,
- std::function<bool(const Instruction&)> pred =
- [](const Instruction&) { return true; });
+ bool RemoveDecorationsFrom(
+ uint32_t id, std::function<bool(const Instruction&)> pred =
+ [](const Instruction&) { return true; });
// Removes all decorations from the result id of |inst|.
//
diff --git a/source/opt/desc_sroa.cpp b/source/opt/desc_sroa.cpp
index b68549a0..5e950069 100644
--- a/source/opt/desc_sroa.cpp
+++ b/source/opt/desc_sroa.cpp
@@ -63,16 +63,7 @@ bool DescriptorScalarReplacement::IsCandidate(Instruction* var) {
// 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 @@ bool DescriptorScalarReplacement::IsCandidate(Instruction* var) {
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 @@ uint32_t DescriptorScalarReplacement::GetNumBindingsUsedByType(
// 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 c3aa0ea2..cd72fd30 100644
--- a/source/opt/desc_sroa.h
+++ b/source/opt/desc_sroa.h
@@ -93,6 +93,11 @@ class DescriptorScalarReplacement : public Pass {
// 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/fix_storage_class.cpp b/source/opt/fix_storage_class.cpp
index 03da0d0d..04eb1326 100644
--- a/source/opt/fix_storage_class.cpp
+++ b/source/opt/fix_storage_class.cpp
@@ -222,6 +222,16 @@ bool FixStorageClass::PropagateType(Instruction* inst, uint32_t type_id,
uint32_t pointee_type_id = GetPointeeTypeId(ptr_inst);
if (obj_type_id != pointee_type_id) {
+ if (context()->get_type_mgr()->GetType(obj_type_id)->AsImage() &&
+ context()->get_type_mgr()->GetType(pointee_type_id)->AsImage()) {
+ // When storing an image, allow the type mismatch
+ // and let the later legalization passes eliminate the OpStore.
+ // This is to support assigning an image to a variable,
+ // where the assigned image does not have a pre-defined
+ // image format.
+ return false;
+ }
+
uint32_t copy_id = GenerateCopy(obj_inst, pointee_type_id, inst);
inst->SetInOperand(1, {copy_id});
context()->UpdateDefUse(inst);
diff --git a/source/opt/generate_webgpu_initializers_pass.cpp b/source/opt/generate_webgpu_initializers_pass.cpp
deleted file mode 100644
index eaed3c28..00000000
--- 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 f95e84c5..00000000
--- 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_pass.cpp b/source/opt/inline_pass.cpp
index 88f395f0..8159ebf7 100644
--- a/source/opt/inline_pass.cpp
+++ b/source/opt/inline_pass.cpp
@@ -383,9 +383,7 @@ std::unique_ptr<BasicBlock> InlinePass::InlineReturn(
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;
}
@@ -759,8 +757,7 @@ bool InlinePass::IsInlinableFunction(Function* func) {
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 00857343..5607239a 100644
--- a/source/opt/inst_bindless_check_pass.cpp
+++ b/source/opt/inst_bindless_check_pass.cpp
@@ -27,13 +27,16 @@ static const int kSpvCopyObjectOperandIdInIdx = 0;
static const int kSpvLoadPtrIdInIdx = 0;
static const int kSpvAccessChainBaseIdInIdx = 0;
static const int kSpvAccessChainIndex0IdInIdx = 1;
+static const int kSpvTypeArrayTypeIdInIdx = 0;
static const int kSpvTypeArrayLengthIdInIdx = 1;
static const int kSpvConstantValueInIdx = 0;
static const int kSpvVariableStorageClassInIdx = 0;
+static const int kSpvTypePtrTypeIdInIdx = 1;
static const int kSpvTypeImageDim = 1;
static const int kSpvTypeImageDepth = 2;
static const int kSpvTypeImageArrayed = 3;
static const int kSpvTypeImageMS = 4;
+static const int kSpvTypeImageSampled = 5;
} // anonymous namespace
// Avoid unused variable warning/error on Linux
@@ -206,13 +209,40 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx);
switch (storage_class) {
case SpvStorageClassUniform:
- case SpvStorageClassUniformConstant:
case SpvStorageClassStorageBuffer:
break;
default:
return false;
break;
}
+ // Check for deprecated storage block form
+ if (storage_class == SpvStorageClassUniform) {
+ uint32_t var_ty_id = var_inst->type_id();
+ Instruction* var_ty_inst = get_def_use_mgr()->GetDef(var_ty_id);
+ uint32_t ptr_ty_id =
+ var_ty_inst->GetSingleWordInOperand(kSpvTypePtrTypeIdInIdx);
+ Instruction* ptr_ty_inst = get_def_use_mgr()->GetDef(ptr_ty_id);
+ SpvOp ptr_ty_op = ptr_ty_inst->opcode();
+ uint32_t block_ty_id =
+ (ptr_ty_op == SpvOpTypeArray || ptr_ty_op == SpvOpTypeRuntimeArray)
+ ? ptr_ty_inst->GetSingleWordInOperand(kSpvTypeArrayTypeIdInIdx)
+ : ptr_ty_id;
+ assert(get_def_use_mgr()->GetDef(block_ty_id)->opcode() ==
+ SpvOpTypeStruct &&
+ "unexpected block type");
+ bool block_found = get_decoration_mgr()->FindDecoration(
+ block_ty_id, SpvDecorationBlock,
+ [](const Instruction&) { return true; });
+ if (!block_found) {
+ // If block decoration not found, verify deprecated form of SSBO
+ bool buffer_block_found = get_decoration_mgr()->FindDecoration(
+ block_ty_id, SpvDecorationBufferBlock,
+ [](const Instruction&) { return true; });
+ USE_ASSERT(buffer_block_found && "block decoration not found");
+ storage_class = SpvStorageClassStorageBuffer;
+ }
+ }
+ ref->strg_class = storage_class;
Instruction* desc_type_inst = GetPointeeTypeInst(var_inst);
switch (desc_type_inst->opcode()) {
case SpvOpTypeArray:
@@ -665,8 +695,10 @@ void InstBindlessCheckPass::GenDescInitCheckCode(
// for the referenced value.
Instruction* ult_inst =
builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, ref_id, init_id);
- uint32_t error =
- init_check ? kInstErrorBindlessUninit : kInstErrorBindlessBuffOOB;
+ uint32_t error = init_check ? kInstErrorBindlessUninit
+ : (ref.strg_class == SpvStorageClassUniform
+ ? kInstErrorBuffOOBUniform
+ : kInstErrorBuffOOBStorage);
uint32_t error_id = builder.GetUintConstantId(error);
GenCheckCode(ult_inst->result_id(), error_id, init_check ? 0 : ref_id,
init_check ? builder.GetUintConstantId(0u) : init_id, stage_idx,
@@ -732,7 +764,11 @@ void InstBindlessCheckPass::GenTexBuffCheckCode(
// for the referenced value.
Instruction* ult_inst =
builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, coord_id, size_id);
- uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBuffOOB);
+ uint32_t error =
+ (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageSampled) == 2)
+ ? kInstErrorBuffOOBStorageTexel
+ : kInstErrorBuffOOBUniformTexel;
+ uint32_t error_id = builder.GetUintConstantId(error);
GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_id, stage_idx,
&ref, new_blocks);
// Move original block's remaining code into remainder/merge block and add
diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h
index a7dff75f..cd961805 100644
--- a/source/opt/inst_bindless_check_pass.h
+++ b/source/opt/inst_bindless_check_pass.h
@@ -130,6 +130,7 @@ class InstBindlessCheckPass : public InstrumentPass {
uint32_t ptr_id;
uint32_t var_id;
uint32_t desc_idx_id;
+ uint32_t strg_class;
Instruction* ref_inst;
} RefAnalysis;
diff --git a/source/opt/instruction.h b/source/opt/instruction.h
index 252e8cb5..3e557dd7 100644
--- a/source/opt/instruction.h
+++ b/source/opt/instruction.h
@@ -97,10 +97,14 @@ struct Operand {
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;
}
@@ -205,7 +209,7 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
Instruction(Instruction&&);
Instruction& operator=(Instruction&&);
- virtual ~Instruction() = default;
+ ~Instruction() override = default;
// Returns a newly allocated instruction that has the same operands, result,
// and type as |this|. The new instruction is not linked into any list.
diff --git a/source/opt/instruction_list.h b/source/opt/instruction_list.h
index 417cbd76..b3e42745 100644
--- a/source/opt/instruction_list.h
+++ b/source/opt/instruction_list.h
@@ -53,7 +53,7 @@ class InstructionList : public utils::IntrusiveList<Instruction> {
}
// Destroy this list and any instructions in the list.
- inline virtual ~InstructionList();
+ inline ~InstructionList() override;
class iterator : public utils::IntrusiveList<Instruction>::iterator {
public:
diff --git a/source/opt/ir_loader.cpp b/source/opt/ir_loader.cpp
index 06099ce0..e443ebb5 100644
--- a/source/opt/ir_loader.cpp
+++ b/source/opt/ir_loader.cpp
@@ -41,6 +41,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
++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 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
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 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
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;
}
}
@@ -137,7 +138,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
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/legalize_vector_shuffle_pass.cpp b/source/opt/legalize_vector_shuffle_pass.cpp
deleted file mode 100644
index b5d5d599..00000000
--- 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 ca6e1dfb..00000000
--- 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/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp
index b8d9091a..d322a2fb 100644
--- a/source/opt/local_single_store_elim_pass.cpp
+++ b/source/opt/local_single_store_elim_pass.cpp
@@ -175,7 +175,7 @@ bool LocalSingleStoreElimPass::RewriteDebugDeclares(Instruction* store_inst,
for (auto* decl : invisible_decls) {
if (dominator_analysis->Dominates(store_inst, decl)) {
context()->get_debug_info_mgr()->AddDebugValueForDecl(decl, value_id,
- decl);
+ decl, store_inst);
modified = true;
}
}
diff --git a/source/opt/module.cpp b/source/opt/module.cpp
index 9d3b0edc..0c886010 100644
--- a/source/opt/module.cpp
+++ b/source/opt/module.cpp
@@ -188,7 +188,7 @@ void Module::ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const {
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 2c96f029..d609b603 100644
--- a/source/opt/module.h
+++ b/source/opt/module.h
@@ -49,7 +49,7 @@ class Module {
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 @@ class Module {
// 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.
@@ -301,8 +301,8 @@ class Module {
// 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|.
@@ -364,7 +364,7 @@ inline void Module::AddFunction(std::unique_ptr<Function> f) {
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 8726ff93..909442cc 100644
--- a/source/opt/optimizer.cpp
+++ b/source/opt/optimizer.cpp
@@ -62,7 +62,9 @@ struct Optimizer::Impl {
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 @@ Optimizer& Optimizer::RegisterSizePasses() {
.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 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
//
// 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());
@@ -505,14 +488,6 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
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 @@ bool Optimizer::Run(const uint32_t* original_binary,
#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 @@ Optimizer::PassToken CreateNullPass() {
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>());
@@ -929,31 +901,11 @@ Optimizer::PassToken CreateCodeSinkingPass() {
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 d47cc1ce..1bc94c7e 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 d374e682..c7d46df5 100644
--- a/source/opt/reflect.h
+++ b/source/opt/reflect.h
@@ -59,10 +59,6 @@ inline bool IsCompileTimeConstantInst(SpvOp opcode) {
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/scalar_replacement_pass.cpp b/source/opt/scalar_replacement_pass.cpp
index c8e0da5b..ba2d0675 100644
--- a/source/opt/scalar_replacement_pass.cpp
+++ b/source/opt/scalar_replacement_pass.cpp
@@ -175,7 +175,8 @@ bool ScalarReplacementPass::ReplaceWholeDebugDeclare(
Instruction* added_dbg_value =
context()->get_debug_info_mgr()->AddDebugValueForDecl(
dbg_decl, /*value_id=*/var->result_id(),
- /*insert_before=*/var->NextNode());
+ /*insert_before=*/var->NextNode(), /*scope_and_line=*/dbg_decl);
+
if (added_dbg_value == nullptr) return false;
added_dbg_value->AddOperand(
{SPV_OPERAND_TYPE_ID,
diff --git a/source/opt/split_invalid_unreachable_pass.cpp b/source/opt/split_invalid_unreachable_pass.cpp
deleted file mode 100644
index 31cfbc33..00000000
--- 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 a5613448..00000000
--- 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/ssa_rewrite_pass.cpp b/source/opt/ssa_rewrite_pass.cpp
index 0489f03a..81770d77 100644
--- a/source/opt/ssa_rewrite_pass.cpp
+++ b/source/opt/ssa_rewrite_pass.cpp
@@ -658,8 +658,8 @@ Pass::Status SSARewriter::AddDebugValuesForInvisibleDebugDecls(Function* fp) {
// a = 3;
// foo(3);
// After inlining:
- // a = 3; // we want to specify "DebugValue: %x = %int_3"
- // foo and x disappeared!
+ // a = 3;
+ // foo and x disappeared but we want to specify "DebugValue: %x = %int_3".
//
// We want to specify the value for the variable using |defs_at_block_[bb]|,
// where |bb| is the basic block contains the decl.
@@ -681,16 +681,17 @@ Pass::Status SSARewriter::AddDebugValuesForInvisibleDebugDecls(Function* fp) {
if (value && (pass_->context()->get_instr_block(value) == nullptr ||
dom_tree->Dominates(value, decl))) {
if (pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl(
- decl, value->result_id(), decl) == nullptr) {
+ decl, value->result_id(), decl, value) == nullptr) {
return Pass::Status::Failure;
}
} else {
// If |value| in the same basic block does not dominate |decl|, we can
// assign the value in the immediate dominator.
value_id = GetValueAtBlock(var_id, dom_tree->ImmediateDominator(bb));
+ if (value_id) value = pass_->get_def_use_mgr()->GetDef(value_id);
if (value_id &&
pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl(
- decl, value_id, decl) == nullptr) {
+ decl, value_id, decl, value) == nullptr) {
return Pass::Status::Failure;
}
}
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 47714b74..00000000
--- 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 62e274a1..00000000
--- 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 e2ff99cb..f20ebb4f 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 @@ const char* spvTargetEnvDescription(spv_target_env env) {
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 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) {
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 @@ static const std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] = {
{"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 @@ bool spvIsVulkanEnv(spv_target_env env) {
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 @@ bool spvIsVulkanEnv(spv_target_env env) {
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 @@ bool spvIsOpenCLEnv(spv_target_env env) {
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 @@ bool spvIsOpenCLEnv(spv_target_env env) {
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 @@ bool spvIsOpenGLEnv(spv_target_env env) {
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 @@ bool spvIsOpenGLEnv(spv_target_env env) {
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 @@ std::string spvLogStringForEnv(spv_target_env env) {
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 @@ std::string spvLogStringForEnv(spv_target_env env) {
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 1bdedf91..a804d615 100644
--- a/source/spirv_target_env.h
+++ b/source/spirv_target_env.h
@@ -25,20 +25,14 @@ bool spvIsVulkanEnv(spv_target_env env);
// 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/spirv_validator_options.cpp b/source/spirv_validator_options.cpp
index 01aa7974..2716cca9 100644
--- a/source/spirv_validator_options.cpp
+++ b/source/spirv_validator_options.cpp
@@ -111,6 +111,11 @@ void spvValidatorOptionsSetScalarBlockLayout(spv_validator_options options,
options->scalar_block_layout = val;
}
+void spvValidatorOptionsSetWorkgroupScalarBlockLayout(spv_validator_options options,
+ bool val) {
+ options->workgroup_scalar_block_layout = val;
+}
+
void spvValidatorOptionsSetSkipBlockLayout(spv_validator_options options,
bool val) {
options->skip_block_layout = val;
diff --git a/source/spirv_validator_options.h b/source/spirv_validator_options.h
index b7da5d8e..baaa5359 100644
--- a/source/spirv_validator_options.h
+++ b/source/spirv_validator_options.h
@@ -45,6 +45,7 @@ struct spv_validator_options_t {
relax_block_layout(false),
uniform_buffer_standard_layout(false),
scalar_block_layout(false),
+ workgroup_scalar_block_layout(false),
skip_block_layout(false),
before_hlsl_legalization(false) {}
@@ -54,6 +55,7 @@ struct spv_validator_options_t {
bool relax_block_layout;
bool uniform_buffer_standard_layout;
bool scalar_block_layout;
+ bool workgroup_scalar_block_layout;
bool skip_block_layout;
bool before_hlsl_legalization;
};
diff --git a/source/table.cpp b/source/table.cpp
index 8340e8e2..d4a2d7e9 100644
--- a/source/table.cpp
+++ b/source/table.cpp
@@ -38,7 +38,6 @@ spv_context spvContextCreate(spv_target_env env) {
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 d6e992b1..a2e116b1 100644
--- a/source/val/validate.cpp
+++ b/source/val/validate.cpp
@@ -111,57 +111,6 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) {
<< 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 @@ spv_result_t ValidateEntryPointNamesUnique(ValidationState_t& _) {
// * 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 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) {
"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 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
<< "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 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
}
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 df38f1b1..85d2b751 100644
--- a/source/val/validate_annotation.cpp
+++ b/source/val/validate_annotation.cpp
@@ -22,36 +22,6 @@ namespace spvtools {
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 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
}
}
- 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 @@ spv_result_t ValidateMemberDecorate(ValidationState_t& _,
<< " 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 ValidateDecorationGroup(ValidationState_t& _,
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 ValidateGroupDecorate(ValidationState_t& _,
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 3f1f5617..dd263a79 100644
--- a/source/val/validate_atomics.cpp
+++ b/source/val/validate_atomics.cpp
@@ -213,7 +213,19 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) {
// 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 1d8a1406..3c9df9fc 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -113,28 +113,6 @@ SpvStorageClass GetStorageClass(const Instruction& inst) {
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;
- }
- default:
- break;
- }
-
- return false;
-}
-
typedef enum VUIDError_ {
VUIDErrorExecutionModel = 0,
VUIDErrorStorageClass = 1,
@@ -142,15 +120,28 @@ typedef enum VUIDError_ {
VUIDErrorMax,
} VUIDError;
-const static uint32_t NumRtBuiltins = 16;
+const static uint32_t NumVUIDBuiltins = 33;
typedef struct {
SpvBuiltIn builtIn;
uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs
-} RtBuiltinVUIDMapping;
+} BuiltinVUIDMapping;
-std::array<RtBuiltinVUIDMapping, NumRtBuiltins> rtBuiltinInfo = {{
+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}},
@@ -167,12 +158,16 @@ std::array<RtBuiltinVUIDMapping, NumRtBuiltins> rtBuiltinInfo = {{
{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 GetVUIDForRTBuiltin(SpvBuiltIn builtIn, VUIDError type) {
+uint32_t GetVUIDForBuiltin(SpvBuiltIn builtIn, VUIDError type) {
uint32_t vuid = 0;
- for (const auto& iter: rtBuiltinInfo) {
+ for (const auto& iter: builtinVUIDInfo) {
if (iter.builtIn == builtIn) {
assert(type < VUIDErrorMax);
vuid = iter.vuid[type];
@@ -323,6 +318,14 @@ class BuiltInsValidator {
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);
@@ -481,6 +484,26 @@ class BuiltInsValidator {
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,
@@ -534,6 +557,9 @@ class BuiltInsValidator {
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);
@@ -726,6 +752,22 @@ spv_result_t BuiltInsValidator::ValidateBool(
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) {
@@ -1098,8 +1140,9 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference(
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 "
@@ -1111,19 +1154,28 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference(
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.",
@@ -1237,7 +1289,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference(
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 {
@@ -1261,7 +1313,7 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtReference(
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) {
@@ -1299,7 +1351,7 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtReference(
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 {
@@ -1322,7 +1374,7 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference(
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) {
@@ -1375,7 +1427,7 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference(
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 {
@@ -1398,7 +1450,7 @@ spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference(
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) {
@@ -1556,7 +1608,7 @@ spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference(
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 {
@@ -1579,7 +1631,7 @@ spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference(
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) {
@@ -1869,7 +1921,7 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference(
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)
@@ -1879,12 +1931,19 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference(
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_) {
@@ -1962,46 +2021,6 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference(
}
}
- 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(
@@ -2458,8 +2477,9 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference(
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 "
@@ -2470,8 +2490,9 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference(
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 "
@@ -2515,7 +2536,7 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference(
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 {
@@ -2548,51 +2569,14 @@ spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition(
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(
@@ -2608,7 +2592,7 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference(
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) {
@@ -2768,8 +2752,9 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference(
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 "
@@ -2805,33 +2790,18 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference(
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;
@@ -2849,31 +2819,16 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
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)
@@ -2884,30 +2839,13 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
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);
@@ -2929,23 +2867,23 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
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;
@@ -2963,14 +2901,16 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
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)
@@ -2982,11 +2922,12 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
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);
@@ -3008,23 +2949,23 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
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;
@@ -3033,11 +2974,12 @@ spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition(
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);
@@ -3050,23 +2992,23 @@ spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition(
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;
@@ -3077,11 +3019,12 @@ spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition(
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);
@@ -3093,7 +3036,7 @@ spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition(
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)
@@ -3125,7 +3068,7 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
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)
@@ -3404,6 +3347,287 @@ spv_result_t BuiltInsValidator::ValidateDeviceIndexAtReference(
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)) {
@@ -3608,7 +3832,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
decoration, inst,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
- uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
@@ -3630,7 +3854,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
decoration, inst,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
- uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
@@ -3651,7 +3875,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
decoration, inst, 3,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
- uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
@@ -3671,7 +3895,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
decoration, inst, 3,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
- uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
@@ -3691,7 +3915,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
decoration, inst, 3, 4,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
- uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+ uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
@@ -3724,7 +3948,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
- uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorStorageClass);
+ 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,
@@ -3737,7 +3961,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
for (const SpvExecutionModel execution_model : execution_models_) {
if (!IsExecutionModelValidForRtBuiltIn(builtin, execution_model)) {
- uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorExecutionModel);
+ 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,
@@ -3775,26 +3999,17 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
<< "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.
@@ -3910,6 +4125,20 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
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
@@ -3945,13 +4174,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
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:
@@ -3963,9 +4190,6 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
case SpvBuiltInMeshViewIndicesNV:
case SpvBuiltInBaryCoordNV:
case SpvBuiltInBaryCoordNoPerspNV:
- case SpvBuiltInFragmentSizeNV: // alias SpvBuiltInFragSizeEXT
- case SpvBuiltInInvocationsPerPixelNV: // alias
- // SpvBuiltInFragInvocationCountEXT
// No validation rules (for the moment).
break;
diff --git a/source/val/validate_capability.cpp b/source/val/validate_capability.cpp
index 4b98bc19..8efd5542 100644
--- a/source/val/validate_capability.cpp
+++ b/source/val/validate_capability.cpp
@@ -260,19 +260,6 @@ bool IsEnabledByCapabilityOpenCL_2_0(ValidationState_t& _,
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 @@ spv_result_t CapabilityPass(ValidationState_t& _, const Instruction* inst) {
<< " 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 ca2ae1ae..a5f6e6a1 100644
--- a/source/val/validate_cfg.cpp
+++ b/source/val/validate_cfg.cpp
@@ -820,120 +820,6 @@ spv_result_t StructuredControlFlowChecks(
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
@@ -1014,13 +900,6 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) {
<< _.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 d5b978ff..5d6c5e37 100644
--- a/source/val/validate_composites.cpp
+++ b/source/val/validate_composites.cpp
@@ -535,12 +535,10 @@ spv_result_t ValidateVectorShuffle(ValidationState_t& _,
}
// 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) {
@@ -548,12 +546,6 @@ spv_result_t ValidateVectorShuffle(ValidationState_t& _,
<< "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_conversion.cpp b/source/val/validate_conversion.cpp
index 0060d0b7..b4e39cfe 100644
--- a/source/val/validate_conversion.cpp
+++ b/source/val/validate_conversion.cpp
@@ -14,12 +14,12 @@
// Validates correctness of conversion instructions.
-#include "source/val/validate.h"
-
#include "source/diagnostic.h"
#include "source/opcode.h"
#include "source/spirv_constant.h"
+#include "source/spirv_target_env.h"
#include "source/val/instruction.h"
+#include "source/val/validate.h"
#include "source/val/validation_state.h"
namespace spvtools {
@@ -263,16 +263,25 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
<< "Logical addressing not supported: "
<< spvOpcodeString(opcode);
- if (_.addressing_model() ==
- SpvAddressingModelPhysicalStorageBuffer64EXT) {
+ if (_.addressing_model() == SpvAddressingModelPhysicalStorageBuffer64) {
uint32_t input_storage_class = 0;
uint32_t input_data_type = 0;
_.GetPointerTypeInfo(input_type, &input_data_type,
&input_storage_class);
- if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
+ if (input_storage_class != SpvStorageClassPhysicalStorageBuffer)
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Pointer storage class must be PhysicalStorageBufferEXT: "
+ << "Pointer storage class must be PhysicalStorageBuffer: "
<< spvOpcodeString(opcode);
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (_.GetBitWidth(result_type) != 64) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4710)
+ << "PhysicalStorageBuffer64 addressing mode requires the "
+ "result integer type to have a 64-bit width for Vulkan "
+ "environment.";
+ }
+ }
}
break;
}
@@ -314,16 +323,25 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
<< "Logical addressing not supported: "
<< spvOpcodeString(opcode);
- if (_.addressing_model() ==
- SpvAddressingModelPhysicalStorageBuffer64EXT) {
+ if (_.addressing_model() == SpvAddressingModelPhysicalStorageBuffer64) {
uint32_t result_storage_class = 0;
uint32_t result_data_type = 0;
_.GetPointerTypeInfo(result_type, &result_data_type,
&result_storage_class);
- if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
+ if (result_storage_class != SpvStorageClassPhysicalStorageBuffer)
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Pointer storage class must be PhysicalStorageBufferEXT: "
+ << "Pointer storage class must be PhysicalStorageBuffer: "
<< spvOpcodeString(opcode);
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (_.GetBitWidth(input_type) != 64) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4710)
+ << "PhysicalStorageBuffer64 addressing mode requires the "
+ "input integer to have a 64-bit width for Vulkan "
+ "environment.";
+ }
+ }
}
break;
}
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index d3812766..ed336b47 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -379,6 +379,7 @@ bool IsAlignedTo(uint32_t offset, uint32_t alignment) {
// or row major-ness.
spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
const char* decoration_str, bool blockRules,
+ bool scalar_block_layout,
uint32_t incoming_offset,
MemberConstraints& constraints,
ValidationState_t& vstate) {
@@ -392,7 +393,6 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
// For example, relaxed layout is implied by Vulkan 1.1. But scalar layout
// is more permissive than relaxed layout.
const bool relaxed_block_layout = vstate.IsRelaxedBlockLayout();
- const bool scalar_block_layout = vstate.options()->scalar_block_layout;
auto fail = [&vstate, struct_id, storage_class_str, decoration_str,
blockRules, relaxed_block_layout,
@@ -501,6 +501,7 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
if (SpvOpTypeStruct == opcode &&
SPV_SUCCESS != (recursive_status = checkLayout(
id, storage_class_str, decoration_str, blockRules,
+ scalar_block_layout,
offset, constraints, vstate)))
return recursive_status;
// Check matrix stride.
@@ -553,7 +554,8 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
if (SpvOpTypeStruct == element_inst->opcode() &&
SPV_SUCCESS != (recursive_status = checkLayout(
typeId, storage_class_str, decoration_str,
- blockRules, next_offset, constraints, vstate)))
+ blockRules, scalar_block_layout,
+ next_offset, constraints, vstate)))
return recursive_status;
// If offsets accumulate up to a 16-byte multiple stop checking since
// it will just repeat.
@@ -698,6 +700,9 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
const auto& descs = vstate.entry_point_descriptions(entry_point);
int num_builtin_inputs = 0;
int num_builtin_outputs = 0;
+ int num_workgroup_variables = 0;
+ int num_workgroup_variables_with_block = 0;
+ int num_workgroup_variables_with_aliased = 0;
for (const auto& desc : descs) {
std::unordered_set<Instruction*> seen_vars;
for (auto interface : desc.interfaces) {
@@ -754,6 +759,16 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
if (auto error = CheckBuiltInVariable(interface, vstate))
return error;
}
+
+ if (storage_class == SpvStorageClassWorkgroup) {
+ ++num_workgroup_variables;
+ if (type_instr && SpvOpTypeStruct == type_instr->opcode()) {
+ if (hasDecoration(type_id, SpvDecorationBlock, vstate))
+ ++num_workgroup_variables_with_block;
+ if (hasDecoration(var_instr->id(), SpvDecorationAliased, vstate))
+ ++num_workgroup_variables_with_aliased;
+ }
+ }
}
if (num_builtin_inputs > 1 || num_builtin_outputs > 1) {
return vstate.diag(SPV_ERROR_INVALID_BINARY,
@@ -777,6 +792,30 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
<< " because it is targeted by an OpEntryPoint instruction.";
}
}
+
+ if (vstate.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayoutKHR) &&
+ num_workgroup_variables > 0 &&
+ num_workgroup_variables_with_block > 0) {
+ if (num_workgroup_variables != num_workgroup_variables_with_block) {
+ return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point))
+ << "When declaring WorkgroupMemoryExplicitLayoutKHR, "
+ "either all or none of the Workgroup Storage Class variables "
+ "in the entry point interface must point to struct types "
+ "decorated with Block. Entry point id "
+ << entry_point << " does not meet this requirement.";
+ }
+ if (num_workgroup_variables_with_block > 1 &&
+ num_workgroup_variables_with_block !=
+ num_workgroup_variables_with_aliased) {
+ return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point))
+ << "When declaring WorkgroupMemoryExplicitLayoutKHR, "
+ "if more than one Workgroup Storage Class variable in "
+ "the entry point interface point to a type decorated "
+ "with Block, all of them must be decorated with Aliased. "
+ "Entry point id "
+ << entry_point << " does not meet this requirement.";
+ }
+ }
}
}
return SPV_SUCCESS;
@@ -942,14 +981,16 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
const bool phys_storage_buffer =
storageClass == SpvStorageClassPhysicalStorageBufferEXT;
- if (uniform || push_constant || storage_buffer || phys_storage_buffer) {
+ const bool workgroup = storageClass == SpvStorageClassWorkgroup;
+ if (uniform || push_constant || storage_buffer || phys_storage_buffer ||
+ workgroup) {
const auto ptrInst = vstate.FindDef(words[1]);
assert(SpvOpTypePointer == ptrInst->opcode());
auto id = ptrInst->words()[3];
auto id_inst = vstate.FindDef(id);
// Jump through one level of arraying.
- if (id_inst->opcode() == SpvOpTypeArray ||
- id_inst->opcode() == SpvOpTypeRuntimeArray) {
+ if (!workgroup && (id_inst->opcode() == SpvOpTypeArray ||
+ id_inst->opcode() == SpvOpTypeRuntimeArray)) {
id = id_inst->GetOperandAs<uint32_t>(1u);
id_inst = vstate.FindDef(id);
}
@@ -961,7 +1002,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
// Prepare for messages
const char* sc_str =
uniform ? "Uniform"
- : (push_constant ? "PushConstant" : "StorageBuffer");
+ : (push_constant ? "PushConstant"
+ : (workgroup ? "Workgroup"
+ : "StorageBuffer"));
if (spvIsVulkanEnv(vstate.context()->target_env)) {
const bool block = hasDecoration(id, SpvDecorationBlock, vstate);
@@ -1029,8 +1072,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
const bool bufferDeco = SpvDecorationBufferBlock == dec.dec_type();
const bool blockRules = uniform && blockDeco;
const bool bufferRules =
- (uniform && bufferDeco) || (push_constant && blockDeco) ||
- ((storage_buffer || phys_storage_buffer) && blockDeco);
+ (uniform && bufferDeco) ||
+ ((push_constant || storage_buffer ||
+ phys_storage_buffer || workgroup) && blockDeco);
if (uniform && blockDeco) {
vstate.RegisterPointerToUniformBlock(ptrInst->id());
vstate.RegisterStructForUniformBlock(id);
@@ -1044,6 +1088,10 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
if (blockRules || bufferRules) {
const char* deco_str = blockDeco ? "Block" : "BufferBlock";
spv_result_t recursive_status = SPV_SUCCESS;
+ const bool scalar_block_layout = workgroup ?
+ vstate.options()->workgroup_scalar_block_layout :
+ vstate.options()->scalar_block_layout;
+
if (isMissingOffsetInStruct(id, vstate)) {
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
<< "Structure id " << id << " decorated as " << deco_str
@@ -1072,12 +1120,14 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
"decorations.";
} else if (blockRules &&
(SPV_SUCCESS != (recursive_status = checkLayout(
- id, sc_str, deco_str, true, 0,
+ id, sc_str, deco_str, true,
+ scalar_block_layout, 0,
constraints, vstate)))) {
return recursive_status;
} else if (bufferRules &&
(SPV_SUCCESS != (recursive_status = checkLayout(
- id, sc_str, deco_str, false, 0,
+ id, sc_str, deco_str, false,
+ scalar_block_layout, 0,
constraints, vstate)))) {
return recursive_status;
}
@@ -1260,7 +1310,8 @@ spv_result_t CheckVulkanMemoryModelDeprecatedDecorations(
// 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 +1321,15 @@ spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate,
"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 +1648,8 @@ spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) {
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 17b04460..dc8c0243 100644
--- a/source/val/validate_extensions.cpp
+++ b/source/val/validate_extensions.cpp
@@ -27,6 +27,7 @@
#include "source/latest_version_glsl_std_450_header.h"
#include "source/latest_version_opencl_std_header.h"
#include "source/opcode.h"
+#include "source/spirv_constant.h"
#include "source/spirv_target_env.h"
#include "source/val/instruction.h"
#include "source/val/validate.h"
@@ -686,14 +687,13 @@ bool IsDebugVariableWithIntScalarType(ValidationState_t& _,
} // anonymous namespace
spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
- if (spvIsWebGPUEnv(_.context()->target_env)) {
+ if (_.version() < SPV_SPIRV_VERSION_WORD(1, 4)) {
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)
- << "\".";
+ if (extension ==
+ ExtensionToString(kSPV_KHR_workgroup_memory_explicit_layout)) {
+ return _.diag(SPV_ERROR_WRONG_VERSION, inst)
+ << "SPV_KHR_workgroup_memory_explicit_layout extension "
+ "requires SPIR-V version 1.4 or later.";
}
}
@@ -703,16 +703,6 @@ spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
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));
diff --git a/source/val/validate_id.cpp b/source/val/validate_id.cpp
index e1a775a8..2bab2034 100644
--- a/source/val/validate_id.cpp
+++ b/source/val/validate_id.cpp
@@ -201,7 +201,7 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) {
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 299a3efc..bdb2516e 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 @@ uint32_t GetMinCoordSize(SpvOp opcode, const ImageTypeInfo& info) {
}
// 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,28 +244,48 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
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 (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) {
+ 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) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4662)
<< "Image Operands Offset, ConstOffset, ConstOffsets cannot be used "
<< "together";
}
@@ -296,10 +316,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
"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 +355,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
"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 +388,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
<< " 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) {
@@ -430,6 +441,17 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
<< "Expected Image Operand Offset to have " << plane_size
<< " components, but given " << offset_size;
}
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (opcode != SpvOpImageGather && opcode != SpvOpImageDrefGather &&
+ opcode != SpvOpImageSparseGather &&
+ opcode != SpvOpImageSparseDrefGather) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4663)
+ << "Image Operand Offset can only be used with "
+ "OpImage*Gather operations";
+ }
+ }
}
if (mask & SpvImageOperandsConstOffsetsMask) {
@@ -613,12 +635,12 @@ spv_result_t ValidateImageCommon(ValidationState_t& _, const Instruction* inst,
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 +758,28 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
<< "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 +807,7 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
<< "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 +821,10 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
<< "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 +833,14 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
<< "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 +870,15 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
}
}
+ 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 +889,21 @@ spv_result_t ValidateTypeSampledImage(ValidationState_t& _,
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)
+ << _.VkErrorID(4657)
+ << "Sampled image type requires an image type with \"Sampled\" "
+ "operand set to 0 or 1";
+ }
+
return SPV_SUCCESS;
}
@@ -1066,6 +1131,20 @@ spv_result_t ValidateImageTexelPointer(ValidationState_t& _,
"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 +1182,14 @@ spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) {
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 +1224,11 @@ spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) {
<< " components, but given only " << actual_coord_size;
}
- if (inst->words().size() <= 5) {
- assert(IsImplicitLod(opcode));
- return SPV_SUCCESS;
- }
-
- const uint32_t mask = inst->word(5);
+ const uint32_t mask = inst->words().size() <= 5 ? 0 : 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 +1237,7 @@ spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) {
}
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 +1272,14 @@ spv_result_t ValidateImageDrefLod(ValidationState_t& _,
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 +1306,8 @@ spv_result_t ValidateImageDrefLod(ValidationState_t& _,
<< "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 +1378,8 @@ spv_result_t ValidateImageFetch(ValidationState_t& _, const Instruction* inst) {
<< " 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 +1417,14 @@ spv_result_t ValidateImageGather(ValidationState_t& _,
<< "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 =
@@ -1368,12 +1457,21 @@ spv_result_t ValidateImageGather(ValidationState_t& _,
}
if (opcode == SpvOpImageGather || opcode == SpvOpImageSparseGather) {
- const uint32_t component_index_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t component = inst->GetOperandAs<uint32_t>(4);
+ const uint32_t component_index_type = _.GetTypeId(component);
if (!_.IsIntScalarType(component_index_type) ||
_.GetBitWidth(component_index_type) != 32) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Component to be 32-bit int scalar";
}
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (!spvOpcodeIsConstant(_.GetIdOpcode(component))) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4664)
+ << "Expected Component Operand to be a const object for Vulkan "
+ "environment";
+ }
+ }
} else {
assert(opcode == SpvOpImageDrefGather ||
opcode == SpvOpImageSparseDrefGather);
@@ -1384,11 +1482,8 @@ spv_result_t ValidateImageGather(ValidationState_t& _,
}
}
- 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 +1503,16 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) {
<< " 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 +1526,29 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) {
<< "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 +1597,10 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) {
}
}
- if (inst->words().size() <= 5) return SPV_SUCCESS;
-
- const uint32_t mask = inst->word(5);
+ const uint32_t mask = inst->words().size() <= 5 ? 0 : 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 +1608,7 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) {
}
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 +1684,7 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) {
}
}
- 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 +1692,8 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) {
}
}
- 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 +1764,16 @@ spv_result_t ValidateImageQuerySizeLod(ValidationState_t& _,
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 +1948,13 @@ spv_result_t ValidateImageQueryLod(ValidationState_t& _,
<< "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 +1991,15 @@ spv_result_t ValidateImageQueryLevelsOrSamples(ValidationState_t& _,
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 d9f8b991..4dd6d941 100644
--- a/source/val/validate_memory.cpp
+++ b/source/val/validate_memory.cpp
@@ -407,6 +407,10 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
<< "' is not a pointer type.";
}
+ const auto type_index = 2;
+ const auto value_id = result_type->GetOperandAs<uint32_t>(type_index);
+ auto value_type = _.FindDef(value_id);
+
const auto initializer_index = 3;
const auto storage_class_index = 2;
if (initializer_index < inst->operands().size()) {
@@ -423,7 +427,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
<< "OpVariable Initializer <id> '" << _.getIdName(initializer_id)
<< "' is not a constant or module-scope variable.";
}
- if (initializer->type_id() != result_type->GetOperandAs<uint32_t>(2u)) {
+ if (initializer->type_id() != value_id) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Initializer type must match the type pointed to by the Result "
"Type";
@@ -440,9 +444,6 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
storage_class != SpvStorageClassHitAttributeNV &&
storage_class != SpvStorageClassCallableDataNV &&
storage_class != SpvStorageClassIncomingCallableDataNV) {
- const auto storage_index = 2;
- const auto storage_id = result_type->GetOperandAs<uint32_t>(storage_index);
- const auto storage = _.FindDef(storage_id);
bool storage_input_or_output = storage_class == SpvStorageClassInput ||
storage_class == SpvStorageClassOutput;
bool builtin = false;
@@ -455,7 +456,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
}
}
if (!(storage_input_or_output && builtin) &&
- ContainsInvalidBool(_, storage, storage_input_or_output)) {
+ ContainsInvalidBool(_, value_type, storage_input_or_output)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "If OpTypeBool is stored in conjunction with OpVariable, it "
<< "can only be used with non-externally visible shader Storage "
@@ -535,18 +536,14 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
if (!IsAllowedTypeOrArrayOfSame(
_, pointee,
{SpvOpTypeImage, SpvOpTypeSampler, SpvOpTypeSampledImage,
- SpvOpTypeAccelerationStructureNV,
- SpvOpTypeAccelerationStructureKHR, SpvOpTypeRayQueryKHR})) {
+ SpvOpTypeAccelerationStructureKHR})) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "UniformConstant OpVariable <id> '" << _.getIdName(inst->id())
- << "' has illegal type.\n"
- << "From Vulkan spec, section 14.5.2:\n"
+ << _.VkErrorID(4655) << "UniformConstant OpVariable <id> '"
+ << _.getIdName(inst->id()) << "' has illegal type.\n"
<< "Variables identified with the UniformConstant storage class "
<< "are used only as handles to refer to opaque resources. Such "
<< "variables must be typed as OpTypeImage, OpTypeSampler, "
- << "OpTypeSampledImage, OpTypeAccelerationStructureNV, "
- "OpTypeAccelerationStructureKHR, "
- "OpTypeRayQueryKHR, "
+ << "OpTypeSampledImage, OpTypeAccelerationStructureKHR, "
<< "or an array of one of these types.";
}
}
@@ -576,40 +573,59 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
"of this type";
}
}
+
+ // Check for invalid use of Invariant
+ if (storage_class != SpvStorageClassInput &&
+ storage_class != SpvStorageClassOutput) {
+ if (_.HasDecoration(inst->id(), SpvDecorationInvariant)) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(4677)
+ << "Variable decorated with Invariant must only be identified "
+ "with the Input or Output storage class in Vulkan "
+ "environment.";
+ }
+ // Need to check if only the members in a struct are decorated
+ if (value_type && value_type->opcode() == SpvOpTypeStruct) {
+ if (_.HasDecoration(value_id, SpvDecorationInvariant)) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(4677)
+ << "Variable struct member decorated with Invariant must only "
+ "be identified with the Input or Output storage class in "
+ "Vulkan environment.";
+ }
+ }
+ }
}
- // 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)) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpVariable, <id> '" << _.getIdName(inst->id())
- << "', has a disallowed initializer & storage class "
- << "combination.\n"
- << "From " << spvLogStringForEnv(_.context()->target_env)
- << " spec:\n"
- << "Variable declarations that include initializers must have "
- << "one of the following storage classes: Output, Private, or "
- << "Function";
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (storage_class == SpvStorageClassWorkgroup) {
+ auto init_id = inst->GetOperandAs<uint32_t>(3);
+ auto init = _.FindDef(init_id);
+ if (init->opcode() != SpvOpConstantNull) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "Variable initializers in Workgroup storage class are "
+ "limited to OpConstantNull";
+ }
+ } else {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(4651) << "OpVariable, <id> '"
+ << _.getIdName(inst->id())
+ << "', has a disallowed initializer & storage class "
+ << "combination.\n"
+ << "From " << spvLogStringForEnv(_.context()->target_env)
+ << " spec:\n"
+ << "Variable declarations that include initializers must have "
+ << "one of the following storage classes: Output, Private, "
+ << "Function or Workgroup";
+ }
}
}
- // 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.";
@@ -643,9 +659,6 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
}
// Vulkan specific validation rules for OpTypeRuntimeArray
- const auto type_index = 2;
- const auto value_id = result_type->GetOperandAs<uint32_t>(type_index);
- auto value_type = _.FindDef(value_id);
if (spvIsVulkanEnv(_.context()->target_env)) {
// OpTypeRuntimeArray should only ever be in a container like OpTypeStruct,
// so should never appear as a bare variable.
@@ -702,41 +715,6 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
}
}
- // 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) &&
@@ -797,6 +775,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
storage_class_ok = false;
}
break;
+ case SpvStorageClassWorkgroup:
+ if (!_.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR)) {
+ storage_class_ok = false;
+ }
+ break;
default:
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Cannot allocate a variable containing a 16-bit type in "
@@ -848,6 +831,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
storage_class_ok = false;
}
break;
+ case SpvStorageClassWorkgroup:
+ if (!_.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR)) {
+ storage_class_ok = false;
+ }
+ break;
default:
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Cannot allocate a variable containing a 8-bit type in "
diff --git a/source/val/validate_memory_semantics.cpp b/source/val/validate_memory_semantics.cpp
index 4c582f09..6c3e1d44 100644
--- a/source/val/validate_memory_semantics.cpp
+++ b/source/val/validate_memory_semantics.cpp
@@ -56,55 +56,6 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
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 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
if (opcode == SpvOpMemoryBarrier && !num_memory_order_set_bits) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4732) << spvOpcodeString(opcode)
<< ": Vulkan specification requires Memory Semantics to have "
"one "
"of the following bits set: Acquire, Release, "
@@ -231,7 +182,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
if (opcode == SpvOpMemoryBarrier && !includes_storage_class) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4733) << spvOpcodeString(opcode)
<< ": expected Memory Semantics to include a Vulkan-supported "
"storage class";
}
@@ -272,6 +223,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
value & SpvMemorySemanticsAcquireReleaseMask ||
value & SpvMemorySemanticsSequentiallyConsistentMask)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4731)
<< "Vulkan spec disallows OpAtomicLoad with Memory Semantics "
"Release, AcquireRelease and SequentiallyConsistent";
}
@@ -281,6 +233,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
value & SpvMemorySemanticsAcquireReleaseMask ||
value & SpvMemorySemanticsSequentiallyConsistentMask)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4730)
<< "Vulkan spec disallows OpAtomicStore with Memory Semantics "
"Acquire, AcquireRelease and SequentiallyConsistent";
}
diff --git a/source/val/validate_misc.cpp b/source/val/validate_misc.cpp
index 8cccd4c5..0c30f3ca 100644
--- a/source/val/validate_misc.cpp
+++ b/source/val/validate_misc.cpp
@@ -37,10 +37,6 @@ spv_result_t ValidateUndef(ValidationState_t& _, const Instruction* inst) {
<< "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;
}
@@ -56,7 +52,7 @@ spv_result_t ValidateShaderClock(ValidationState_t& _,
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 a7f8d339..79f82d8d 100644
--- a/source/val/validate_mode_setting.cpp
+++ b/source/val/validate_mode_setting.cpp
@@ -42,7 +42,8 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
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 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
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.";
}
@@ -226,6 +228,7 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
}
if (!ok) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4683)
<< "In the Vulkan environment, GLCompute execution model "
"entry points require either the LocalSize execution "
"mode or an object decorated with WorkgroupSize must be "
@@ -457,31 +460,18 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
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 +486,6 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _,
"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 +499,15 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _,
}
}
+ 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 8dcf9743..2b6eb8b5 100644
--- a/source/val/validate_non_uniform.cpp
+++ b/source/val/validate_non_uniform.cpp
@@ -47,6 +47,19 @@ spv_result_t ValidateGroupNonUniformBallotBitCount(ValidationState_t& _,
"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 a6fb26da..a92f7fd3 100644
--- a/source/val/validate_scopes.cpp
+++ b/source/val/validate_scopes.cpp
@@ -99,7 +99,7 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
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 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
}
}
- // 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 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst,
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 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst,
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 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst,
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 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst,
model != SpvExecutionModelCallableKHR) {
if (message) {
*message =
+ errorVUID +
"ShaderCallKHR Memory Scope requires a ray tracing "
"execution model";
}
@@ -258,56 +236,19 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst,
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 5924c69f..6a5ea3c1 100644
--- a/source/val/validate_type.cpp
+++ b/source/val/validate_type.cpp
@@ -40,21 +40,6 @@ int64_t ConstantLiteralAsInt64(uint32_t width,
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 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) {
<< "' 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 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) {
<< "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 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _,
<< _.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 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) {
<< ".";
}
- 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 @@ spv_result_t ValidateTypeForwardPointer(ValidationState_t& _,
<< "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 @@ spv_result_t ValidateTypeForwardPointer(ValidationState_t& _,
<< "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 06abb54f..6dfc7bf6 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -359,6 +359,7 @@ void ValidationState_t::RegisterCapability(SpvCapability cap) {
case SpvCapabilityStorageBuffer8BitAccess:
case SpvCapabilityUniformAndStorageBuffer8BitAccess:
case SpvCapabilityStoragePushConstant8:
+ case SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR:
features_.declare_int8_type = true;
break;
case SpvCapabilityInt16:
@@ -372,6 +373,7 @@ void ValidationState_t::RegisterCapability(SpvCapability cap) {
case SpvCapabilityStorageUniform16:
case SpvCapabilityStoragePushConstant16:
case SpvCapabilityStorageInputOutput16:
+ case SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR:
features_.declare_int16_type = true;
features_.declare_float16_type = true;
features_.free_fp_rounding_mode = true;
@@ -1240,23 +1242,6 @@ bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
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 +1300,22 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
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 +1342,36 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
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:
@@ -1419,6 +1440,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
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:
@@ -1431,6 +1454,12 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
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:
@@ -1477,6 +1506,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
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:
@@ -1523,6 +1554,40 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
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:
@@ -1531,10 +1596,18 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
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:
@@ -1551,6 +1624,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
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:
@@ -1599,6 +1674,66 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
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 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 4655:
+ return VUID_WRAP(VUID-StandaloneSpirv-UniformConstant-04655);
+ 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 4659:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpImageQuerySizeLod-04659);
+ case 4662:
+ return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662);
+ case 4663:
+ return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663);
+ case 4664:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpImageGather-04664);
+ case 4669:
+ return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669);
+ case 4675:
+ return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
+ case 4677:
+ return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677);
+ case 4683:
+ return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683);
+ case 4685:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
+ case 4686:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
+ case 4710:
+ return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710);
+ case 4711:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711);
+ case 4730:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicStore-04730);
+ case 4731:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicLoad-04731);
+ case 4732:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04732);
+ case 4733:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733);
default:
return ""; // unknown id
};
diff --git a/source/val/validation_state.h b/source/val/validation_state.h
index aeb1ca86..85111391 100644
--- a/source/val/validation_state.h
+++ b/source/val/validation_state.h
@@ -103,6 +103,10 @@ class ValidationState_t {
// Members need not be listed in offset order
bool scalar_block_layout = false;
+ // Use scalar block layout (as defined above) for Workgroup block
+ // variables. See VK_KHR_workgroup_memory_explicit_layout.
+ bool workgroup_scalar_block_layout = false;
+
// SPIR-V 1.4 allows us to select between any two composite values
// of the same type.
bool select_between_composites = false;
diff --git a/test/fuzz/transformation_duplicate_region_with_selection_test.cpp b/test/fuzz/transformation_duplicate_region_with_selection_test.cpp
index f3738e74..31fb9a2f 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 @@ TEST(TransformationDuplicateRegionWithSelectionTest,
OpBranch %50
%50 = OpLabel
%51 = OpCopyObject %7 %12
+ OpBranch %52
+ %52 = OpLabel
+ %53 = OpCopyObject %7 %51
OpReturn
OpFunctionEnd
)";
@@ -2275,6 +2278,207 @@ TEST(TransformationDuplicateRegionWithSelectionTest,
.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/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn
index be1258a4..ec09b2b0 100644
--- a/test/fuzzers/BUILD.gn
+++ b/test/fuzzers/BUILD.gn
@@ -39,10 +39,7 @@ if (!build_with_chromium || use_fuzzing_engine) {
":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_size_fuzzer_src") {
]
}
-
-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 @@ if (!build_with_chromium || use_fuzzing_engine) {
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 @@ if (!build_with_chromium || use_fuzzing_engine) {
]
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 9371c0df..00000000
--- 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 78ddbb75..00000000
--- 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 bed6e1a2..00000000
--- 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 34269587..79cb3fc4 100644
--- a/test/opt/CMakeLists.txt
+++ b/test/opt/CMakeLists.txt
@@ -34,7 +34,6 @@ add_spvtools_unittest(TARGET opt
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 @@ add_spvtools_unittest(TARGET opt
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 @@ add_spvtools_unittest(TARGET opt
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 @@ add_spvtools_unittest(TARGET opt
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/convert_relaxed_to_half_test.cpp b/test/opt/convert_relaxed_to_half_test.cpp
index c1381547..ca6ee583 100644
--- a/test/opt/convert_relaxed_to_half_test.cpp
+++ b/test/opt/convert_relaxed_to_half_test.cpp
@@ -1331,6 +1331,72 @@ OpFunctionEnd
SinglePassRunAndMatch<ConvertToHalfPass>(defs + func, true);
}
+TEST_F(ConvertToHalfTest, RemoveRelaxDec) {
+ // See https://github.com/KhronosGroup/SPIRV-Tools/issues/4117
+
+ // This test is a case where the relax precision decorations need to be
+ // removed, but the body of the function does not change because there are not
+ // arithmetic operations. So, there is not need for the Float16 capability.
+ const std::string test =
+ R"(
+; CHECK-NOT: OpCapability Float16
+; GLSL seems to generate this decoration on the load of a texture, which seems odd to me.
+; This pass does not currently remove it, and I'm not sure what we should do with it, so I will leave it.
+; CHECK: OpDecorate [[tex:%\w+]] RelaxedPrecision
+; CHECK-NOT: OpDecorate {{%\w+}} RelaxedPrecision
+; CHECK: OpLabel
+; CHECK: [[tex]] = OpLoad {{%\w+}} %sTexture
+; CHECK: [[coord:%\w+]] = OpLoad %v2float
+; CHECK: [[retval:%\w+]] = OpImageSampleImplicitLod %v4float {{%\w+}} [[coord]]
+; CHECK: OpStore %outFragColor [[retval]]
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %outFragColor %v_texcoord
+ OpExecutionMode %main OriginUpperLeft
+ OpSource ESSL 310
+ OpName %main "main"
+ OpName %outFragColor "outFragColor"
+ OpName %sTexture "sTexture"
+ OpName %v_texcoord "v_texcoord"
+ OpDecorate %outFragColor RelaxedPrecision
+ OpDecorate %outFragColor Location 0
+ OpDecorate %sTexture RelaxedPrecision
+ OpDecorate %sTexture DescriptorSet 0
+ OpDecorate %sTexture Binding 0
+ OpDecorate %14 RelaxedPrecision
+ OpDecorate %v_texcoord RelaxedPrecision
+ OpDecorate %v_texcoord Location 0
+ OpDecorate %18 RelaxedPrecision
+ OpDecorate %19 RelaxedPrecision
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%outFragColor = OpVariable %_ptr_Output_v4float Output
+ %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
+ %11 = OpTypeSampledImage %10
+%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
+ %sTexture = OpVariable %_ptr_UniformConstant_11 UniformConstant
+ %v2float = OpTypeVector %float 2
+%_ptr_Input_v2float = OpTypePointer Input %v2float
+ %v_texcoord = OpVariable %_ptr_Input_v2float Input
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %14 = OpLoad %11 %sTexture
+ %18 = OpLoad %v2float %v_texcoord
+ %19 = OpImageSampleImplicitLod %v4float %14 %18
+ OpStore %outFragColor %19
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ auto result = SinglePassRunAndMatch<ConvertToHalfPass>(test, true);
+ EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/debug_info_manager_test.cpp b/test/opt/debug_info_manager_test.cpp
index 911331a7..49407fd5 100644
--- a/test/opt/debug_info_manager_test.cpp
+++ b/test/opt/debug_info_manager_test.cpp
@@ -31,6 +31,9 @@ static const uint32_t kDebugFunctionOperandFunctionIndex = 13;
static const uint32_t kDebugInlinedAtOperandLineIndex = 4;
static const uint32_t kDebugInlinedAtOperandScopeIndex = 5;
static const uint32_t kDebugInlinedAtOperandInlinedIndex = 6;
+static const uint32_t kOpLineInOperandFileIndex = 0;
+static const uint32_t kOpLineInOperandLineIndex = 1;
+static const uint32_t kOpLineInOperandColumnIndex = 2;
namespace spvtools {
namespace opt {
@@ -609,6 +612,80 @@ void main(float in_var_color : COLOR) {
EXPECT_FALSE(dbg_info_mgr->IsVariableDebugDeclared(100));
}
+TEST(DebugInfoManager, AddDebugValueForDecl) {
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "OpenCL.DebugInfo.100"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %in_var_COLOR
+ OpExecutionMode %main OriginUpperLeft
+ %5 = OpString "ps.hlsl"
+ %14 = OpString "#line 1 \"ps.hlsl\"
+void main(float in_var_color : COLOR) {
+ float color = in_var_color;
+}
+"
+ %17 = OpString "float"
+ %21 = OpString "main"
+ %24 = OpString "color"
+ OpName %in_var_COLOR "in.var.COLOR"
+ OpName %main "main"
+ OpDecorate %in_var_COLOR Location 0
+ %uint = OpTypeInt 32 0
+ %uint_32 = OpConstant %uint 32
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %void = OpTypeVoid
+ %27 = OpTypeFunction %void
+%_ptr_Function_float = OpTypePointer Function %float
+%in_var_COLOR = OpVariable %_ptr_Input_float Input
+ %13 = OpExtInst %void %1 DebugExpression
+ %15 = OpExtInst %void %1 DebugSource %5 %14
+ %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
+ %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
+ %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18
+ %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %main
+ %12 = OpExtInst %void %1 DebugInfoNone
+ %25 = OpExtInst %void %1 DebugLocalVariable %24 %18 %15 1 20 %22 FlagIsLocal 0
+ %main = OpFunction %void None %27
+ %28 = OpLabel
+ %100 = OpVariable %_ptr_Function_float Function
+ %31 = OpLoad %float %in_var_COLOR
+ %101 = OpExtInst %void %1 DebugScope %22
+ OpLine %5 13 7
+ OpStore %100 %31
+ OpNoLine
+ %102 = OpExtInst %void %1 DebugNoScope
+ %36 = OpExtInst %void %1 DebugDeclare %25 %100 %13
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ std::unique_ptr<IRContext> context =
+ BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ auto* def_use_mgr = context->get_def_use_mgr();
+ auto* dbg_decl = def_use_mgr->GetDef(36);
+ EXPECT_EQ(dbg_decl->GetOpenCL100DebugOpcode(),
+ OpenCLDebugInfo100DebugDeclare);
+
+ auto* dbg_info_mgr = context->get_debug_info_mgr();
+ Instruction* store = dbg_decl->PreviousNode();
+ auto* dbg_value =
+ dbg_info_mgr->AddDebugValueForDecl(dbg_decl, 100, dbg_decl, store);
+
+ EXPECT_EQ(dbg_value->GetOpenCL100DebugOpcode(), OpenCLDebugInfo100DebugValue);
+ EXPECT_EQ(dbg_value->dbg_line_inst()->GetSingleWordInOperand(
+ kOpLineInOperandFileIndex),
+ 5);
+ EXPECT_EQ(dbg_value->dbg_line_inst()->GetSingleWordInOperand(
+ kOpLineInOperandLineIndex),
+ 13);
+ EXPECT_EQ(dbg_value->dbg_line_inst()->GetSingleWordInOperand(
+ kOpLineInOperandColumnIndex),
+ 7);
+}
+
} // namespace
} // namespace analysis
} // namespace opt
diff --git a/test/opt/decompose_initialized_variables_test.cpp b/test/opt/decompose_initialized_variables_test.cpp
deleted file mode 100644
index 06ba59a5..00000000
--- 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 cdcc9a83..b35ad474 100644
--- a/test/opt/desc_sroa_test.cpp
+++ b/test/opt/desc_sroa_test.cpp
@@ -729,6 +729,47 @@ TEST_F(DescriptorScalarReplacementTest, ResourceStructAsFunctionParam) {
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/fix_storage_class_test.cpp b/test/opt/fix_storage_class_test.cpp
index 4c8504ae..1c0101a0 100644
--- a/test/opt/fix_storage_class_test.cpp
+++ b/test/opt/fix_storage_class_test.cpp
@@ -528,6 +528,48 @@ TEST_F(FixStorageClassTest, FixLinkedAccessChain2) {
SinglePassRunAndMatch<FixStorageClass>(text, false);
}
+TEST_F(FixStorageClassTest, AllowImageFormatMismatch) {
+ const std::string text = R"(OpCapability Shader
+OpCapability SampledBuffer
+OpCapability ImageBuffer
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpSource HLSL 600
+OpName %type_buffer_image "type.buffer.image"
+OpName %Buf "Buf"
+OpName %main "main"
+OpName %src_main "src.main"
+OpName %bb_entry "bb.entry"
+OpName %type_buffer_image_0 "type.buffer.image"
+OpName %b "b"
+OpDecorate %Buf DescriptorSet 0
+OpDecorate %Buf Binding 0
+%float = OpTypeFloat 32
+%type_buffer_image = OpTypeImage %float Buffer 2 0 0 2 Rgba16f
+%_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image
+%void = OpTypeVoid
+%11 = OpTypeFunction %void
+%type_buffer_image_0 = OpTypeImage %float Buffer 2 0 0 2 Rgba32f
+%_ptr_Function_type_buffer_image_0 = OpTypePointer Function %type_buffer_image_0
+%Buf = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant
+%main = OpFunction %void None %11
+%13 = OpLabel
+%14 = OpFunctionCall %void %src_main
+OpReturn
+OpFunctionEnd
+%src_main = OpFunction %void None %11
+%bb_entry = OpLabel
+%b = OpVariable %_ptr_Function_type_buffer_image_0 Function
+%15 = OpLoad %type_buffer_image %Buf
+OpStore %b %15
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndCheck<FixStorageClass>(text, text, false, false);
+}
+
using FixTypeTest = PassTest<::testing::Test>;
TEST_F(FixTypeTest, FixAccessChain) {
diff --git a/test/opt/generate_webgpu_initializers_test.cpp b/test/opt/generate_webgpu_initializers_test.cpp
deleted file mode 100644
index 4aab2ce2..00000000
--- 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_test.cpp b/test/opt/inline_test.cpp
index d3ef09c3..29399013 100644
--- a/test/opt/inline_test.cpp
+++ b/test/opt/inline_test.cpp
@@ -2581,6 +2581,63 @@ OpFunctionEnd
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
//
diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp
index f1899627..1a42329b 100644
--- a/test/opt/inst_bindless_check_test.cpp
+++ b/test/opt/inst_bindless_check_test.cpp
@@ -7308,15 +7308,15 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
;CHECK: %_ptr_StorageBuffer__struct_128 = OpTypePointer StorageBuffer %_struct_128
;CHECK: %130 = OpVariable %_ptr_StorageBuffer__struct_128 StorageBuffer
;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
- ;CHECK: %uint_3 = OpConstant %uint 3
+ ;CHECK: %uint_4 = OpConstant %uint 4
;CHECK: %148 = OpTypeFunction %void %uint %uint %uint %uint %uint
;CHECK: %_struct_155 = OpTypeStruct %uint %_runtimearr_uint
;CHECK: %_ptr_StorageBuffer__struct_155 = OpTypePointer StorageBuffer %_struct_155
;CHECK: %157 = OpVariable %_ptr_StorageBuffer__struct_155 StorageBuffer
;CHECK: %uint_11 = OpConstant %uint 11
- ;CHECK: %uint_4 = OpConstant %uint 4
;CHECK: %uint_23 = OpConstant %uint 23
;CHECK: %uint_2 = OpConstant %uint 2
+ ;CHECK: %uint_3 = OpConstant %uint 3
;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float
;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
;CHECK: %v4uint = OpTypeVector %uint 4
@@ -7352,7 +7352,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
;CHECK: %146 = OpLoad %v2float %86
;CHECK: OpBranch %143
;CHECK: %145 = OpLabel
- ;CHECK: %201 = OpFunctionCall %void %147 %uint_71 %uint_3 %uint_0 %119 %140
+ ;CHECK: %201 = OpFunctionCall %void %147 %uint_71 %uint_4 %uint_0 %119 %140
;CHECK: OpBranch %143
;CHECK: %143 = OpLabel
;CHECK: %203 = OpPhi %v2float %146 %144 %202 %145
@@ -7369,7 +7369,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
;CHECK: %209 = OpLoad %v2float %89
;CHECK: OpBranch %206
;CHECK: %208 = OpLabel
- ;CHECK: %211 = OpFunctionCall %void %147 %uint_75 %uint_3 %uint_0 %204 %140
+ ;CHECK: %211 = OpFunctionCall %void %147 %uint_75 %uint_4 %uint_0 %204 %140
;CHECK: OpBranch %206
;CHECK: %206 = OpLabel
;CHECK: %212 = OpPhi %v2float %209 %207 %202 %208
@@ -7409,49 +7409,49 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
;CHECK: %153 = OpFunctionParameter %uint
;CHECK: %154 = OpLabel
;CHECK: %158 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_0
- ;CHECK: %161 = OpAtomicIAdd %uint %158 %uint_4 %uint_0 %uint_11
- ;CHECK: %162 = OpIAdd %uint %161 %uint_11
- ;CHECK: %163 = OpArrayLength %uint %157 1
- ;CHECK: %164 = OpULessThanEqual %bool %162 %163
- ;CHECK: OpSelectionMerge %165 None
- ;CHECK: OpBranchConditional %164 %166 %165
- ;CHECK: %166 = OpLabel
- ;CHECK: %167 = OpIAdd %uint %161 %uint_0
- ;CHECK: %168 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %167
- ;CHECK: OpStore %168 %uint_11
- ;CHECK: %170 = OpIAdd %uint %161 %uint_1
- ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %170
- ;CHECK: OpStore %171 %uint_23
- ;CHECK: %173 = OpIAdd %uint %161 %uint_2
- ;CHECK: %174 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %173
- ;CHECK: OpStore %174 %149
- ;CHECK: %175 = OpIAdd %uint %161 %uint_3
+ ;CHECK: %160 = OpAtomicIAdd %uint %158 %uint_4 %uint_0 %uint_11
+ ;CHECK: %161 = OpIAdd %uint %160 %uint_11
+ ;CHECK: %162 = OpArrayLength %uint %157 1
+ ;CHECK: %163 = OpULessThanEqual %bool %161 %162
+ ;CHECK: OpSelectionMerge %164 None
+ ;CHECK: OpBranchConditional %163 %165 %164
+ ;CHECK: %165 = OpLabel
+ ;CHECK: %166 = OpIAdd %uint %160 %uint_0
+ ;CHECK: %167 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %166
+ ;CHECK: OpStore %167 %uint_11
+ ;CHECK: %169 = OpIAdd %uint %160 %uint_1
+ ;CHECK: %170 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %169
+ ;CHECK: OpStore %170 %uint_23
+ ;CHECK: %172 = OpIAdd %uint %160 %uint_2
+ ;CHECK: %173 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %172
+ ;CHECK: OpStore %173 %149
+ ;CHECK: %175 = OpIAdd %uint %160 %uint_3
;CHECK: %176 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %175
;CHECK: OpStore %176 %uint_4
;CHECK: %179 = OpLoad %v4float %gl_FragCoord
;CHECK: %181 = OpBitcast %v4uint %179
;CHECK: %182 = OpCompositeExtract %uint %181 0
- ;CHECK: %183 = OpIAdd %uint %161 %uint_4
+ ;CHECK: %183 = OpIAdd %uint %160 %uint_4
;CHECK: %184 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %183
;CHECK: OpStore %184 %182
;CHECK: %185 = OpCompositeExtract %uint %181 1
- ;CHECK: %187 = OpIAdd %uint %161 %uint_5
+ ;CHECK: %187 = OpIAdd %uint %160 %uint_5
;CHECK: %188 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %187
;CHECK: OpStore %188 %185
- ;CHECK: %189 = OpIAdd %uint %161 %uint_7
+ ;CHECK: %189 = OpIAdd %uint %160 %uint_7
;CHECK: %190 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %189
;CHECK: OpStore %190 %150
- ;CHECK: %192 = OpIAdd %uint %161 %uint_8
+ ;CHECK: %192 = OpIAdd %uint %160 %uint_8
;CHECK: %193 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %192
;CHECK: OpStore %193 %151
- ;CHECK: %195 = OpIAdd %uint %161 %uint_9
+ ;CHECK: %195 = OpIAdd %uint %160 %uint_9
;CHECK: %196 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %195
;CHECK: OpStore %196 %152
- ;CHECK: %198 = OpIAdd %uint %161 %uint_10
+ ;CHECK: %198 = OpIAdd %uint %160 %uint_10
;CHECK: %199 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %198
;CHECK: OpStore %199 %153
- ;CHECK: OpBranch %165
- ;CHECK: %165 = OpLabel
+ ;CHECK: OpBranch %164
+ ;CHECK: %164 = OpLabel
;CHECK: OpReturn
;CHECK: OpFunctionEnd
)";
@@ -7596,14 +7596,14 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) {
;CHECK: %113 = OpVariable %_ptr_StorageBuffer__struct_111 StorageBuffer
;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
;CHECK: %bool = OpTypeBool
-;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %uint_4 = OpConstant %uint 4
;CHECK: %132 = OpTypeFunction %void %uint %uint %uint %uint %uint
;CHECK:%_struct_139 = OpTypeStruct %uint %_runtimearr_uint
;CHECK:%_ptr_StorageBuffer__struct_139 = OpTypePointer StorageBuffer %_struct_139
;CHECK: %141 = OpVariable %_ptr_StorageBuffer__struct_139 StorageBuffer
;CHECK: %uint_11 = OpConstant %uint 11
-;CHECK: %uint_4 = OpConstant %uint 4
;CHECK: %uint_23 = OpConstant %uint 23
+;CHECK: %uint_3 = OpConstant %uint 3
;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float
;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
;CHECK: %v4uint = OpTypeVector %uint 4
@@ -7637,7 +7637,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) {
;CHECK: %130 = OpLoad %v2float %81
;CHECK: OpBranch %127
;CHECK: %129 = OpLabel
-;CHECK: %184 = OpFunctionCall %void %131 %uint_78 %uint_3 %uint_0 %101 %123
+;CHECK: %184 = OpFunctionCall %void %131 %uint_78 %uint_4 %uint_0 %101 %123
;CHECK: OpBranch %127
;CHECK: %127 = OpLabel
;CHECK: %186 = OpPhi %v2float %130 %128 %185 %129
@@ -7674,49 +7674,49 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) {
;CHECK: %137 = OpFunctionParameter %uint
;CHECK: %138 = OpLabel
;CHECK: %142 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_0
-;CHECK: %145 = OpAtomicIAdd %uint %142 %uint_4 %uint_0 %uint_11
-;CHECK: %146 = OpIAdd %uint %145 %uint_11
-;CHECK: %147 = OpArrayLength %uint %141 1
-;CHECK: %148 = OpULessThanEqual %bool %146 %147
-;CHECK: OpSelectionMerge %149 None
-;CHECK: OpBranchConditional %148 %150 %149
-;CHECK: %150 = OpLabel
-;CHECK: %151 = OpIAdd %uint %145 %uint_0
-;CHECK: %152 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %151
-;CHECK: OpStore %152 %uint_11
-;CHECK: %154 = OpIAdd %uint %145 %uint_1
-;CHECK: %155 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %154
-;CHECK: OpStore %155 %uint_23
-;CHECK: %156 = OpIAdd %uint %145 %uint_2
-;CHECK: %157 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %156
-;CHECK: OpStore %157 %133
-;CHECK: %158 = OpIAdd %uint %145 %uint_3
+;CHECK: %144 = OpAtomicIAdd %uint %142 %uint_4 %uint_0 %uint_11
+;CHECK: %145 = OpIAdd %uint %144 %uint_11
+;CHECK: %146 = OpArrayLength %uint %141 1
+;CHECK: %147 = OpULessThanEqual %bool %145 %146
+;CHECK: OpSelectionMerge %148 None
+;CHECK: OpBranchConditional %147 %149 %148
+;CHECK: %149 = OpLabel
+;CHECK: %150 = OpIAdd %uint %144 %uint_0
+;CHECK: %151 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %150
+;CHECK: OpStore %151 %uint_11
+;CHECK: %153 = OpIAdd %uint %144 %uint_1
+;CHECK: %154 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %153
+;CHECK: OpStore %154 %uint_23
+;CHECK: %155 = OpIAdd %uint %144 %uint_2
+;CHECK: %156 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %155
+;CHECK: OpStore %156 %133
+;CHECK: %158 = OpIAdd %uint %144 %uint_3
;CHECK: %159 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %158
;CHECK: OpStore %159 %uint_4
;CHECK: %162 = OpLoad %v4float %gl_FragCoord
;CHECK: %164 = OpBitcast %v4uint %162
;CHECK: %165 = OpCompositeExtract %uint %164 0
-;CHECK: %166 = OpIAdd %uint %145 %uint_4
+;CHECK: %166 = OpIAdd %uint %144 %uint_4
;CHECK: %167 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %166
;CHECK: OpStore %167 %165
;CHECK: %168 = OpCompositeExtract %uint %164 1
-;CHECK: %170 = OpIAdd %uint %145 %uint_5
+;CHECK: %170 = OpIAdd %uint %144 %uint_5
;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %170
;CHECK: OpStore %171 %168
-;CHECK: %172 = OpIAdd %uint %145 %uint_7
+;CHECK: %172 = OpIAdd %uint %144 %uint_7
;CHECK: %173 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %172
;CHECK: OpStore %173 %134
-;CHECK: %175 = OpIAdd %uint %145 %uint_8
+;CHECK: %175 = OpIAdd %uint %144 %uint_8
;CHECK: %176 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %175
;CHECK: OpStore %176 %135
-;CHECK: %178 = OpIAdd %uint %145 %uint_9
+;CHECK: %178 = OpIAdd %uint %144 %uint_9
;CHECK: %179 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %178
;CHECK: OpStore %179 %136
-;CHECK: %181 = OpIAdd %uint %145 %uint_10
+;CHECK: %181 = OpIAdd %uint %144 %uint_10
;CHECK: %182 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %181
;CHECK: OpStore %182 %137
-;CHECK: OpBranch %149
-;CHECK: %149 = OpLabel
+;CHECK: OpBranch %148
+;CHECK: %148 = OpLabel
;CHECK: OpReturn
;CHECK: OpFunctionEnd
)";
@@ -7743,11 +7743,11 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
OpExecutionMode %MainPs OriginUpperLeft
OpSource HLSL 500
OpName %MainPs "MainPs"
- OpName %PerBatchEnvMapConstantBuffer_t
-"PerBatchEnvMapConstantBuffer_t" OpMemberName %PerBatchEnvMapConstantBuffer_t 0
-"g_matEnvMapWorldToLocal" OpMemberName %PerBatchEnvMapConstantBuffer_t 1
-"g_vEnvironmentMapBoxMins" OpMemberName %PerBatchEnvMapConstantBuffer_t 2
-"g_TexOff" OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
+ OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
+ OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
+ OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
+ OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
+ OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
OpName %_ ""
OpName %PerViewPushConst_t "PerViewPushConst_t"
@@ -7831,15 +7831,15 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
;CHECK: %113 = OpVariable %_ptr_StorageBuffer__struct_111 StorageBuffer
;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
;CHECK: %bool = OpTypeBool
-;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %uint_4 = OpConstant %uint 4
;CHECK: %135 = OpTypeFunction %void %uint %uint %uint %uint %uint
;CHECK:%_struct_142 = OpTypeStruct %uint %_runtimearr_uint
;CHECK:%_ptr_StorageBuffer__struct_142 = OpTypePointer StorageBuffer %_struct_142
;CHECK: %144 = OpVariable %_ptr_StorageBuffer__struct_142 StorageBuffer
;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_3 = OpConstant %uint 3
;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float
;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
;CHECK: %v4uint = OpTypeVector %uint 4
@@ -7878,13 +7878,15 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
;CHECK: %133 = OpLoad %v2float %81
;CHECK: OpBranch %130
;CHECK: %132 = OpLabel
-;CHECK: %188 = OpFunctionCall %void %134 %uint_78 %uint_3 %uint_0 %101 %126
+;CHECK: %188 = OpFunctionCall %void %134 %uint_78 %uint_4 %uint_0 %101 %126
;CHECK: OpBranch %130
;CHECK: %130 = OpLabel
;CHECK: %190 = OpPhi %v2float %133 %131 %189 %132
;CHECK: %86 = OpFAdd %v2float %66 %190
- %87 = OpLoad %46 %g_tColor %88 = OpLoad %50 %g_sAniso %89 =
- OpSampledImage %54 %87 %88 %91 = OpImageSampleImplicitLod %v4float %89 %86
+ %87 = OpLoad %46 %g_tColor
+ %88 = OpLoad %50 %g_sAniso
+ %89 = OpSampledImage %54 %87 %88
+ %91 = OpImageSampleImplicitLod %v4float %89 %86
OpStore %_entryPointOutput_vColor %91
;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86
;CHECK-NOT: OpStore %_entryPointOutput_vColor %91
@@ -7931,49 +7933,49 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
;CHECK: %140 = OpFunctionParameter %uint
;CHECK: %141 = OpLabel
;CHECK: %145 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_0
-;CHECK: %148 = OpAtomicIAdd %uint %145 %uint_4 %uint_0 %uint_11
-;CHECK: %149 = OpIAdd %uint %148 %uint_11
-;CHECK: %150 = OpArrayLength %uint %144 1
-;CHECK: %151 = OpULessThanEqual %bool %149 %150
-;CHECK: OpSelectionMerge %152 None
-;CHECK: OpBranchConditional %151 %153 %152
-;CHECK: %153 = OpLabel
-;CHECK: %154 = OpIAdd %uint %148 %uint_0
-;CHECK: %156 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %154
-;CHECK: OpStore %156 %uint_11
-;CHECK: %158 = OpIAdd %uint %148 %uint_1
-;CHECK: %159 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %158
-;CHECK: OpStore %159 %uint_23
-;CHECK: %160 = OpIAdd %uint %148 %uint_2
-;CHECK: %161 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %160
-;CHECK: OpStore %161 %136
-;CHECK: %162 = OpIAdd %uint %148 %uint_3
+;CHECK: %147 = OpAtomicIAdd %uint %145 %uint_4 %uint_0 %uint_11
+;CHECK: %148 = OpIAdd %uint %147 %uint_11
+;CHECK: %149 = OpArrayLength %uint %144 1
+;CHECK: %150 = OpULessThanEqual %bool %148 %149
+;CHECK: OpSelectionMerge %151 None
+;CHECK: OpBranchConditional %150 %152 %151
+;CHECK: %152 = OpLabel
+;CHECK: %153 = OpIAdd %uint %147 %uint_0
+;CHECK: %155 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %153
+;CHECK: OpStore %155 %uint_11
+;CHECK: %157 = OpIAdd %uint %147 %uint_1
+;CHECK: %158 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %157
+;CHECK: OpStore %158 %uint_23
+;CHECK: %159 = OpIAdd %uint %147 %uint_2
+;CHECK: %160 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %159
+;CHECK: OpStore %160 %136
+;CHECK: %162 = OpIAdd %uint %147 %uint_3
;CHECK: %163 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %162
;CHECK: OpStore %163 %uint_4
;CHECK: %166 = OpLoad %v4float %gl_FragCoord
;CHECK: %168 = OpBitcast %v4uint %166
;CHECK: %169 = OpCompositeExtract %uint %168 0
-;CHECK: %170 = OpIAdd %uint %148 %uint_4
+;CHECK: %170 = OpIAdd %uint %147 %uint_4
;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %170
;CHECK: OpStore %171 %169
;CHECK: %172 = OpCompositeExtract %uint %168 1
-;CHECK: %174 = OpIAdd %uint %148 %uint_5
+;CHECK: %174 = OpIAdd %uint %147 %uint_5
;CHECK: %175 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %174
;CHECK: OpStore %175 %172
-;CHECK: %176 = OpIAdd %uint %148 %uint_7
+;CHECK: %176 = OpIAdd %uint %147 %uint_7
;CHECK: %177 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %176
;CHECK: OpStore %177 %137
-;CHECK: %179 = OpIAdd %uint %148 %uint_8
+;CHECK: %179 = OpIAdd %uint %147 %uint_8
;CHECK: %180 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %179
;CHECK: OpStore %180 %138
-;CHECK: %182 = OpIAdd %uint %148 %uint_9
+;CHECK: %182 = OpIAdd %uint %147 %uint_9
;CHECK: %183 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %182
;CHECK: OpStore %183 %139
-;CHECK: %185 = OpIAdd %uint %148 %uint_10
+;CHECK: %185 = OpIAdd %uint %147 %uint_10
;CHECK: %186 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %185
;CHECK: OpStore %186 %140
-;CHECK: OpBranch %152
-;CHECK: %152 = OpLabel
+;CHECK: OpBranch %151
+;CHECK: %151 = OpLabel
;CHECK: OpReturn
;CHECK: OpFunctionEnd
)";
@@ -8344,15 +8346,15 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
;CHECK: %69 = OpVariable %_ptr_StorageBuffer__struct_67 StorageBuffer
;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
;CHECK: %bool = OpTypeBool
-;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %uint_4 = OpConstant %uint 4
;CHECK: %88 = OpTypeFunction %void %uint %uint %uint %uint %uint
;CHECK: %_struct_95 = OpTypeStruct %uint %_runtimearr_uint
;CHECK:%_ptr_StorageBuffer__struct_95 = OpTypePointer StorageBuffer %_struct_95
;CHECK: %97 = OpVariable %_ptr_StorageBuffer__struct_95 StorageBuffer
;CHECK: %uint_11 = OpConstant %uint 11
-;CHECK: %uint_4 = OpConstant %uint 4
;CHECK: %uint_23 = OpConstant %uint 23
;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %uint_3 = OpConstant %uint 3
;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float
;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
;CHECK: %v4uint = OpTypeVector %uint 4
@@ -8389,7 +8391,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
;CHECK: %86 = OpLoad %v2float %41
;CHECK: OpBranch %83
;CHECK: %85 = OpLabel
-;CHECK: %141 = OpFunctionCall %void %87 %uint_81 %uint_3 %uint_0 %58 %79
+;CHECK: %141 = OpFunctionCall %void %87 %uint_81 %uint_4 %uint_0 %58 %79
;CHECK: OpBranch %83
;CHECK: %83 = OpLabel
;CHECK: %143 = OpPhi %v2float %86 %84 %142 %85
@@ -8424,49 +8426,49 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
;CHECK: %93 = OpFunctionParameter %uint
;CHECK: %94 = OpLabel
;CHECK: %98 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_0
-;CHECK: %101 = OpAtomicIAdd %uint %98 %uint_4 %uint_0 %uint_11
-;CHECK: %102 = OpIAdd %uint %101 %uint_11
-;CHECK: %103 = OpArrayLength %uint %97 1
-;CHECK: %104 = OpULessThanEqual %bool %102 %103
-;CHECK: OpSelectionMerge %105 None
-;CHECK: OpBranchConditional %104 %106 %105
-;CHECK: %106 = OpLabel
-;CHECK: %107 = OpIAdd %uint %101 %uint_0
-;CHECK: %108 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %107
-;CHECK: OpStore %108 %uint_11
-;CHECK: %110 = OpIAdd %uint %101 %uint_1
-;CHECK: %111 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %110
-;CHECK: OpStore %111 %uint_23
-;CHECK: %113 = OpIAdd %uint %101 %uint_2
-;CHECK: %114 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %113
-;CHECK: OpStore %114 %89
-;CHECK: %115 = OpIAdd %uint %101 %uint_3
+;CHECK: %100 = OpAtomicIAdd %uint %98 %uint_4 %uint_0 %uint_11
+;CHECK: %101 = OpIAdd %uint %100 %uint_11
+;CHECK: %102 = OpArrayLength %uint %97 1
+;CHECK: %103 = OpULessThanEqual %bool %101 %102
+;CHECK: OpSelectionMerge %104 None
+;CHECK: OpBranchConditional %103 %105 %104
+;CHECK: %105 = OpLabel
+;CHECK: %106 = OpIAdd %uint %100 %uint_0
+;CHECK: %107 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %106
+;CHECK: OpStore %107 %uint_11
+;CHECK: %109 = OpIAdd %uint %100 %uint_1
+;CHECK: %110 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %109
+;CHECK: OpStore %110 %uint_23
+;CHECK: %112 = OpIAdd %uint %100 %uint_2
+;CHECK: %113 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %112
+;CHECK: OpStore %113 %89
+;CHECK: %115 = OpIAdd %uint %100 %uint_3
;CHECK: %116 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %115
;CHECK: OpStore %116 %uint_4
;CHECK: %119 = OpLoad %v4float %gl_FragCoord
;CHECK: %121 = OpBitcast %v4uint %119
;CHECK: %122 = OpCompositeExtract %uint %121 0
-;CHECK: %123 = OpIAdd %uint %101 %uint_4
+;CHECK: %123 = OpIAdd %uint %100 %uint_4
;CHECK: %124 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %123
;CHECK: OpStore %124 %122
;CHECK: %125 = OpCompositeExtract %uint %121 1
-;CHECK: %127 = OpIAdd %uint %101 %uint_5
+;CHECK: %127 = OpIAdd %uint %100 %uint_5
;CHECK: %128 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %127
;CHECK: OpStore %128 %125
-;CHECK: %129 = OpIAdd %uint %101 %uint_7
+;CHECK: %129 = OpIAdd %uint %100 %uint_7
;CHECK: %130 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %129
;CHECK: OpStore %130 %90
-;CHECK: %132 = OpIAdd %uint %101 %uint_8
+;CHECK: %132 = OpIAdd %uint %100 %uint_8
;CHECK: %133 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %132
;CHECK: OpStore %133 %91
-;CHECK: %135 = OpIAdd %uint %101 %uint_9
+;CHECK: %135 = OpIAdd %uint %100 %uint_9
;CHECK: %136 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %135
;CHECK: OpStore %136 %92
-;CHECK: %138 = OpIAdd %uint %101 %uint_10
+;CHECK: %138 = OpIAdd %uint %100 %uint_10
;CHECK: %139 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %138
;CHECK: OpStore %139 %93
-;CHECK: OpBranch %105
-;CHECK: %105 = OpLabel
+;CHECK: OpBranch %104
+;CHECK: %104 = OpLabel
;CHECK: OpReturn
;CHECK: OpFunctionEnd
)";
@@ -8557,6 +8559,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
%_ptr_Input_v4float = OpTypePointer Input %v4float
%a_position = OpVariable %_ptr_Input_v4float Input
;CHECK; %uint_0 = OpConstant %uint 0
+;CHECK; %uint_16 = OpConstant %uint 16
;CHECK; %uint_4 = OpConstant %uint 4
;CHECK; %uint_3 = OpConstant %uint 3
;CHECK; %37 = OpTypeFunction %uint %uint %uint %uint
@@ -8583,10 +8586,13 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
;CHECK; %uint_10 = OpConstant %uint 10
;CHECK; %uint_45 = OpConstant %uint 45
;CHECK; %115 = OpConstantNull %float
-;CHECK; %uint_27 = OpConstant %uint 27
%main = OpFunction %void None %3
%5 = OpLabel
;CHECK: %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0
+;CHECK: OpBranch %26
+;CHECK: %26 = OpLabel
+;CHECK: OpBranch %25
+;CHECK: %25 = OpLabel
%20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
%21 = OpLoad %float %20
;CHECK-NOT: %21 = OpLoad %float %20
@@ -8602,7 +8608,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
;CHECK: %61 = OpLoad %float %20
;CHECK: OpBranch %58
;CHECK: %60 = OpLabel
-;CHECK: %114 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55
+;CHECK: %114 = OpFunctionCall %void %62 %uint_45 %uint_4 %uint_0 %35 %55
;CHECK: OpBranch %58
;CHECK: %58 = OpLabel
;CHECK: %116 = OpPhi %float %61 %59 %115 %60
@@ -8790,9 +8796,14 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) {
;CHECK: %uint_9 = OpConstant %uint 9
;CHECK: %uint_10 = OpConstant %uint 10
;CHECK: %uint_45 = OpConstant %uint 45
+;CHECK: %114 = OpConstantNull %float
%main = OpFunction %void None %3
%5 = OpLabel
;CHECK: %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0
+;CHECK: OpBranch %26
+;CHECK: %26 = OpLabel
+;CHECK: OpBranch %25
+;CHECK: %25 = OpLabel
%20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
%21 = OpLoad %float %20
;CHECK-NOT: %21 = OpLoad %float %20
@@ -8808,7 +8819,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) {
;CHECK: %61 = OpLoad %float %20
;CHECK: OpBranch %58
;CHECK: %60 = OpLabel
-;CHECK: %113 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55
+;CHECK: %113 = OpFunctionCall %void %62 %uint_45 %uint_4 %uint_0 %35 %55
;CHECK: OpBranch %58
;CHECK: %58 = OpLabel
;CHECK: %115 = OpPhi %float %61 %59 %114 %60
@@ -9032,7 +9043,7 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) {
;CHECK: %70 = OpLoad %v2float %25
;CHECK: OpBranch %67
;CHECK: %69 = OpLabel
-;CHECK: %123 = OpFunctionCall %void %71 %uint_51 %uint_3 %uint_0 %43 %64
+;CHECK: %123 = OpFunctionCall %void %71 %uint_51 %uint_4 %uint_0 %43 %64
;CHECK: OpBranch %67
;CHECK: %67 = OpLabel
;CHECK: %125 = OpPhi %v2float %70 %68 %124 %69
@@ -9167,7 +9178,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) {
;CHECK: %uint = OpTypeInt 32 0
;CHECK: %uint_0 = OpConstant %uint 0
;CHECK: %bool = OpTypeBool
-;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %uint_7 = OpConstant %uint 7
;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint
;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint
@@ -9179,11 +9190,11 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) {
;CHECK: %uint_1 = OpConstant %uint 1
;CHECK: %uint_23 = OpConstant %uint 23
;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %uint_3 = OpConstant %uint 3
;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
@@ -9213,7 +9224,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) {
;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: %92 = OpFunctionCall %void %34 %uint_33 %uint_7 %uint_0 %23 %25
;CHECK: OpBranch %29
;CHECK: %29 = OpLabel
;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31
@@ -9244,19 +9255,19 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) {
;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: %66 = OpIAdd %uint %50 %uint_3
+;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %66
+;CHECK: OpStore %67 %uint_4
+;CHECK: %70 = OpLoad %v4float %gl_FragCoord
+;CHECK: %72 = OpBitcast %v4uint %70
+;CHECK: %73 = OpCompositeExtract %uint %72 0
+;CHECK: %74 = OpIAdd %uint %50 %uint_4
+;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %74
+;CHECK: OpStore %75 %73
+;CHECK: %76 = OpCompositeExtract %uint %72 1
+;CHECK: %78 = OpIAdd %uint %50 %uint_5
+;CHECK: %79 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %78
+;CHECK: OpStore %79 %76
;CHECK: %80 = OpIAdd %uint %50 %uint_7
;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80
;CHECK: OpStore %81 %37
@@ -9336,7 +9347,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) {
;CHECK: %uint = OpTypeInt 32 0
;CHECK: %uint_0 = OpConstant %uint 0
;CHECK: %bool = OpTypeBool
-;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %uint_7 = OpConstant %uint 7
;CHECK: %34 = OpTypeFunction %void %uint %uint %uint %uint %uint
;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
;CHECK: %_struct_42 = OpTypeStruct %uint %_runtimearr_uint
@@ -9348,11 +9359,11 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) {
;CHECK: %uint_1 = OpConstant %uint 1
;CHECK: %uint_23 = OpConstant %uint 23
;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %uint_3 = OpConstant %uint 3
;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
@@ -9380,7 +9391,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) {
;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: %91 = OpFunctionCall %void %33 %uint_34 %uint_7 %uint_0 %23 %25
;CHECK: OpBranch %29
;CHECK: %29 = OpLabel
OpReturn
@@ -9409,19 +9420,19 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) {
;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: %65 = OpIAdd %uint %49 %uint_3
+;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %44 %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 %49 %uint_4
+;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %73
+;CHECK: OpStore %74 %72
+;CHECK: %75 = OpCompositeExtract %uint %71 1
+;CHECK: %77 = OpIAdd %uint %49 %uint_5
+;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %77
+;CHECK: OpStore %78 %75
;CHECK: %79 = OpIAdd %uint %49 %uint_7
;CHECK: %80 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %79
;CHECK: OpStore %80 %36
@@ -9500,7 +9511,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) {
;CHECK: %uint = OpTypeInt 32 0
;CHECK: %uint_0 = OpConstant %uint 0
;CHECK: %bool = OpTypeBool
-;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %uint_6 = OpConstant %uint 6
;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint
;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint
@@ -9512,6 +9523,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) {
;CHECK: %uint_1 = OpConstant %uint 1
;CHECK: %uint_23 = OpConstant %uint 23
;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %uint_3 = OpConstant %uint 3
;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
;CHECK: %v4uint = OpTypeVector %uint 4
@@ -9521,7 +9533,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) {
;CHECK: %uint_9 = OpConstant %uint 9
;CHECK: %uint_10 = OpConstant %uint 10
;CHECK: %uint_32 = OpConstant %uint 32
-;CHECK: %93 = OpConstantNull %v4float
+;CHECK: %94 = OpConstantNull %v4float
%main = OpFunction %void None %3
%5 = OpLabel
;CHECK: OpBranch %21
@@ -9546,11 +9558,11 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) {
;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: %93 = OpFunctionCall %void %34 %uint_32 %uint_6 %uint_0 %23 %25
;CHECK: OpBranch %29
;CHECK: %29 = OpLabel
-;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31
-;CHECK: OpStore %x %94
+;CHECK: %95 = OpPhi %v4float %33 %30 %94 %31
+;CHECK: OpStore %x %95
OpReturn
OpFunctionEnd
;CHECK: %34 = OpFunction %void None %35
@@ -9577,31 +9589,31 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) {
;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: %66 = OpIAdd %uint %50 %uint_3
+;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %66
+;CHECK: OpStore %67 %uint_4
+;CHECK: %70 = OpLoad %v4float %gl_FragCoord
+;CHECK: %72 = OpBitcast %v4uint %70
+;CHECK: %73 = OpCompositeExtract %uint %72 0
+;CHECK: %74 = OpIAdd %uint %50 %uint_4
+;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %74
+;CHECK: OpStore %75 %73
+;CHECK: %76 = OpCompositeExtract %uint %72 1
+;CHECK: %78 = OpIAdd %uint %50 %uint_5
+;CHECK: %79 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %78
+;CHECK: OpStore %79 %76
+;CHECK: %81 = OpIAdd %uint %50 %uint_7
+;CHECK: %82 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %81
+;CHECK: OpStore %82 %37
+;CHECK: %84 = OpIAdd %uint %50 %uint_8
+;CHECK: %85 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %84
+;CHECK: OpStore %85 %38
+;CHECK: %87 = OpIAdd %uint %50 %uint_9
+;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %87
+;CHECK: OpStore %88 %39
+;CHECK: %90 = OpIAdd %uint %50 %uint_10
+;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %90
+;CHECK: OpStore %91 %40
;CHECK: OpBranch %54
;CHECK: %54 = OpLabel
;CHECK: OpReturn
@@ -9669,7 +9681,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) {
;CHECK: %uint = OpTypeInt 32 0
;CHECK: %uint_0 = OpConstant %uint 0
;CHECK: %bool = OpTypeBool
-;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %uint_6 = OpConstant %uint 6
;CHECK: %38 = OpTypeFunction %void %uint %uint %uint %uint %uint
;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
;CHECK: %_struct_46 = OpTypeStruct %uint %_runtimearr_uint
@@ -9681,6 +9693,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) {
;CHECK: %uint_1 = OpConstant %uint 1
;CHECK: %uint_23 = OpConstant %uint 23
;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %uint_3 = OpConstant %uint 3
;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
;CHECK: %v4uint = OpTypeVector %uint 4
@@ -9690,7 +9703,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) {
;CHECK: %uint_9 = OpConstant %uint 9
;CHECK: %uint_10 = OpConstant %uint 10
;CHECK: %uint_34 = OpConstant %uint 34
-;CHECK: %96 = OpConstantNull %v4float
+;CHECK: %97 = OpConstantNull %v4float
%main = OpFunction %void None %3
%5 = OpLabel
;CHECK: OpBranch %23
@@ -9717,11 +9730,11 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) {
;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: %96 = OpFunctionCall %void %37 %uint_34 %uint_6 %uint_0 %25 %27
;CHECK: OpBranch %31
;CHECK: %31 = OpLabel
-;CHECK: %97 = OpPhi %v4float %36 %32 %96 %33
-;CHECK: OpStore %x %97
+;CHECK: %98 = OpPhi %v4float %36 %32 %97 %33
+;CHECK: OpStore %x %98
OpReturn
OpFunctionEnd
;CHECK: %37 = OpFunction %void None %38
@@ -9748,31 +9761,31 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) {
;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: %69 = OpIAdd %uint %53 %uint_3
+;CHECK: %70 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %69
+;CHECK: OpStore %70 %uint_4
+;CHECK: %73 = OpLoad %v4float %gl_FragCoord
+;CHECK: %75 = OpBitcast %v4uint %73
+;CHECK: %76 = OpCompositeExtract %uint %75 0
+;CHECK: %77 = OpIAdd %uint %53 %uint_4
+;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %77
+;CHECK: OpStore %78 %76
+;CHECK: %79 = OpCompositeExtract %uint %75 1
+;CHECK: %81 = OpIAdd %uint %53 %uint_5
+;CHECK: %82 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %81
+;CHECK: OpStore %82 %79
+;CHECK: %84 = OpIAdd %uint %53 %uint_7
+;CHECK: %85 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %84
+;CHECK: OpStore %85 %40
+;CHECK: %87 = OpIAdd %uint %53 %uint_8
+;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %87
+;CHECK: OpStore %88 %41
+;CHECK: %90 = OpIAdd %uint %53 %uint_9
+;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %90
+;CHECK: OpStore %91 %42
+;CHECK: %93 = OpIAdd %uint %53 %uint_10
+;CHECK: %94 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %93
+;CHECK: OpStore %94 %43
;CHECK: OpBranch %57
;CHECK: %57 = OpLabel
;CHECK: OpReturn
@@ -9847,7 +9860,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) {
;CHECK: %uint = OpTypeInt 32 0
;CHECK: %uint_0 = OpConstant %uint 0
;CHECK: %bool = OpTypeBool
-;CHECK: %uint_3 = OpConstant %uint 3
+;CHECK: %uint_6 = OpConstant %uint 6
;CHECK: %44 = OpTypeFunction %void %uint %uint %uint %uint %uint
;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
;CHECK: %_struct_52 = OpTypeStruct %uint %_runtimearr_uint
@@ -9859,6 +9872,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) {
;CHECK: %uint_1 = OpConstant %uint 1
;CHECK: %uint_23 = OpConstant %uint 23
;CHECK: %uint_2 = OpConstant %uint 2
+;CHECK: %uint_3 = OpConstant %uint 3
;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
;CHECK: %v4uint = OpTypeVector %uint 4
@@ -9868,7 +9882,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) {
;CHECK: %uint_9 = OpConstant %uint 9
;CHECK: %uint_10 = OpConstant %uint 10
;CHECK: %uint_42 = OpConstant %uint 42
-;CHECK: %102 = OpConstantNull %v4float
+;CHECK: %103 = OpConstantNull %v4float
%main = OpFunction %void None %3
%5 = OpLabel
;CHECK: OpBranch %28
@@ -9898,11 +9912,11 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) {
;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: %102 = OpFunctionCall %void %43 %uint_42 %uint_6 %uint_0 %30 %32
;CHECK: OpBranch %36
;CHECK: %36 = OpLabel
-;CHECK: %103 = OpPhi %v4float %42 %37 %102 %38
-;CHECK: OpStore %x %103
+;CHECK: %104 = OpPhi %v4float %42 %37 %103 %38
+;CHECK: OpStore %x %104
OpReturn
OpFunctionEnd
;CHECK: %43 = OpFunction %void None %44
@@ -9929,31 +9943,31 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) {
;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: %75 = OpIAdd %uint %59 %uint_3
+;CHECK: %76 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %75
+;CHECK: OpStore %76 %uint_4
+;CHECK: %79 = OpLoad %v4float %gl_FragCoord
+;CHECK: %81 = OpBitcast %v4uint %79
+;CHECK: %82 = OpCompositeExtract %uint %81 0
+;CHECK: %83 = OpIAdd %uint %59 %uint_4
+;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %83
+;CHECK: OpStore %84 %82
+;CHECK: %85 = OpCompositeExtract %uint %81 1
+;CHECK: %87 = OpIAdd %uint %59 %uint_5
+;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %87
+;CHECK: OpStore %88 %85
+;CHECK: %90 = OpIAdd %uint %59 %uint_7
+;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %90
+;CHECK: OpStore %91 %46
+;CHECK: %93 = OpIAdd %uint %59 %uint_8
+;CHECK: %94 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %93
+;CHECK: OpStore %94 %47
+;CHECK: %96 = OpIAdd %uint %59 %uint_9
+;CHECK: %97 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %96
+;CHECK: OpStore %97 %48
+;CHECK: %99 = OpIAdd %uint %59 %uint_10
+;CHECK: %100 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %99
+;CHECK: OpStore %100 %49
;CHECK: OpBranch %63
;CHECK: %63 = OpLabel
;CHECK: OpReturn
diff --git a/test/opt/legalize_vector_shuffle_test.cpp b/test/opt/legalize_vector_shuffle_test.cpp
deleted file mode 100644
index 07d96eb3..00000000
--- 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/local_single_store_elim_test.cpp b/test/opt/local_single_store_elim_test.cpp
index d015dfba..c94ff372 100644
--- a/test/opt/local_single_store_elim_test.cpp
+++ b/test/opt/local_single_store_elim_test.cpp
@@ -1403,18 +1403,20 @@ TEST_F(LocalSingleStoreElimTest, AddDebugValueforStoreOutOfDebugDeclareScope) {
%param_var_pos = OpVariable %_ptr_Function_v4float Function
%param_var_color = OpVariable %_ptr_Function_v4float Function
%55 = OpLoad %v4float %in_var_POSITION
+ OpLine %7 6 23
OpStore %param_var_pos %55
+ OpNoLine
%56 = OpLoad %v4float %in_var_COLOR
;CHECK: DebugNoScope
;CHECK-NOT: OpLine
;CHECK: [[pos:%\w+]] = OpLoad %v4float %in_var_POSITION
;CHECK: [[color:%\w+]] = OpLoad %v4float %in_var_COLOR
+ OpLine %7 7 23
OpStore %param_var_color %56
+ OpNoLine
%93 = OpExtInst %void %1 DebugScope %48
- OpLine %7 6 23
%73 = OpExtInst %void %1 DebugDeclare %53 %param_var_pos %52
- OpLine %7 7 23
%74 = OpExtInst %void %1 DebugDeclare %51 %param_var_color %52
;CHECK: OpLine [[file:%\w+]] 6 23
;CHECK-NEXT: {{%\w+}} = OpExtInst %void {{%\w+}} DebugValue [[dbg_pos]] [[pos]] [[empty_expr:%\w+]]
diff --git a/test/opt/local_ssa_elim_test.cpp b/test/opt/local_ssa_elim_test.cpp
index 9baf8da8..ca9aba33 100644
--- a/test/opt/local_ssa_elim_test.cpp
+++ b/test/opt/local_ssa_elim_test.cpp
@@ -2261,9 +2261,13 @@ TEST_F(LocalSSAElimTest, AddDebugValueForFunctionParameterWithPhi) {
%69 = OpExtInst %void %1 DebugLexicalBlock %60 7 21 %68
%70 = OpExtInst %void %1 DebugLocalVariable %11 %59 %60 6 26 %67 FlagIsLocal 2
+; CHECK: [[color_name:%\w+]] = OpString "color"
+; CHECK: [[pos_name:%\w+]] = OpString "pos"
; CHECK: [[i_name:%\w+]] = OpString "i"
; CHECK: [[null_expr:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugExpression
; CHECK: [[dbg_i:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable [[i_name]] {{%\w+}} {{%\w+}} 6 16 {{%\w+}} FlagIsLocal 1
+; CHECK: [[dbg_color:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable [[color_name]] {{%\w+}} {{%\w+}} 15 23
+; CHECK: [[dbg_pos:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable [[pos_name]] {{%\w+}} {{%\w+}} 14 23
%71 = OpExtInst %void %1 DebugLocalVariable %15 %65 %60 6 16 %67 FlagIsLocal 1
%72 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %62 %59 %59
%73 = OpExtInst %void %1 DebugFunction %16 %72 %60 14 1 %61 %14 FlagIsProtected|FlagIsPrivate 15 %156
@@ -2282,13 +2286,23 @@ TEST_F(LocalSSAElimTest, AddDebugValueForFunctionParameterWithPhi) {
%169 = OpExtInst %void %1 DebugNoScope
%param_var_pos = OpVariable %_ptr_Function_v4float Function
%param_var_color = OpVariable %_ptr_Function_v4float Function
+ OpLine %7 100 105
%80 = OpLoad %v4float %in_var_POSITION
OpStore %param_var_pos %80
+ OpNoLine
+ OpLine %7 200 205
%81 = OpLoad %v4float %in_var_COLOR
OpStore %param_var_color %81
+ OpNoLine
%170 = OpExtInst %void %1 DebugScope %73
+
+; CHECK: OpLine {{%\w+}} 100 105
+; CHECK: DebugValue [[dbg_pos]]
%124 = OpExtInst %void %1 DebugDeclare %78 %param_var_pos %77
+; CHECK: OpLine {{%\w+}} 200 205
+; CHECK: DebugValue [[dbg_color]]
%125 = OpExtInst %void %1 DebugDeclare %76 %param_var_color %77
+
%171 = OpExtInst %void %1 DebugScope %74
OpLine %7 17 18
diff --git a/test/opt/optimizer_test.cpp b/test/opt/optimizer_test.cpp
index 945aa782..a51638a1 100644
--- a/test/opt/optimizer_test.cpp
+++ b/test/opt/optimizer_test.cpp
@@ -221,545 +221,171 @@ TEST(Optimizer, CanRegisterPassesFromFlags) {
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;
-};
+TEST(Optimizer, RemoveNop) {
+ // Test that OpNops are removed even if no optimizations are run.
+ const std::string before = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%2 = OpTypeFunction %void
+%3 = OpFunction %void None %2
+%4 = OpLabel
+OpNop
+OpReturn
+OpFunctionEnd
+)";
-using VulkanToWebGPUPassTest =
- PassTest<::testing::TestWithParam<VulkanToWebGPUPassCase>>;
+ const std::string after = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%2 = OpTypeFunction %void
+%3 = OpFunction %void None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
-TEST_P(VulkanToWebGPUPassTest, Ran) {
std::vector<uint32_t> binary;
{
SpirvTools tools(SPV_ENV_VULKAN_1_1);
- tools.Assemble(GetParam().input, &binary);
+ tools.Assemble(before, &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";
+ << 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);
}
- 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]);
+ EXPECT_EQ(after, disassembly)
+ << "Was expecting the OpNop to have been removed.";
}
-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;
-};
+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
+)";
-using WebGPUToVulkanPassTest =
- PassTest<::testing::TestWithParam<WebGPUToVulkanPassCase>>;
+ 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
+)";
-TEST_P(WebGPUToVulkanPassTest, Ran) {
std::vector<uint32_t> binary;
- {
- SpirvTools tools(SPV_ENV_WEBGPU_0);
- tools.Assemble(GetParam().input, &binary);
- }
+ SpirvTools tools(SPV_ENV_VULKAN_1_1);
+ tools.Assemble(before, &binary);
- Optimizer opt(SPV_ENV_WEBGPU_0);
- opt.RegisterWebGPUToVulkanPasses();
+ 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));
+ validator_options, true))
+ << before << "\n";
+
std::string disassembly;
- {
- SpirvTools tools(SPV_ENV_VULKAN_1_1);
- tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
- }
+ tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
- EXPECT_EQ(GetParam().expected, disassembly)
- << "Was expecting pass '" << GetParam().pass << "' to have been run.\n";
+ EXPECT_EQ(after, disassembly)
+ << "Was expecting the OpLine to have been propagated.";
}
-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.
+TEST(Optimizer, AvoidIntegrityCheckForDebugScope) {
+ // Test that it avoids the integrity check when the code contains DebugScope.
const std::string before = R"(OpCapability Shader
-OpCapability Linkage
+%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
-%2 = OpTypeFunction %void
-%3 = OpFunction %void None %2
-%4 = OpLabel
-OpNop
+%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
-OpCapability Linkage
+%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
-%2 = OpTypeFunction %void
-%3 = OpFunction %void None %2
-%4 = OpLabel
+%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);
- }
+ 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))
+ ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized))
<< before << "\n";
+
std::string disassembly;
- {
- SpirvTools tools(SPV_ENV_WEBGPU_0);
- tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
- }
+ tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
EXPECT_EQ(after, disassembly)
- << "Was expecting the OpNop to have been removed.";
+ << "Was expecting the result id of DebugScope to have been changed.";
}
} // namespace
diff --git a/test/opt/split_invalid_unreachable_test.cpp b/test/opt/split_invalid_unreachable_test.cpp
deleted file mode 100644
index 520af015..00000000
--- 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 90daa59c..00000000
--- 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 9c86e2da..4acb8ff2 100644
--- a/test/target_env_test.cpp
+++ b/test/target_env_test.cpp
@@ -95,7 +95,6 @@ INSTANTIATE_TEST_SUITE_P(
{"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 f8117d9d..c79f6807 100644
--- a/test/tools/opt/flags.py
+++ b/test/tools/opt/flags.py
@@ -73,10 +73,7 @@ class TestValidPassFlags(expect.ValidObjectFile1_5,
'--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 @@ class TestValidPassFlags(expect.ValidObjectFile1_5,
'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 @@ class TestLoopPeelingThresholdArgsInvalidNumber(expect.ErrorMessageSubstr):
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 32646620..f0a2958d 100644
--- a/test/unit_spirv.h
+++ b/test/unit_spirv.h
@@ -195,7 +195,7 @@ inline std::vector<spv_target_env> AllTargetEnvironments() {
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 153a9167..b17d1cb1 100644
--- a/test/val/CMakeLists.txt
+++ b/test/val/CMakeLists.txt
@@ -89,7 +89,6 @@ add_spvtools_unittest(TARGET val_stuvw
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 aca0f3c9..fccfabc3 100644
--- a/test/val/val_atomics_test.cpp
+++ b/test/val/val_atomics_test.cpp
@@ -30,16 +30,16 @@ using ValidateAtomics = spvtest::ValidateBase<bool>;
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 @@ std::string GenerateShaderCode(
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 @@ std::string GenerateShaderCode(
)";
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 @@ TEST_F(ValidateAtomics, AtomicLoadInt32VulkanSuccess) {
%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 @@ TEST_F(ValidateAtomics, AtomicLoadFloatVulkan) {
%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 @@ TEST_F(ValidateAtomics, AtomicLoadInt64WithCapabilityVulkanSuccess) {
%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 @@ TEST_F(ValidateAtomics, AtomicLoadInt64WithoutCapabilityVulkan) {
%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 @@ OpAtomicStore %f32_var_function %device %relaxed %f32_1
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."));
}
@@ -447,6 +477,8 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanRelease) {
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-OpAtomicLoad-04731"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Vulkan spec disallows OpAtomicLoad with Memory Semantics "
@@ -460,6 +492,8 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanAcquireRelease) {
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-OpAtomicLoad-04731"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Vulkan spec disallows OpAtomicLoad with Memory Semantics "
@@ -473,6 +507,8 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanSequentiallyConsistent) {
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-OpAtomicLoad-04731"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Vulkan spec disallows OpAtomicLoad with Memory Semantics "
@@ -501,39 +537,6 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanInt64) {
"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
@@ -678,6 +681,8 @@ OpAtomicStore %u32_var %device %acquire %u32_1
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-OpAtomicStore-04730"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Vulkan spec disallows OpAtomicStore with Memory Semantics "
@@ -691,6 +696,8 @@ OpAtomicStore %u32_var %device %acquire_release %u32_1
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-OpAtomicStore-04730"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Vulkan spec disallows OpAtomicStore with Memory Semantics "
@@ -704,44 +711,14 @@ OpAtomicStore %u32_var %device %sequentially_consistent %u32_1
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-OpAtomicStore-04730"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Vulkan spec disallows OpAtomicStore with Memory Semantics "
"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 +2009,6 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 8bd10d42..46f5b5a1 100644
--- a/test/val/val_barriers_test.cpp
+++ b/test/val/val_barriers_test.cpp
@@ -121,40 +121,13 @@ OpCapability Int64
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 @@ OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
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 @@ OpControlBarrier %device %workgroup %none
"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 @@ OpControlBarrier %subgroup %subgroup %none
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 @@ OpControlBarrier %subgroup %cross_device %none
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 @@ OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup
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 @@ OpMemoryBarrier %subgroup %acquire_release_uniform_workgroup
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 @@ OpMemoryBarrier %device %none
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-04732"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("MemoryBarrier: Vulkan specification requires Memory Semantics "
@@ -935,6 +737,8 @@ OpMemoryBarrier %device %acquire
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-04733"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
"Vulkan-supported storage class"));
}
@@ -947,6 +751,8 @@ OpMemoryBarrier %device %acquire_release_subgroup
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04733"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
"Vulkan-supported storage class"));
}
@@ -1629,6 +1435,8 @@ TEST_F(ValidateBarriers, OpMemoryBarrierShaderCallComputeFailure) {
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 936279a2..bbcdbb11 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -54,18 +54,14 @@ using ::testing::Values;
using ::testing::ValuesIn;
using ValidateBuiltIns = spvtest::ValidateBase<bool>;
-using ValidateVulkanSubgroupBuiltIns = spvtest::ValidateBase<
- std::tuple<const char*, const char*, const char*, const char*, TestResult>>;
-using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult =
+using ValidateVulkanSubgroupBuiltIns =
spvtest::ValidateBase<std::tuple<const char*, const char*, const char*,
const char*, const char*, TestResult>>;
-using ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult =
+using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult =
spvtest::ValidateBase<std::tuple<const char*, const char*, const char*,
- const char*, TestResult>>;
+ 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 @@ using ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResu
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 @@ CodeGenerator GetInMainCodeGenerator(spv_target_env env,
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 @@ CodeGenerator GetInMainCodeGenerator(spv_target_env env,
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 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) {
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(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) {
}
}
-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 @@ TEST_P(
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 @@ TEST_P(
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 @@ TEST_P(
}
}
-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 @@ CodeGenerator GetInFunctionCodeGenerator(spv_target_env env,
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 @@ OpReturn
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 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) {
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(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) {
}
}
-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 @@ TEST_P(
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 @@ TEST_P(
}
}
-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 @@ CodeGenerator GetVariableCodeGenerator(spv_target_env env,
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 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) {
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(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) {
}
}
-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 @@ TEST_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
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 "
@@ -667,7 +559,9 @@ 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 @@ INSTANTIATE_TEST_SUITE_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
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 @@ INSTANTIATE_TEST_SUITE_P(
"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 @@ INSTANTIATE_TEST_SUITE_P(
"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"),
@@ -1918,7 +1596,8 @@ INSTANTIATE_TEST_SUITE_P(
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 "
@@ -1929,7 +1608,8 @@ INSTANTIATE_TEST_SUITE_P(
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 "
@@ -2005,7 +1685,8 @@ INSTANTIATE_TEST_SUITE_P(
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 "
@@ -2016,7 +1697,8 @@ INSTANTIATE_TEST_SUITE_P(
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 "
@@ -2070,12 +1752,6 @@ INSTANTIATE_TEST_SUITE_P(
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"),
@@ -2087,14 +1763,6 @@ INSTANTIATE_TEST_SUITE_P(
"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(
@@ -2105,16 +1773,6 @@ INSTANTIATE_TEST_SUITE_P(
"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"),
@@ -2125,15 +1783,6 @@ INSTANTIATE_TEST_SUITE_P(
"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"),
@@ -2143,50 +1792,6 @@ INSTANTIATE_TEST_SUITE_P(
"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"),
@@ -2938,14 +2543,11 @@ INSTANTIATE_TEST_SUITE_P(
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 3-component 32-bit int vector"))));
-CodeGenerator GetArrayedVariableCodeGenerator(spv_target_env env,
- const char* const built_in,
+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;
@@ -2953,14 +2555,14 @@ CodeGenerator GetArrayedVariableCodeGenerator(spv_target_env env,
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";
@@ -3009,7 +2611,7 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) {
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,
@@ -3022,27 +2624,6 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) {
}
}
-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"),
@@ -3089,14 +2670,6 @@ INSTANTIATE_TEST_SUITE_P(
"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"),
@@ -3199,10 +2772,8 @@ INSTANTIATE_TEST_SUITE_P(
"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
@@ -3224,22 +2795,13 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize
}
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
@@ -3262,8 +2824,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize
}
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));
@@ -3279,20 +2840,6 @@ TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeFragment) {
"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"(
@@ -3318,10 +2865,8 @@ OpDecorate %copy BuiltIn WorkgroupSize
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
@@ -3343,8 +2888,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize
}
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));
@@ -3356,22 +2900,8 @@ TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVector) {
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
@@ -3393,8 +2923,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize
}
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));
@@ -3406,22 +2935,8 @@ TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotIntVector) {
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
@@ -3443,8 +2958,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize
}
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));
@@ -3456,17 +2970,6 @@ TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVec3) {
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"(
@@ -3744,10 +3247,8 @@ OpFunctionEnd
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
@@ -3780,17 +3281,13 @@ OpReturn
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));
@@ -3801,21 +3298,8 @@ TEST_F(ValidateBuiltIns, VulkanFragmentFragDepthNoDepthReplacing) {
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
@@ -3859,19 +3343,14 @@ OpReturn
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));
@@ -3882,17 +3361,6 @@ TEST_F(ValidateBuiltIns,
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();
@@ -4047,7 +3515,8 @@ TEST_P(ValidateVulkanSubgroupBuiltIns, InMain) {
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"(
@@ -4107,6 +3576,9 @@ OpCapability GroupNonUniformBallot
if (test_result.error_str2) {
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
}
+ if (vuid) {
+ EXPECT_THAT(getDiagnosticString(), AnyVUID(vuid));
+ }
}
INSTANTIATE_TEST_SUITE_P(
@@ -4114,6 +3586,11 @@ INSTANTIATE_TEST_SUITE_P(
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"))));
@@ -4122,6 +3599,11 @@ INSTANTIATE_TEST_SUITE_P(
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"))));
@@ -4131,6 +3613,11 @@ INSTANTIATE_TEST_SUITE_P(
"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"))));
@@ -4140,7 +3627,7 @@ INSTANTIATE_TEST_SUITE_P(SubgroupMaskOk, ValidateVulkanSubgroupBuiltIns,
"SubgroupGtMask", "SubgroupLeMask",
"SubgroupLtMask"),
Values("GLCompute"), Values("Input"),
- Values("%u32vec4"),
+ Values("%u32vec4"), Values(nullptr),
Values(TestResult(SPV_SUCCESS, ""))));
TEST_F(ValidateBuiltIns, SubgroupMaskMemberDecorate) {
@@ -4173,6 +3660,8 @@ INSTANTIATE_TEST_SUITE_P(
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"))));
@@ -4181,6 +3670,8 @@ INSTANTIATE_TEST_SUITE_P(
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"))));
@@ -4189,7 +3680,7 @@ INSTANTIATE_TEST_SUITE_P(
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"(
@@ -4217,9 +3708,21 @@ OpFunctionEnd
}
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"))));
@@ -4227,6 +3730,8 @@ INSTANTIATE_TEST_SUITE_P(
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"))));
@@ -4234,7 +3739,7 @@ INSTANTIATE_TEST_SUITE_P(
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) {
@@ -4436,6 +3941,184 @@ INSTANTIATE_TEST_SUITE_P(
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 9705cb8f..82f8d381 100644
--- a/test/val/val_capability_test.cpp
+++ b/test/val/val_capability_test.cpp
@@ -116,8 +116,6 @@ using ValidateCapabilityOpenGL40 = spvtest::ValidateBase<CapTestParameter>;
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 @@ const std::vector<std::string>& AllVulkan12Capabilities() {
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 @@ const char kGLSL450MemoryModel[] = \
" 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 @@ std::make_pair(std::string(kGLSL450MemoryModel) +
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(ValidateCapabilityOpenGL40, Capability) {
}
}
-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 7a268ebb..9698fb1c 100644
--- a/test/val/val_cfg_test.cpp
+++ b/test/val/val_cfg_test.cpp
@@ -168,15 +168,6 @@ const std::string& GetDefaultHeader(SpvCapability cap) {
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"
@@ -714,10 +705,8 @@ TEST_P(ValidateCFG, HeaderDoesntStrictlyDominateMergeBad) {
}
}
-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 @@ std::string GetUnreachableMergeNoMergeInst(SpvCapability cap,
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 @@ std::string GetUnreachableMergeNoMergeInst(SpvCapability cap,
}
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 @@ std::string GetUnreachableMergeTerminatedBy(SpvCapability cap,
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 @@ std::string GetUnreachableMergeTerminatedBy(SpvCapability cap,
}
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 @@ std::string GetUnreachableContinueTerminatedBy(SpvCapability cap,
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 @@ std::string GetUnreachableContinueTerminatedBy(SpvCapability cap,
}
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_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpUnreachable) {
}
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, UnreachableContinueTerminatedBySpvOpReturn) {
}
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 @@ std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap,
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 @@ std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap,
}
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 @@ std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap,
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 @@ std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap,
}
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_P(ValidateCFG, UnreachableContinueUnreachableLoopInst) {
}
}
-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 @@ std::string GetUnreachableMergeWithComplexBody(SpvCapability cap,
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 @@ std::string GetUnreachableMergeWithComplexBody(SpvCapability cap,
}
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 @@ std::string GetUnreachableContinueWithComplexBody(SpvCapability cap,
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 @@ std::string GetUnreachableContinueWithComplexBody(SpvCapability cap,
}
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 @@ std::string GetUnreachableMergeWithBranchUse(SpvCapability cap,
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 @@ std::string GetUnreachableMergeWithBranchUse(SpvCapability cap,
}
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 @@ std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap,
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 @@ std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap,
}
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_P(ValidateCFG, UnreachableMergeWithMultipleUses) {
}
}
-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 @@ std::string GetUnreachableContinueWithBranchUse(SpvCapability cap,
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 @@ std::string GetUnreachableContinueWithBranchUse(SpvCapability cap,
}
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 @@ std::string GetReachableMergeAndContinue(SpvCapability cap,
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 @@ std::string GetReachableMergeAndContinue(SpvCapability cap,
}
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 @@ std::string GetUnreachableMergeAndContinue(SpvCapability cap,
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 @@ std::string GetUnreachableMergeAndContinue(SpvCapability cap,
}
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 @@ std::string GetUnreachableBlock(SpvCapability cap, spv_target_env env) {
}
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 @@ std::string GetUnreachableBranch(SpvCapability cap, spv_target_env env) {
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 @@ std::string GetUnreachableBranch(SpvCapability cap, spv_target_env env) {
}
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
diff --git a/test/val/val_code_generator.cpp b/test/val/val_code_generator.cpp
index 96971f9b..f151f51a 100644
--- a/test/val/val_code_generator.cpp
+++ b/test/val/val_code_generator.cpp
@@ -32,13 +32,6 @@ OpCapability SampleRateShading
)";
}
-std::string GetWebGPUShaderCapabilities() {
- return R"(
-OpCapability Shader
-OpCapability VulkanMemoryModelKHR
-)";
-}
-
std::string GetDefaultShaderTypes() {
return R"(
%void = OpTypeVoid
@@ -127,55 +120,6 @@ std::string GetDefaultShaderTypes() {
)";
}
-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
-)";
-}
-
} // namespace
CodeGenerator CodeGenerator::GetDefaultShaderCodeGenerator() {
@@ -186,15 +130,6 @@ CodeGenerator CodeGenerator::GetDefaultShaderCodeGenerator() {
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 e580ddff..c69deeec 100644
--- a/test/val/val_code_generator.h
+++ b/test/val/val_code_generator.h
@@ -31,7 +31,6 @@ struct EntryPoint {
class CodeGenerator {
public:
static CodeGenerator GetDefaultShaderCodeGenerator();
- static CodeGenerator GetWebGPUShaderCodeGenerator();
std::string Build() const;
diff --git a/test/val/val_conversion_test.cpp b/test/val/val_conversion_test.cpp
index 47e67938..b9802ece 100644
--- a/test/val/val_conversion_test.cpp
+++ b/test/val/val_conversion_test.cpp
@@ -1464,16 +1464,16 @@ OpFunctionEnd
TEST_F(ValidateConversion, ConvertUToPtrPSBSuccess) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%uint64 = OpTypeInt 64 0
%u64_1 = OpConstant %uint64 1
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%main = OpFunction %void None %voidfn
@@ -1489,11 +1489,11 @@ OpFunctionEnd
TEST_F(ValidateConversion, ConvertUToPtrPSBStorageClass) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%uint64 = OpTypeInt 64 0
@@ -1513,22 +1513,54 @@ OpFunctionEnd
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Pointer storage class must be "
- "PhysicalStorageBufferEXT: ConvertUToPtr"));
+ "PhysicalStorageBuffer: ConvertUToPtr"));
+}
+
+TEST_F(ValidateConversion, ConvertUToPtrVulkanWrongWidth) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint32 = OpTypeInt 32 0
+%uint64 = OpTypeInt 64 0
+%u32_1 = OpConstant %uint32 1
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpConvertUToPtr %ptr %u32_1
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("PhysicalStorageBuffer64 addressing mode requires the input "
+ "integer to have a 64-bit width for Vulkan environment."));
}
TEST_F(ValidateConversion, ConvertPtrToUPSBSuccess) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpDecorate %val1 RestrictPointerEXT
%uint64 = OpTypeInt 64 0
%u64_1 = OpConstant %uint64 1
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%pptr_f = OpTypePointer Function %ptr
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
@@ -1547,11 +1579,11 @@ OpFunctionEnd
TEST_F(ValidateConversion, ConvertPtrToUPSBStorageClass) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%uint64 = OpTypeInt 64 0
@@ -1571,7 +1603,42 @@ OpFunctionEnd
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Pointer storage class must be "
- "PhysicalStorageBufferEXT: ConvertPtrToU"));
+ "PhysicalStorageBuffer: ConvertPtrToU"));
+}
+
+TEST_F(ValidateConversion, ConvertPtrToUVulkanWrongWidth) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 RestrictPointerEXT
+%uint32 = OpTypeInt 32 0
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpConvertPtrToU %uint32 %val2
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("PhysicalStorageBuffer64 addressing mode requires the result "
+ "integer type to have a 64-bit width for Vulkan environment."));
}
using ValidateSmallConversions = spvtest::ValidateBase<std::string>;
diff --git a/test/val/val_data_test.cpp b/test/val/val_data_test.cpp
index 30afd03c..1d4c0e04 100644
--- a/test/val/val_data_test.cpp
+++ b/test/val/val_data_test.cpp
@@ -36,24 +36,6 @@ std::string HeaderWith(std::string cap) {
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 @@ TEST_F(ValidateData, int8_with_storage_push_constant_8_good) {
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 @@ TEST_F(ValidateData, int16_bad) {
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 @@ TEST_F(ValidateData, int64_bad) {
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 @@ TEST_F(ValidateData, float16_bad) {
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 @@ TEST_F(ValidateData, float64_bad) {
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 @@ TEST_F(ValidateData, ids_should_be_validated_before_data) {
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 @@ TEST_F(ValidateData, vulkan_RTA_not_at_end_of_struct) {
"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 e6461624..cbf6d7c1 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -42,8 +42,8 @@ struct TestResult {
};
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 @@ TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) {
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 @@ OpFunctionEnd
"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 @@ TEST_F(ValidateDecorations, NonWritableRuntimeArrayGood) {
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 @@ TEST_P(ValidateWebGPUCombineDecorationResult, Decorate) {
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));
- 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);
+ CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_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");
@@ -7159,6 +7183,469 @@ OpDecorate %float Location 0
"or member of a structure type"));
}
+TEST_F(ValidateDecorations, WorkgroupSingleBlockVariable) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability WorkgroupMemoryExplicitLayoutKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 8 1 1
+ OpMemberDecorate %first 0 Offset 0
+ OpDecorate %first Block
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %first = OpTypeStruct %int
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int_0 = OpConstant %int 0
+ %int_2 = OpConstant %int 2
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
+ OpStore %13 %int_2
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+}
+
+TEST_F(ValidateDecorations, WorkgroupBlockVariableRequiresV14) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability WorkgroupMemoryExplicitLayoutKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 8 1 1
+ OpMemberDecorate %first 0 Offset 0
+ OpDecorate %first Block
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %first = OpTypeStruct %int
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int_0 = OpConstant %int 0
+ %int_2 = OpConstant %int 2
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
+ OpStore %13 %int_2
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
+ EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("requires SPIR-V version 1.4 or later"));
+}
+
+TEST_F(ValidateDecorations, WorkgroupSingleNonBlockVariable) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %a
+ OpExecutionMode %main LocalSize 8 1 1
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %a = OpVariable %_ptr_Workgroup_int Workgroup
+ %int_2 = OpConstant %int 2
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpStore %a %int_2
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+}
+
+TEST_F(ValidateDecorations, WorkgroupMultiBlockVariable) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability WorkgroupMemoryExplicitLayoutKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_ %__0
+ OpExecutionMode %main LocalSize 8 1 1
+ OpMemberDecorate %first 0 Offset 0
+ OpDecorate %first Block
+ OpMemberDecorate %second 0 Offset 0
+ OpDecorate %second Block
+ OpDecorate %_ Aliased
+ OpDecorate %__0 Aliased
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %first = OpTypeStruct %int
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int_0 = OpConstant %int 0
+ %int_2 = OpConstant %int 2
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %second = OpTypeStruct %int
+%_ptr_Workgroup_second = OpTypePointer Workgroup %second
+ %__0 = OpVariable %_ptr_Workgroup_second Workgroup
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
+ OpStore %13 %int_2
+ %18 = OpAccessChain %_ptr_Workgroup_int %__0 %int_0
+ OpStore %18 %int_3
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+}
+
+TEST_F(ValidateDecorations, WorkgroupBlockVariableWith8BitType) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability Int8
+ OpCapability WorkgroupMemoryExplicitLayout8BitAccessKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 2 1 1
+ OpMemberDecorate %first 0 Offset 0
+ OpDecorate %first Block
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %char = OpTypeInt 8 1
+ %first = OpTypeStruct %char
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %char_2 = OpConstant %char 2
+%_ptr_Workgroup_char = OpTypePointer Workgroup %char
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %14 = OpAccessChain %_ptr_Workgroup_char %_ %int_0
+ OpStore %14 %char_2
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+}
+
+TEST_F(ValidateDecorations, WorkgroupMultiNonBlockVariable) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %a %b
+ OpExecutionMode %main LocalSize 8 1 1
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %a = OpVariable %_ptr_Workgroup_int Workgroup
+ %int_2 = OpConstant %int 2
+ %b = OpVariable %_ptr_Workgroup_int Workgroup
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpStore %a %int_2
+ OpStore %b %int_3
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+}
+
+TEST_F(ValidateDecorations, WorkgroupBlockVariableWith16BitType) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability Float16
+ OpCapability Int16
+ OpCapability WorkgroupMemoryExplicitLayout16BitAccessKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 2 1 1
+ OpMemberDecorate %first 0 Offset 0
+ OpMemberDecorate %first 1 Offset 2
+ OpDecorate %first Block
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %short = OpTypeInt 16 1
+ %half = OpTypeFloat 16
+ %first = OpTypeStruct %short %half
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %short_3 = OpConstant %short 3
+%_ptr_Workgroup_short = OpTypePointer Workgroup %short
+ %int_1 = OpConstant %int 1
+%half_0x1_898p_3 = OpConstant %half 0x1.898p+3
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %15 = OpAccessChain %_ptr_Workgroup_short %_ %int_0
+ OpStore %15 %short_3
+ %19 = OpAccessChain %_ptr_Workgroup_half %_ %int_1
+ OpStore %19 %half_0x1_898p_3
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+}
+
+TEST_F(ValidateDecorations, WorkgroupBlockVariableScalarLayout) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability WorkgroupMemoryExplicitLayoutKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %B
+ OpSource GLSL 450
+ OpMemberDecorate %S 0 Offset 0
+ OpMemberDecorate %S 1 Offset 4
+ OpMemberDecorate %S 2 Offset 16
+ OpMemberDecorate %S 3 Offset 28
+ OpDecorate %S Block
+ OpDecorate %B Aliased
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+ %S = OpTypeStruct %float %v3float %v3float %v3float
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+ %B = OpVariable %_ptr_Workgroup_S Workgroup
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ spvValidatorOptionsSetWorkgroupScalarBlockLayout(getValidatorOptions(), true);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4))
+ << getDiagnosticString();
+}
+
+TEST_F(ValidateDecorations, WorkgroupMixBlockAndNonBlockBad) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability WorkgroupMemoryExplicitLayoutKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_ %b
+ OpExecutionMode %main LocalSize 8 1 1
+ OpMemberDecorate %first 0 Offset 0
+ OpDecorate %first Block
+ OpDecorate %_ Aliased
+ OpDecorate %b Aliased
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %first = OpTypeStruct %int
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int_0 = OpConstant %int 0
+ %int_2 = OpConstant %int 2
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %b = OpVariable %_ptr_Workgroup_int Workgroup
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
+ OpStore %13 %int_2
+ OpStore %b %int_3
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("either all or none of the Workgroup Storage Class variables "
+ "in the entry point interface must point to struct types "
+ "decorated with Block"));
+}
+
+TEST_F(ValidateDecorations, WorkgroupMultiBlockVariableMissingAliased) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability WorkgroupMemoryExplicitLayoutKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_ %__0
+ OpExecutionMode %main LocalSize 8 1 1
+ OpMemberDecorate %first 0 Offset 0
+ OpDecorate %first Block
+ OpMemberDecorate %second 0 Offset 0
+ OpDecorate %second Block
+ OpDecorate %_ Aliased
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %first = OpTypeStruct %int
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int_0 = OpConstant %int 0
+ %int_2 = OpConstant %int 2
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %second = OpTypeStruct %int
+%_ptr_Workgroup_second = OpTypePointer Workgroup %second
+ %__0 = OpVariable %_ptr_Workgroup_second Workgroup
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
+ OpStore %13 %int_2
+ %18 = OpAccessChain %_ptr_Workgroup_int %__0 %int_0
+ OpStore %18 %int_3
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("more than one Workgroup Storage Class variable in the "
+ "entry point interface point to a type decorated with Block, "
+ "all of them must be decorated with Aliased"));
+}
+
+TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableNotAStruct) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability WorkgroupMemoryExplicitLayoutKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 8 1 1
+ OpDecorate %first Block
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %int_3 = OpConstant %int 3
+ %first = OpTypeArray %int %int_3
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int_0 = OpConstant %int 0
+ %int_2 = OpConstant %int 2
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
+ OpStore %13 %int_2
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Block decoration on a non-struct type"));
+}
+
+TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableMissingLayout) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability WorkgroupMemoryExplicitLayoutKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 8 1 1
+ OpDecorate %first Block
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %first = OpTypeStruct %int
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int_0 = OpConstant %int 0
+ %int_2 = OpConstant %int 2
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
+ OpStore %13 %int_2
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Block must be explicitly laid out with Offset decorations"));
+}
+
+TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableBadLayout) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpCapability WorkgroupMemoryExplicitLayoutKHR
+ OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 8 1 1
+ OpMemberDecorate %first 0 Offset 1
+ OpDecorate %first Block
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %first = OpTypeStruct %int
+%_ptr_Workgroup_first = OpTypePointer Workgroup %first
+ %_ = OpVariable %_ptr_Workgroup_first Workgroup
+ %int_0 = OpConstant %int 0
+ %int_2 = OpConstant %int 2
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
+ OpStore %13 %int_2
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID,
+ ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Block for variable in Workgroup storage class must follow "
+ "standard storage buffer layout rules: "
+ "member 0 at offset 1 is not aligned to 4"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_fixtures.h b/test/val/val_fixtures.h
index 5635c781..acbe0e57 100644
--- a/test/val/val_fixtures.h
+++ b/test/val/val_fixtures.h
@@ -183,4 +183,43 @@ spv_position_t ValidateBase<T>::getErrorPosition() {
} // 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 069e8f20..c65d1715 100644
--- a/test/val/val_id_test.cpp
+++ b/test/val/val_id_test.cpp
@@ -411,10 +411,10 @@ TEST_F(ValidateIdWithMessage, OpEntryPointFunctionBad) {
}
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, OpEntryPointParameterCountBad) {
}
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 @@ TEST_F(ValidateIdWithMessage, OpEntryPointReturnTypeBad) {
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, LengthPositiveHugeEnding1InVulkan) {
}
}
-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
@@ -4692,39 +4706,6 @@ TEST_F(ValidateIdWithMessage, OpVectorShuffleLiterals) {
"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 2e84a29f..6a0333cd 100644
--- a/test/val/val_image_test.cpp
+++ b/test/val/val_image_test.cpp
@@ -66,9 +66,9 @@ OpCapability ImageBuffer
%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
@@ -80,6 +80,7 @@ OpCapability ImageBuffer
%private_image_u32_buffer_0002_r32ui
%private_image_u32_spd_0002
%private_image_f32_buffer_0002_r32ui
+%input_flat_u32
)";
ss << capabilities_and_extensions;
@@ -99,12 +100,12 @@ OpDecorate %uniform_image_f32_1d_0002_rgba32f DescriptorSet 0
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
@@ -121,6 +122,8 @@ OpDecorate %uniform_image_f32_cube_0102_rgba32f DescriptorSet 2
OpDecorate %uniform_image_f32_cube_0102_rgba32f Binding 3
OpDecorate %uniform_sampler DescriptorSet 3
OpDecorate %uniform_sampler Binding 0
+OpDecorate %input_flat_u32 Flat
+OpDecorate %input_flat_u32 Location 0
)";
}
@@ -133,6 +136,7 @@ OpDecorate %uniform_sampler Binding 0
%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 +227,25 @@ OpDecorate %uniform_sampler Binding 0
%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 +255,14 @@ OpDecorate %uniform_sampler Binding 0
%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 +277,6 @@ OpDecorate %uniform_sampler Binding 0
%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
@@ -299,6 +297,9 @@ OpDecorate %uniform_sampler Binding 0
%ptr_Image_f32 = OpTypePointer Image %f32
%ptr_image_f32_buffer_0002_r32ui = OpTypePointer Private %type_image_f32_buffer_0002_r32ui
%private_image_f32_buffer_0002_r32ui = OpVariable %ptr_image_f32_buffer_0002_r32ui Private
+
+%ptr_input_flat_u32 = OpTypePointer Input %u32
+%input_flat_u32 = OpVariable %ptr_input_flat_u32 Input
)";
if (env == SPV_ENV_UNIVERSAL_1_0) {
@@ -311,7 +312,6 @@ OpDecorate %uniform_sampler Binding 0
%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 +400,15 @@ OpMemoryModel Physical32 OpenCL
%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 +431,35 @@ OpFunctionEnd)";
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 +480,11 @@ OpMemoryModel Logical GLSL450
%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 +506,7 @@ TEST_F(ValidateImage, TypeImageWrongSampledType) {
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 +516,153 @@ OpFunctionEnd
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, TypeImageU64SampledTypeVulkan) {
+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
-%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_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(
+ "OpCapability Int64ImageEXT\nOpExtension "
+ "\"SPV_EXT_shader_image_int64\"\n") +
+ 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_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
+)";
+
+ 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, 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
@@ -510,8 +672,10 @@ OpFunctionEnd
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, TypeImageWrongDepth) {
@@ -571,6 +735,83 @@ TEST_F(ValidateImage, TypeImageWrongSampledForSubpassData) {
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 +825,44 @@ TEST_F(ValidateImage, TypeImageWrongFormatForSubpassData) {
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 +873,43 @@ TEST_F(ValidateImage, TypeSampledImageNotImage) {
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 +961,32 @@ TEST_F(ValidateImage, SampledImageNotImage) {
}
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!
- CompileSuccessfully(GenerateShaderCode(body).c_str());
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Expected Image 'Sampled' parameter to be 0 or 1"));
-}
+%ptr_im_ty = OpTypePointer UniformConstant %im_ty
+%var_im = OpVariable %ptr_im_ty UniformConstant
-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
+%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
)";
- const spv_target_env env = SPV_ENV_VULKAN_1_0;
- CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env), env);
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
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 +1059,7 @@ TEST_F(ValidateImage, ImageTexelPointerImageNotResultTypePointer) {
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 +1117,7 @@ TEST_F(ValidateImage, ImageTexelPointerImageCoordTypeBad) {
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 +1218,20 @@ TEST_F(ValidateImage, SampleImplicitLodNotSampledImage) {
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 +1380,20 @@ TEST_F(ValidateImage, SampleExplicitLodNotSampledImage) {
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 +1526,6 @@ TEST_F(ValidateImage, LodWrongDim) {
"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 +1558,6 @@ TEST_F(ValidateImage, ImplicitLodWithGrad) {
"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 +1602,6 @@ TEST_F(ValidateImage, SampleImplicitLodBiasWrongDim) {
"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 +1664,6 @@ TEST_F(ValidateImage, SampleExplicitLodGradDyWrongSize) {
"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 +1682,10 @@ TEST_F(ValidateImage, SampleImplicitLodConstOffsetCubeDim) {
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 +1698,26 @@ TEST_F(ValidateImage, SampleImplicitLodConstOffsetWrongType) {
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 +1744,10 @@ TEST_F(ValidateImage, SampleImplicitLodOffsetCubeDim) {
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 +1759,10 @@ TEST_F(ValidateImage, SampleImplicitLodOffsetWrongType) {
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 +1770,33 @@ TEST_F(ValidateImage, SampleImplicitLodOffsetWrongSize) {
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, SampleImplicitLodVulkanOffsetWrongSize) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
+%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %s32vec2_01
+)";
+
+ CompileSuccessfully(
+ GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_VULKAN_1_0).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Offset-04663"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Image Operand Offset can only be used with "
+ "OpImage*Gather operations"));
}
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());
@@ -1499,6 +1806,24 @@ TEST_F(ValidateImage, SampleImplicitLodMoreThanOneOffset) {
"cannot be used together"));
}
+TEST_F(ValidateImage, SampleImplicitLodVulkanMoreThanOneOffset) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
+%sampler = OpLoad %type_sampler %uniform_sampler
+%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, "", "Fragment", "", SPV_ENV_VULKAN_1_0).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Offset-04662"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Image Operands Offset, ConstOffset, ConstOffsets "
+ "cannot be used together"));
+}
+
TEST_F(ValidateImage, SampleImplicitLodMinLodWrongType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101
@@ -1528,21 +1853,6 @@ TEST_F(ValidateImage, SampleImplicitLodMinLodWrongDim) {
"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 +1930,20 @@ TEST_F(ValidateImage, SampleProjExplicitLodNotSampledImage) {
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 +2065,20 @@ TEST_F(ValidateImage, SampleProjImplicitLodNotSampledImage) {
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 +2186,21 @@ TEST_F(ValidateImage, SampleDrefImplicitLodNotSampledImage) {
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 +2324,21 @@ TEST_F(ValidateImage, SampleDrefExplicitLodNotSampledImage) {
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 +2463,21 @@ TEST_F(ValidateImage, SampleProjDrefImplicitLodNotSampledImage) {
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 +2601,21 @@ TEST_F(ValidateImage, SampleProjDrefExplicitLodNotSampledImage) {
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 +2692,23 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 +2764,7 @@ TEST_F(ValidateImage, FetchSampledImageDirectly) {
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 +2848,21 @@ TEST_F(ValidateImage, FetchLodNotInt) {
"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 +2924,20 @@ TEST_F(ValidateImage, GatherNotSampledImage) {
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
@@ -2578,6 +3022,40 @@ TEST_F(ValidateImage, GatherComponentNot32Bit) {
HasSubstr("Expected Component to be 32-bit int scalar"));
}
+TEST_F(ValidateImage, GatherComponentSuccessVulkan) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_cube_0101 %img %sampler
+%res1 = OpImageGather %f32vec4 %simg %f32vec4_0000 %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, GatherComponentNotConstantVulkan) {
+ const std::string body = R"(
+%input_u32 = OpLoad %u32 %input_flat_u32
+%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_cube_0101 %img %sampler
+%res1 = OpImageGather %f32vec4 %simg %f32vec4_0000 %input_u32
+)";
+
+ spv_target_env env = SPV_ENV_VULKAN_1_0;
+ CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env).c_str(),
+ env);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpImageGather-04664"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Component Operand to be a const object for "
+ "Vulkan environment"));
+}
+
TEST_F(ValidateImage, GatherDimCube) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101
@@ -2709,6 +3187,20 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 +3232,7 @@ TEST_F(ValidateImage, DrefGatherWrongDrefType) {
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 +3275,7 @@ TEST_F(ValidateImage, ReadSuccess4) {
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 +3285,7 @@ TEST_F(ValidateImage, ReadNeedCapabilityStorageImageReadWithoutFormat) {
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 +3328,7 @@ TEST_F(ValidateImage, ReadNeedCapabilityImageCubeArray) {
// 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 +3339,41 @@ TEST_F(ValidateImage, DISABLED_ReadWrongResultType) {
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 +3406,7 @@ TEST_F(ValidateImage, ReadImageSampled) {
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 +3433,7 @@ TEST_F(ValidateImage, ReadVoidSampledType) {
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 +3446,7 @@ TEST_F(ValidateImage, ReadWrongCoordinateType) {
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 +3460,7 @@ TEST_F(ValidateImage, ReadCoordinateSizeTooSmall) {
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 +3493,24 @@ OpImageWrite %img %u32vec3_012 %f32vec4_0000
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 +3528,7 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000
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 +3538,7 @@ OpImageWrite %img %u32vec2_01 %u32vec4_0123
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 +3607,7 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000
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 +3620,7 @@ OpImageWrite %img %f32vec2_00 %u32vec4_0123
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 +3634,7 @@ OpImageWrite %img %u32_1 %u32vec4_0123
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 +3647,7 @@ OpImageWrite %img %u32vec2_01 %img
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 +3660,7 @@ OpImageWrite %img %u32vec2_01 %u32vec3_012
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 +3675,29 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000
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 +3713,16 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1
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,27 +3915,79 @@ TEST_F(ValidateImage, QuerySizeLodSampledImageDirectly) {
"for OpImageQuerySizeLod"));
}
-TEST_F(ValidateImage, QuerySizeLodWrongImageDim) {
+TEST_F(ValidateImage, QuerySizeLodMultisampledError) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
+%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("Image 'Dim' must be 1D, 2D, 3D or Cube"));
+ AnyVUID("VUID-StandaloneSpirv-OpImageQuerySizeLod-04659"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpImageQuerySizeLod must only consume an \"Image\" operand whose "
+ "type has its \"Sampled\" operand set to 1"));
}
-TEST_F(ValidateImage, QuerySizeLodMultisampled) {
+TEST_F(ValidateImage, QuerySizeLodWrongImageDim) {
const std::string body = R"(
-%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
+%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
%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"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Image 'Dim' must be 1D, 2D, 3D or Cube"));
}
TEST_F(ValidateImage, QuerySizeLodWrongLodType) {
@@ -3416,7 +4004,7 @@ TEST_F(ValidateImage, QuerySizeLodWrongLodType) {
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 +4014,7 @@ TEST_F(ValidateImage, QuerySizeSuccess) {
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 +4027,7 @@ TEST_F(ValidateImage, QuerySizeWrongResultType) {
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 +4041,7 @@ TEST_F(ValidateImage, QuerySizeNotImage) {
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 +4264,58 @@ TEST_F(ValidateImage, QueryLevelsWrongDim) {
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(),
+ AnyVUID("VUID-StandaloneSpirv-OpImageQuerySizeLod-04659"));
+ 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 +4325,7 @@ TEST_F(ValidateImage, QuerySamplesSuccess) {
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 +4403,102 @@ OpExecutionMode %main DerivativeGroupLinearNV
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(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04657"));
+ 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 +5186,7 @@ TEST_F(ValidateImage, SparseTexelsResidentResultTypeNotBool) {
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 +5244,7 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 +5265,7 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 +5305,7 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 +5326,7 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 +5348,7 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 +5366,7 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 +5388,7 @@ OpExtension "SPV_KHR_vulkan_memory_model"
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 +5441,7 @@ TEST_F(ValidateImage, Issue2463NoSegFault) {
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 +5452,7 @@ TEST_F(ValidateImage, SignExtendV13Bad) {
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 +5464,7 @@ TEST_F(ValidateImage, ZeroExtendV13Bad) {
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 +5493,7 @@ TEST_F(ValidateImage, SignExtendScalarSIntTexelV14Good) {
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 +5525,7 @@ TEST_F(ValidateImage, SignExtendVectorSIntTexelV14Good) {
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 +5554,7 @@ TEST_F(ValidateImage, ZeroExtendScalarSIntTexelV14Good) {
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 +5582,7 @@ TEST_F(ValidateImage, ZeroExtendVectorSIntTexelV14Good) {
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 +5647,7 @@ TEST_F(ValidateImage, ReadLodAMDNeedCapability) {
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 +5821,12 @@ static const std::string declarations_image64 = R"(
%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 +5912,134 @@ TEST_F(ValidateImage, ImageTexelPointer64SampleNotZeroForImageWithMSZero) {
"<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 43fa0469..d34c97f9 100644
--- a/test/val/val_layout_test.cpp
+++ b/test/val/val_layout_test.cpp
@@ -667,57 +667,6 @@ TEST_F(ValidateLayout, ModuleProcessedInvalidInBasicBlock) {
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 e5418905..9799b404 100644
--- a/test/val/val_memory_test.cpp
+++ b/test/val/val_memory_test.cpp
@@ -22,6 +22,16 @@
#include "test/val/val_code_generator.h"
#include "test/val/val_fixtures.h"
+// For pretty-printing tuples with spv_target_env.
+std::ostream& operator<<(std::ostream& stream, spv_target_env target)
+{
+ switch (target) {
+ case SPV_ENV_UNIVERSAL_1_3: return stream << "SPV_ENV_UNIVERSAL_1_3";
+ case SPV_ENV_UNIVERSAL_1_4: return stream << "SPV_ENV_UNIVERSAL_1_4";
+ default: return stream << (unsigned)target;
+ }
+}
+
namespace spvtools {
namespace val {
namespace {
@@ -51,14 +61,14 @@ OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-UniformConstant-04655"));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr("From Vulkan spec, section 14.5.2:\n"
- "Variables identified with the UniformConstant storage class "
+ HasSubstr("Variables identified with the UniformConstant storage class "
"are used only as handles to refer to opaque resources. Such "
"variables must be typed as OpTypeImage, OpTypeSampler, "
- "OpTypeSampledImage, OpTypeAccelerationStructureNV, "
- "OpTypeAccelerationStructureKHR, OpTypeRayQueryKHR, "
+ "OpTypeSampledImage, OpTypeAccelerationStructureKHR, "
"or an array of one of these types."));
}
@@ -105,14 +115,14 @@ OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-UniformConstant-04655"));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr("From Vulkan spec, section 14.5.2:\n"
- "Variables identified with the UniformConstant storage class "
+ HasSubstr("Variables identified with the UniformConstant storage class "
"are used only as handles to refer to opaque resources. Such "
"variables must be typed as OpTypeImage, OpTypeSampler, "
- "OpTypeSampledImage, OpTypeAccelerationStructureNV, "
- "OpTypeAccelerationStructureKHR, OpTypeRayQueryKHR, "
+ "OpTypeSampledImage, OpTypeAccelerationStructureKHR, "
"or an array of one of these types."));
}
@@ -362,192 +372,6 @@ OpFunctionEnd
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,12 +454,15 @@ OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpVariable-04651"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("OpVariable, <id> '5[%5]', has a disallowed initializer & "
"storage class combination.\nFrom Vulkan spec:\nVariable "
"declarations that include initializers must have one of the "
- "following storage classes: Output, Private, or Function\n %5 "
+ "following storage classes: Output, Private, Function or "
+ "Workgroup\n %5 "
"= OpVariable %_ptr_Input_float Input %float_1\n"));
}
@@ -2280,38 +2107,6 @@ OpFunctionEnd
"%_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 +2196,6 @@ OpFunctionEnd
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 +2225,6 @@ OpFunctionEnd
"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 +2253,6 @@ OpFunctionEnd
"%_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 +2279,6 @@ OpFunctionEnd
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 +2336,6 @@ OpFunctionEnd
"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 +2496,6 @@ OpFunctionEnd
"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
@@ -3843,9 +3454,10 @@ OpFunctionEnd
}
using ValidateSizedVariable =
- spvtest::ValidateBase<std::tuple<std::string, std::string, std::string>>;
+ spvtest::ValidateBase<std::tuple<std::string, std::string,
+ std::string, spv_target_env>>;
-CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit) {
+CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit, bool buffer_block) {
CodeGenerator generator;
generator.capabilities_ = "OpCapability Shader\nOpCapability Linkage\n";
generator.extensions_ =
@@ -3853,20 +3465,25 @@ CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit) {
"\"SPV_KHR_8bit_storage\"\n";
generator.memory_model_ = "OpMemoryModel Logical GLSL450\n";
if (is_8bit) {
- generator.before_types_ = R"(OpDecorate %char_buffer_block BufferBlock
-OpMemberDecorate %char_buffer_block 0 Offset 0
-)";
+ generator.before_types_ = "OpMemberDecorate %char_buffer_block 0 Offset 0\n";
+ if (buffer_block)
+ generator.before_types_ += "OpDecorate %char_buffer_block BufferBlock\n";
+
generator.types_ = R"(%void = OpTypeVoid
%char = OpTypeInt 8 0
%char4 = OpTypeVector %char 4
%char_buffer_block = OpTypeStruct %char
)";
} else {
- generator.before_types_ = R"(OpDecorate %half_buffer_block BufferBlock
-OpDecorate %short_buffer_block BufferBlock
-OpMemberDecorate %half_buffer_block 0 Offset 0
-OpMemberDecorate %short_buffer_block 0 Offset 0
-)";
+ generator.before_types_ =
+ "OpMemberDecorate %half_buffer_block 0 Offset 0\n"
+ "OpMemberDecorate %short_buffer_block 0 Offset 0\n";
+ if (buffer_block) {
+ generator.before_types_ +=
+ "OpDecorate %half_buffer_block BufferBlock\n"
+ "OpDecorate %short_buffer_block BufferBlock\n";
+ }
+
generator.types_ = R"(%void = OpTypeVoid
%short = OpTypeInt 16 0
%half = OpTypeFloat 16
@@ -3889,6 +3506,10 @@ TEST_P(ValidateSizedVariable, Capability) {
const std::string storage_class = std::get<0>(GetParam());
const std::string capability = std::get<1>(GetParam());
const std::string var_type = std::get<2>(GetParam());
+ const spv_target_env target = std::get<3>(GetParam());
+
+ ASSERT_TRUE(target == SPV_ENV_UNIVERSAL_1_3 ||
+ target == SPV_ENV_UNIVERSAL_1_4);
bool type_8bit = false;
if (var_type == "%char" || var_type == "%char4" ||
@@ -3896,7 +3517,16 @@ TEST_P(ValidateSizedVariable, Capability) {
type_8bit = true;
}
- auto generator = GetSizedVariableCodeGenerator(type_8bit);
+ const bool buffer_block = var_type.find("buffer_block") != std::string::npos;
+
+ auto generator = GetSizedVariableCodeGenerator(type_8bit, buffer_block);
+
+ if (capability == "WorkgroupMemoryExplicitLayout8BitAccessKHR" ||
+ capability == "WorkgroupMemoryExplicitLayout16BitAccessKHR") {
+ generator.extensions_ +=
+ "OpExtension \"SPV_KHR_workgroup_memory_explicit_layout\"\n";
+ }
+
generator.types_ += "%ptr_type = OpTypePointer " + storage_class + " " +
var_type + "\n%var = OpVariable %ptr_type " +
storage_class + "\n";
@@ -3926,7 +3556,6 @@ TEST_P(ValidateSizedVariable, Capability) {
}
storage_class_ok = true;
} else if (storage_class == "Uniform") {
- bool buffer_block = var_type.find("buffer_block") != std::string::npos;
if (type_8bit) {
capability_ok = capability == "UniformAndStorageBuffer8BitAccess" ||
(capability == "StorageBuffer8BitAccess" && buffer_block);
@@ -3936,11 +3565,30 @@ TEST_P(ValidateSizedVariable, Capability) {
(capability == "StorageBuffer16BitAccess" && buffer_block);
}
storage_class_ok = true;
+ } else if (storage_class == "Workgroup") {
+ if (type_8bit) {
+ capability_ok =
+ capability == "WorkgroupMemoryExplicitLayout8BitAccessKHR";
+ } else {
+ capability_ok =
+ capability == "WorkgroupMemoryExplicitLayout16BitAccessKHR";
+ }
+ storage_class_ok = true;
}
- CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
- spv_result_t result = ValidateInstructions(SPV_ENV_UNIVERSAL_1_3);
- if (capability_ok) {
+ CompileSuccessfully(generator.Build(), target);
+ spv_result_t result = ValidateInstructions(target);
+ if (target < SPV_ENV_UNIVERSAL_1_4 &&
+ (capability == "WorkgroupMemoryExplicitLayout8BitAccessKHR" ||
+ capability == "WorkgroupMemoryExplicitLayout16BitAccessKHR")) {
+ EXPECT_EQ(SPV_ERROR_WRONG_VERSION, result);
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("requires SPIR-V version 1.4 or later"));
+ } else if (buffer_block && target > SPV_ENV_UNIVERSAL_1_3) {
+ EXPECT_EQ(SPV_ERROR_WRONG_VERSION, result);
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("requires SPIR-V version 1.3 or earlier"));
+ } else if (capability_ok) {
EXPECT_EQ(SPV_SUCCESS, result);
} else {
EXPECT_EQ(SPV_ERROR_INVALID_ID, result);
@@ -3965,8 +3613,10 @@ INSTANTIATE_TEST_SUITE_P(
Combine(Values("UniformConstant", "Input", "Output", "Workgroup",
"CrossWorkgroup", "Private", "StorageBuffer", "Uniform"),
Values("StorageBuffer8BitAccess",
- "UniformAndStorageBuffer8BitAccess", "StoragePushConstant8"),
- Values("%char", "%char4", "%char_buffer_block")));
+ "UniformAndStorageBuffer8BitAccess", "StoragePushConstant8",
+ "WorkgroupMemoryExplicitLayout8BitAccessKHR"),
+ Values("%char", "%char4", "%char_buffer_block"),
+ Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4)));
INSTANTIATE_TEST_SUITE_P(
Storage16, ValidateSizedVariable,
@@ -3974,9 +3624,11 @@ INSTANTIATE_TEST_SUITE_P(
"CrossWorkgroup", "Private", "StorageBuffer", "Uniform"),
Values("StorageBuffer16BitAccess",
"UniformAndStorageBuffer16BitAccess",
- "StoragePushConstant16", "StorageInputOutput16"),
+ "StoragePushConstant16", "StorageInputOutput16",
+ "WorkgroupMemoryExplicitLayout16BitAccessKHR"),
Values("%short", "%half", "%short4", "%half4", "%mat4x4",
- "%short_buffer_block", "%half_buffer_block")));
+ "%short_buffer_block", "%half_buffer_block"),
+ Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4)));
using ValidateSizedLoadStore =
spvtest::ValidateBase<std::tuple<std::string, uint32_t, std::string>>;
@@ -4390,6 +4042,109 @@ OpFunctionEnd
"typed as OpTypeStruct, or an array of this type"));
}
+TEST_F(ValidateMemory, VulkanInvariantOutputSuccess) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main"
+OpDecorate %var Location 0
+OpDecorate %var Invariant
+%void = OpTypeVoid
+%f32 = OpTypeFloat 32
+%ptr_output = OpTypePointer Output %f32
+%var = OpVariable %ptr_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
+TEST_F(ValidateMemory, VulkanInvariantInputStructSuccess) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %var Location 0
+OpMemberDecorate %struct 1 Invariant
+%void = OpTypeVoid
+%f32 = OpTypeFloat 32
+%struct = OpTypeStruct %f32 %f32
+%ptr_input = OpTypePointer Input %struct
+%var = OpVariable %ptr_input Input
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
+TEST_F(ValidateMemory, VulkanInvariantWrongStorageClass) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main"
+OpDecorate %var Invariant
+%void = OpTypeVoid
+%f32 = OpTypeFloat 32
+%ptr_private = OpTypePointer Private %f32
+%var = OpVariable %ptr_private Private
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Invariant-04677"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Variable decorated with Invariant must only be identified with the "
+ "Input or Output storage class in Vulkan environment."));
+}
+
+TEST_F(ValidateMemory, VulkanInvariantMemberWrongStorageClass) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpMemberDecorate %struct 1 Invariant
+%void = OpTypeVoid
+%f32 = OpTypeFloat 32
+%struct = OpTypeStruct %f32 %f32
+%ptr_private = OpTypePointer Private %struct
+%var = OpVariable %ptr_private Private
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Invariant-04677"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Variable struct member decorated with Invariant must "
+ "only be identified with the Input or Output storage "
+ "class in Vulkan environment."));
+}
+
TEST_F(ValidateMemory, PhysicalStorageBufferPtrEqual) {
const std::string spirv = R"(
OpCapability Shader
@@ -4480,6 +4235,55 @@ OpFunctionEnd
"Cannot use a pointer in the PhysicalStorageBuffer storage class"));
}
+TEST_F(ValidateMemory, VulkanInitializerWithWorkgroupStorageClassBad) {
+ 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 Workgroup %float
+%init_val = OpConstant %float 1.0
+%1 = OpVariable %float_ptr Workgroup %init_val
+%void = OpTypeVoid
+%functy = OpTypeFunction %void
+%func = OpFunction %void None %functy
+%2 = 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(),
+ HasSubstr("Variable initializers in Workgroup storage class are "
+ "limited to OpConstantNull"));
+}
+
+TEST_F(ValidateMemory, VulkanInitializerWithWorkgroupStorageClassGood) {
+ 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 Workgroup %float
+%init_val = OpConstantNull %float
+%1 = OpVariable %float_ptr Workgroup %init_val
+%void = OpTypeVoid
+%functy = OpTypeFunction %void
+%func = OpFunction %void None %functy
+%2 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+ CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_misc_test.cpp b/test/val/val_misc_test.cpp
index e181f8d1..499b5b28 100644
--- a/test/val/val_misc_test.cpp
+++ b/test/val/val_misc_test.cpp
@@ -227,6 +227,30 @@ OpFunctionEnd)";
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
diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp
index 0a1476ee..99f5c9cf 100644
--- a/test/val/val_modes_test.cpp
+++ b/test/val/val_modes_test.cpp
@@ -62,6 +62,8 @@ OpEntryPoint GLCompute %main "main"
spv_target_env env = SPV_ENV_VULKAN_1_0;
CompileSuccessfully(spirv, env);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-LocalSize-04683"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("In the Vulkan environment, GLCompute execution model entry "
@@ -111,6 +113,8 @@ OpExecutionMode %main OriginLowerLeft
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 +132,8 @@ OpExecutionMode %main PixelCenterInteger
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 +537,16 @@ TEST_P(ValidateModeExecution, ExecutionMode) {
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 +712,6 @@ INSTANTIATE_TEST_SUITE_P(
"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 fbd11a9e..3840eec6 100644
--- a/test/val/val_non_uniform_test.cpp
+++ b/test/val/val_non_uniform_test.cpp
@@ -100,6 +100,7 @@ OpFunctionEnd)";
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 @@ TEST_P(GroupNonUniform, Vulkan1p1) {
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 @@ INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBitCountBadValue, GroupNonUniform,
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 10641587..9dab931a 100644
--- a/test/val/val_opencl_test.cpp
+++ b/test/val/val_opencl_test.cpp
@@ -23,6 +23,7 @@ namespace spvtools {
namespace val {
namespace {
+using testing::Eq;
using testing::HasSubstr;
using ValidateOpenCL = spvtest::ValidateBase<bool>;
@@ -91,7 +92,7 @@ TEST_F(ValidateOpenCL, NonZeroMSImageBad) {
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 @@ TEST_F(ValidateOpenCL, ImageReadWithConstOffsetBad) {
"\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 @@ TEST_F(ValidateOpenCL, ImageSampleExplicitLodWithConstOffsetBad) {
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 fe37a93c..e6f98bff 100644
--- a/test/val/val_storage_test.cpp
+++ b/test/val/val_storage_test.cpp
@@ -250,70 +250,6 @@ TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParamBad) {
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 45815790..7a38d3a1 100644
--- a/test/val/val_validation_state_test.cpp
+++ b/test/val/val_validation_state_test.cpp
@@ -245,12 +245,6 @@ TEST_F(ValidationStateTest, CheckVulkanNonRecursiveBodyGood) {
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 @@ TEST_F(ValidationStateTest, CheckVulkanDirectlyRecursiveBodyBad) {
" %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 @@ TEST_F(ValidationStateTest, CheckVulkanIndirectlyRecursiveBodyBad) {
" %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 2b9542a1..98565ddb 100644
--- a/test/val/val_version_test.cpp
+++ b/test/val/val_version_test.cpp
@@ -40,21 +40,6 @@ OpReturn
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 @@ std::string version(spv_target_env env) {
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 @@ INSTANTIATE_TEST_SUITE_P(Universal, ValidateVersion,
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 @@ INSTANTIATE_TEST_SUITE_P(Universal, ValidateVersion,
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 @@ INSTANTIATE_TEST_SUITE_P(Universal, ValidateVersion,
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 @@ INSTANTIATE_TEST_SUITE_P(Universal, ValidateVersion,
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 62fa6a7a..00000000
--- 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 82d430eb..1956f595 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 @@ int main(int argc, char** argv) {
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 66f92286..6999b39a 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -79,18 +79,6 @@ std::string GetSizePasses() {
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 @@ Options (in lexicographical order):)",
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 @@ Options (in lexicographical order):)",
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 @@ Options (in lexicographical order):)",
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,39 +485,15 @@ Options (in lexicographical order):)",
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.
Current workarounds: Avoid OpUnreachable in loops.)");
printf(R"(
+ --workgroup-scalar-block-layout
+ Forwards this option to the validator. See the validator help
+ for details.)");
+ printf(R"(
--wrap-opkill
Replaces all OpKill instructions in functions that can be called
from a continue construct with a function call to a function
@@ -714,9 +662,6 @@ OptStatus ParseFlags(int argc, const char** argv,
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 +726,6 @@ OptStatus ParseFlags(int argc, const char** argv,
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 +735,6 @@ OptStatus ParseFlags(int argc, const char** argv,
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")) {
@@ -849,6 +745,8 @@ OptStatus ParseFlags(int argc, const char** argv,
validator_options->SetRelaxBlockLayout(true);
} else if (0 == strcmp(cur_arg, "--scalar-block-layout")) {
validator_options->SetScalarBlockLayout(true);
+ } else if (0 == strcmp(cur_arg, "--workgroup-scalar-block-layout")) {
+ validator_options->SetWorkgroupScalarBlockLayout(true);
} else if (0 == strcmp(cur_arg, "--skip-block-layout")) {
validator_options->SetSkipBlockLayout(true);
} else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
diff --git a/tools/sva/yarn.lock b/tools/sva/yarn.lock
index 34a1808e..c46b9017 100644
--- a/tools/sva/yarn.lock
+++ b/tools/sva/yarn.lock
@@ -795,9 +795,9 @@ inherits@2:
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 19b8c776..5450023a 100644
--- a/tools/val/val.cpp
+++ b/tools/val/val.cpp
@@ -58,6 +58,7 @@ Options:
uniform, storage buffer, and push constant layouts. Scalar layout
rules are more permissive than relaxed block layout so in effect
this will override the --relax-block-layout option.
+ --workgroup-scalar-block-layout Enable scalar block layout when checking Workgroup block layouts.
--skip-block-layout Skip checking standard uniform/storage buffer layout.
Overrides any --relax-block-layout or --scalar-block-layout option.
--relax-struct-store Allow store from one struct type to a
@@ -108,7 +109,7 @@ int main(int argc, char** argv) {
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 +119,7 @@ int main(int argc, char** argv) {
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")) {
@@ -149,6 +149,8 @@ int main(int argc, char** argv) {
options.SetUniformBufferStandardLayout(true);
} else if (0 == strcmp(cur_arg, "--scalar-block-layout")) {
options.SetScalarBlockLayout(true);
+ } else if (0 == strcmp(cur_arg, "--workgroup-scalar-block-layout")) {
+ options.SetWorkgroupScalarBlockLayout(true);
} else if (0 == strcmp(cur_arg, "--skip-block-layout")) {
options.SetSkipBlockLayout(true);
} else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
diff --git a/utils/check_copyright.py b/utils/check_copyright.py
index 39d27cb7..b15bc206 100755
--- a/utils/check_copyright.py
+++ b/utils/check_copyright.py
@@ -39,7 +39,7 @@ AUTHORS = ['The Khronos Group Inc.',
'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 05756413..eecfbe93 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