Squashed 'third_party/SPIRV-Tools/' changes from 65e362b7a..c3f22f7cb
c3f22f7cb Update README (#3047)
1f2af55f2 Update README (#3048)
3da910d55 Avoid uninit warning in GCC (#3044)
cdd6829a3 utils/vscode: Add SPIR-V language server support
b96c9a057 utils/vscode: Add go language server packages.
ab3cdcaef Fix operand access of composite in upgrade memory model (#3021)
1a18d491f Validate array stride does not cause overlap (#3028)
12e54dae1 Update Offset to ConstOffset bitmask if operand is constant. (#3024)
3e4abc9ac Try to fix go linter: exported constant comment (#3026)
c5e6761ac spirv-fuzz: Eliminate spurious semicolons (#3025)
041f0a024 spirv-fuzz: simplify transformation for replacing an id with a synonym (#3020)
528c00c01 Re-enable OpReadClockKHR validation (#3013)
8a35bf030 Python 3: remove deprecated U qualifier on 'open' (#3019)
989f62fb9 Remove semicolon (#3022)
dc59b4b07 spirv-fuzz: vector shuffle transformation (#3015)
87efe0a8b Add basic documentation about spirv-fuzz (#3016)
d9fbf0234 Fix Go lint issues: comment exported symbols (#3014)
3724cfbea spirv-fuzz: better computation of data synonym facts (#3010)
fb6bac889 spirv-fuzz: make equivalence classes deterministic (#3011)
e0d5544c9 Add missing headers to GN. (#3009)
178c4ddea Correct "environment" typo (#3007)
f1e5cd73f spirv-fuzz: improvements to representation of data synonym facts (#3006)
cdee051e2 Add iOS as a supported platform (#3001)
5f6fb2f34 Reset pointers before iterating in fuzzer to avoid double free (#3003)
618ee5094 Fix some clang-tidy issues in graphics_robust_access_pass (#2998)
466908b50 Add description of wrap-opkill. (#3000)
f893d4d41 [opt] Do not compare optimized binary with an invalidated buffer (#2999)
7e2cba6a5 utils/vscode: Change assembly file ext to .spvasm (#2995)
42f885238 utils: Add a vscode extension for SPIR-V disassembly files (#2987)
5ea709937 Add two new simplifications. (#2984)
fac166162 spirv-fuzz: Transformation to extract from a composite object (#2991)
ec12de913 spirv-fuzz: rename class, and fix bug related to dominance (#2990)
0dbd4e358 spirv-fuzz: Rework management of data synonyms (#2989)
b34fa7319 spirv-fuzz: add class to represent equivalence relation (#2988)
4517c7b88 Update DEPS (#2986)
570582d8d spirv-fuzz: fuzzer pass to adjust memory access operands (#2968)
02910ffdf Instrument: Add missing def-use analysis. (#2985)
8357b878d spirv-fuzz: add missing functionality for matrix composites (#2974)
615918c91 Update CHANGES
e8c3f9b0b Ensure timestamp does not vary with timezone. (#2982)
6a9be627c Keep NOPs when comparing with original binary (#2931)
2a3cbe7c3 Check that derivatives operate on 32-bit values (#2983)
3cdd6444c Check text->str before destroying (#2981)
e3da3143b Disallow use of OpCompositeExtract/OpCompositeInsert with no indices (#2980)
2ca4fcfdc Add fuzzer for spirv-dis call path (#2977)
024417d83 Check binary->code existence before destroying (#2979)
9c0ae6bb8 Improved CMake install step. (#2963)
e99b91822 Support constant-folding UConvert and SConvert (#2960)
8e8977853 Add fuzzer for spirv-as call path (#2976)
00170cc5e spirv-fuzz: Refactor 'copy object' and 'construct composite' transformations (#2966)
964dc52df Update SPIR-V binary header test for SPIR-V 1.5 (#2967)
1b6fd37fa spirv-fuzz: Refactor 'split blocks' to identify instructions differently (#2961)
2276e5978 Validate that selections are structured (#2962)
3eda1b9ff spirv-fuzz: Rework id descriptors (#2959)
eba98c4eb spirv-fuzz: Add fuzzer pass to add NoContraction decorations (#2950)
91232f7f7 spirv-fuzz: Add fuzzer pass to change function controls (#2951)
feb154921 reduce: add large tests and fix (#2947)
253806adc spirv-fuzz: Add fuzzer pass to change loop controls (#2949)
1cea3b785 Fixed include paths and order according to Google style. (#2957)
82f84c4b8 Use a longer timeout for Bazel tests. (#2956)
c705032b2 Remove non-existent files from BUILD.gn (#2955)
c1d42038f Disable scope validation for OpReadClockKHR (#2953)
df15a4a3c CMake: Add support for building with emscripten (#2948)
c3ca04741 Update CHANGES
32f76efa6 Link cfg and dominator analysis in the context (#2946)
5910bb8e9 spirv-fuzz: add transformation and pass to construct composites (#2941)
2f6a87f61 reduce: improve remove unref instr pass (#2945)
81d227f36 spirv-fuzz: add disabled test to document known issue (#2942)
26dba32c4 spirv-fuzz: Add fuzzer pass to change selection controls (#2944)
3c7ff8d4f Enable OpTypeCooperativeMatrix specialization (#2927)
c18c9ff6b Handle OpKill better (#2933)
ad3d23f47 Generate null pointer by converting uint64 zero to pointer. (#2935)
8fa0f1a65 spirv-fuzz: option to convert shader into a form that renders red (#2934)
bc37fd585 Add SPV_KHR_shader_clock validation (#2879)
bd839ca6b reduce/fuzz: improve command line args (#2932)
9d7428b05 Validate physical storage buffer restrictions (#2930)
44b32176e fuzz: add shrinker-temp-file-prefix (#2928)
9eb1c9a4c Add continue construct analysis to struct cfg analysis (#2922)
85c67b5e0 Record trailing line dbg instructions (#2926)
4075b921f Add removing references to debug instructions when removing them (#2923)
ef4679a58 spirv-fuzz: allow interestingness script arguments (#2925)
bc84daff2 Add Kokoro bots for building with Bazel. (#2914)
10951a7c9 Refactor the InstructionPass (#2924)
84b197606 spirv-fuzz: do not allow a dead break to target an unreachable block (#2917)
27238bcca spirv-fuzz: preserve some analyses when permuting blocks (#2918)
510ca9d61 Only allow previously declared forward refs in structs (#2920)
2a11f365b Handle id overflow in wrap-opkill (#2916)
70097c776 spirv-fuzz: do not replace struct indices with synonyms (#2915)
c1e03834e spirv-fuzz: Fixes to preconditions for adding dead break/continue edges (#2904)
7bc114ba2 spirv-fuzz: do not replace a pointer argument to a function call with a synonym (#2901)
290f6a820 spirv-fuzz: do not replace boolean constant argument to OpPhi instruction (#2903)
527a68930 Remove validate_datarules.cpp (#2911)
55ea57a78 Handle extract with no indexes (#2910)
a03cd1f3e Add Bazel build configuration. (#2891)
6f26d9ad8 Handle id overflow in convert local access chains (#2908)
71e0ba606 Add OpCopyMemory test to SVA. (#2885)
3a762d54f Add missing GN dependency (#2899)
958f7e72a Employ the "swarm testing" idea in spirv-fuzz (#2890)
b83535da5 Fix operand index in spirv-fuzz (#2895)
f62ee4a4a Update DEPS: effcee, re2, googletest (#2881)
8d0ca43da Add method comment for opt::Function::WhileEachInst (#2867)
6b0721265 Use OpReturn* in wrap-opkill (#2886)
465312726 Fix to CMakeLists for spirv-fuzz tests (#2888)
7275a7165 Allow validation during spirv-fuzz replay (#2873)
4eee71e78 Disable long-running fuzzer tests by default (#2887)
61edde52a Revert "Use OpReturn* in wrap-opkill"
87f0fa432 Use OpReturn* in wrap-opkill
08fcf8a4a Fix header include syntax. (#2882)
248c80b04 Handle OpConstantNull in copy-prop-arrays. (#2870)
d06fe0848 Fix comment typo found by protobufs linter (#2884)
47e354b0c Move docs into docs/ folder (#2872)
605c2e3c0 Add WebGPU SPIR-V Assembler in JavaScript. (#2876)
acf20302c Android.mk: Add dependency from optimizer file to amd-shader-ballot-insts.inc (#2883)
c02a6191a Update SPIRV-Headers in DEPS (#2880)
e59b60de0 Fix detection of blocks bypassed by new edge (#2874)
ccd7bf167 Fix CMake issue related to spirv-fuzz (#2877)
0a07cd1c9 Add fuzzer pass to replace ids with synonyms (#2857)
bbb29870b Relaxed bitcast with pointers (#2878)
36c1c0e22 Fix Fuchsia build. (#2868)
99793fa67 Adding valilidation checks for OpEntryPoint duplicate names and execution mode (#2862)
932561935 Extra resource interface validation (#2864)
1e146e8a3 Split capability tests (#2866)
5a48c0da1 SPIRV-Tools support for SPIR-V 1.5 (#2865)
ad7f2c5c4 Add fuzzer pass to copy objects (#2853)
67b87f22c Handle another case where creating a constant can fail (#2854)
c7a39bc40 Don't inline function containing OpKill (#2842)
4f9256db3 Handle id overflow in wrap op kill. (#2851)
9f188e337 Assembler: Can't set an ID in instruction without result ID (#2852)
c0e980709 Handle creating a new constant failing gracefully (#2848)
e2e95172d Rework management of probabilities in spirv-fuzz (#2839)
7ee8f443e Fix add-dead-break and add-dead-continue passes to respect dominance (#2838)
35c9518c4 Handle id overflow in the ssa rewriter. (#2845)
7f7236f1e Handle id overflow in the constant manager. (#2844)
a464ac1a2 Add generic builtin validation of target (#2843)
6797173cf Don't register duplicate decoration in validator. (#2841)
76261e2a7 Replace CubeFaceCoord and CubeFaceIndexAMD (#2840)
b218ad199 Fold Min, Max, and Clamp instructions. (#2836)
a41520eaa Replace uses of SPV_AMD_shader_trinary_minmax extension (#2835)
19b256616 For WebGPU<->Vulkan optimization, set correct execution environment (#2834)
1dfb5fc12 Export SPIRV-Tools targets on installation (#2785)
635b583cf GN: Add Chromium GoogleTest deps. (#2832)
9b3cc3e05 Upadate CHANGES
c77045b4a Instrument: Be sure Float16 capability on when generating float16 null (#2831)
d11725b1d Add --relax-float-ops and --convert-relaxed-to-half (#2808)
1c9ca422d GN: Make SPIRV-Tools target use public_deps. (#2828)
b54d95029 Fold Fmix should accept vector operands. (#2826)
2c5ed16ba Fix end comments in header files (#2829)
git-subtree-dir: third_party/SPIRV-Tools
git-subtree-split: c3f22f7cba60e55d178b8184851d17697a996143
diff --git a/.gitignore b/.gitignore
index a965a99..196c63c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,11 @@
/testing
/tools/clang/
/utils/clang-format-diff.py
+bazel-bin
+bazel-genfiles
+bazel-out
+bazel-spirv-tools
+bazel-testlogs
# Vim
[._]*.s[a-w][a-z]
diff --git a/Android.mk b/Android.mk
index 9428116..cb7062c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -49,7 +49,6 @@
source/val/validate_composites.cpp \
source/val/validate_constants.cpp \
source/val/validate_conversion.cpp \
- source/val/validate_datarules.cpp \
source/val/validate_debug.cpp \
source/val/validate_decorations.cpp \
source/val/validate_derivatives.cpp \
@@ -89,6 +88,7 @@
source/opt/composite.cpp \
source/opt/const_folding_rules.cpp \
source/opt/constants.cpp \
+ source/opt/convert_to_half_pass.cpp \
source/opt/copy_prop_arrays.cpp \
source/opt/dead_branch_elim_pass.cpp \
source/opt/dead_insert_elim_pass.cpp \
@@ -130,7 +130,6 @@
source/opt/local_redundancy_elimination.cpp \
source/opt/local_single_block_elim_pass.cpp \
source/opt/local_single_store_elim_pass.cpp \
- source/opt/local_ssa_elim_pass.cpp \
source/opt/loop_dependence.cpp \
source/opt/loop_dependence_helpers.cpp \
source/opt/loop_descriptor.cpp \
@@ -153,6 +152,7 @@
source/opt/reduce_load_size.cpp \
source/opt/redundancy_elimination.cpp \
source/opt/register_pressure.cpp \
+ source/opt/relax_float_ops_pass.cpp \
source/opt/remove_duplicates_pass.cpp \
source/opt/replace_invalid_opc.cpp \
source/opt/scalar_analysis.cpp \
@@ -249,6 +249,8 @@
$(1)/spv-amd-shader-ballot.insts.inc \
$(1)/spv-amd-shader-explicit-vertex-parameter.insts.inc \
$(1)/spv-amd-shader-trinary-minmax.insts.inc
+$(LOCAL_PATH)/source/opt/amd_ext_to_khr.cpp: \
+ $(1)/spv-amd-shader-ballot.insts.inc
endef
$(eval $(call gen_spvtools_grammar_tables,$(SPVTOOLS_OUT_PATH)))
diff --git a/BUILD.bazel b/BUILD.bazel
new file mode 100644
index 0000000..dc1ca60
--- /dev/null
+++ b/BUILD.bazel
@@ -0,0 +1,513 @@
+load(
+ ":build_defs.bzl",
+ "COMMON_COPTS",
+ "DEBUGINFO_GRAMMAR_JSON_FILE",
+ "TEST_COPTS",
+ "base_test",
+ "generate_core_tables",
+ "generate_enum_string_mapping",
+ "generate_extinst_lang_headers",
+ "generate_glsl_tables",
+ "generate_opencl_tables",
+ "generate_vendor_tables",
+ "link_test",
+ "opt_test",
+ "reduce_test",
+ "util_test",
+ "val_test",
+)
+
+package(
+ default_visibility = ["//visibility:private"],
+)
+
+licenses(["notice"])
+
+exports_files([
+ "CHANGES",
+ "LICENSE",
+])
+
+py_binary(
+ name = "generate_grammar_tables",
+ srcs = ["utils/generate_grammar_tables.py"],
+)
+
+py_binary(
+ name = "generate_language_headers",
+ srcs = ["utils/generate_language_headers.py"],
+)
+
+generate_core_tables("1.0")
+
+generate_core_tables("1.1")
+
+generate_core_tables("1.2")
+
+generate_core_tables("unified1")
+
+generate_enum_string_mapping("unified1")
+
+generate_opencl_tables("unified1")
+
+generate_glsl_tables("unified1")
+
+generate_vendor_tables("spv-amd-shader-explicit-vertex-parameter")
+
+generate_vendor_tables("spv-amd-shader-trinary-minmax")
+
+generate_vendor_tables("spv-amd-gcn-shader")
+
+generate_vendor_tables("spv-amd-shader-ballot")
+
+generate_vendor_tables("debuginfo")
+
+generate_extinst_lang_headers("DebugInfo", DEBUGINFO_GRAMMAR_JSON_FILE)
+
+py_binary(
+ name = "generate_registry_tables",
+ srcs = ["utils/generate_registry_tables.py"],
+)
+
+genrule(
+ name = "gen_registry_tables",
+ srcs = ["@spirv_headers//:spirv_xml_registry"],
+ outs = ["generators.inc"],
+ cmd = "$(location generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)",
+ tools = [":generate_registry_tables"],
+)
+
+py_binary(
+ name = "update_build_version",
+ srcs = ["utils/update_build_version.py"],
+)
+
+genrule(
+ name = "gen_build_version",
+ srcs = ["CHANGES"],
+ outs = ["build-version.inc"],
+ cmd = "SOURCE_DATE_EPOCH=0 $(location update_build_version) $$(dirname $(location CHANGES)) $(location build-version.inc)",
+ tools = [":update_build_version"],
+)
+
+# Libraries
+
+cc_library(
+ name = "generated_headers",
+ hdrs = [
+ ":gen_build_version",
+ ":gen_core_tables_1.0",
+ ":gen_core_tables_1.1",
+ ":gen_core_tables_1.2",
+ ":gen_core_tables_unified1",
+ ":gen_enum_string_mapping",
+ ":gen_extinst_lang_headers_DebugInfo",
+ ":gen_glsl_tables_unified1",
+ ":gen_opencl_tables_unified1",
+ ":gen_registry_tables",
+ ":gen_vendor_tables_debuginfo",
+ ":gen_vendor_tables_spv_amd_gcn_shader",
+ ":gen_vendor_tables_spv_amd_shader_ballot",
+ ":gen_vendor_tables_spv_amd_shader_explicit_vertex_parameter",
+ ":gen_vendor_tables_spv_amd_shader_trinary_minmax",
+ ],
+ copts = COMMON_COPTS,
+)
+
+cc_library(
+ name = "spirv_tools_headers",
+ hdrs = glob([
+ "include/spirv-tools/libspirv.h",
+ "include/spirv-tools/libspirv.hpp",
+ "source/*.h",
+ "source/util/*.h",
+ "source/val/*.h",
+ ]),
+ copts = COMMON_COPTS,
+ includes = ["source"],
+ deps = [
+ "@spirv_headers//:spirv_c_headers",
+ ],
+)
+
+cc_library(
+ name = "spirv_tools",
+ srcs = glob([
+ "source/*.cpp",
+ "source/util/*.cpp",
+ "source/val/*.cpp",
+ ]),
+ hdrs = [
+ "include/spirv-tools/libspirv.h",
+ "include/spirv-tools/libspirv.hpp",
+ ],
+ copts = COMMON_COPTS + select({
+ "@bazel_tools//src/conditions:windows": [""],
+ "//conditions:default": ["-Wno-implicit-fallthrough"],
+ }),
+ includes = ["include"],
+ linkstatic = 1,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":generated_headers",
+ ":spirv_tools_headers",
+ "@spirv_headers//:spirv_c_headers",
+ "@spirv_headers//:spirv_common_headers",
+ ],
+)
+
+cc_library(
+ name = "spirv_tools_comp",
+ srcs = glob([
+ "source/comp/*.cpp",
+ "source/comp/*.h",
+ ]),
+ copts = COMMON_COPTS,
+ linkstatic = 1,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":generated_headers",
+ ":spirv_tools",
+ ":spirv_tools_headers",
+ "@spirv_headers//:spirv_common_headers",
+ ],
+)
+
+cc_library(
+ name = "spirv_tools_opt_headers",
+ hdrs = glob(["source/opt/*.h"]),
+ copts = COMMON_COPTS,
+)
+
+cc_library(
+ name = "spirv_tools_opt",
+ srcs = glob(["source/opt/*.cpp"]),
+ hdrs = [
+ "include/spirv-tools/instrument.hpp",
+ "include/spirv-tools/optimizer.hpp",
+ ],
+ copts = COMMON_COPTS,
+ includes = ["include"],
+ linkstatic = 1,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":spirv_tools",
+ ":spirv_tools_headers",
+ ":spirv_tools_opt_headers",
+ "@spirv_headers//:spirv_common_headers",
+ ],
+)
+
+cc_library(
+ name = "spirv_tools_reduce",
+ srcs = glob(["source/reduce/*.cpp"]),
+ hdrs = glob(["source/reduce/*.h"]),
+ copts = COMMON_COPTS,
+ linkstatic = 1,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":spirv_tools",
+ ":spirv_tools_opt",
+ ],
+)
+
+cc_library(
+ name = "spirv_tools_link",
+ srcs = glob(["source/link/*.cpp"]),
+ hdrs = ["include/spirv-tools/linker.hpp"],
+ copts = COMMON_COPTS,
+ linkstatic = 1,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":spirv_tools",
+ ":spirv_tools_opt",
+ ],
+)
+
+cc_library(
+ name = "tools_util",
+ srcs = glob(["tools/util/*.cpp"]),
+ hdrs = glob(["tools/util/*.h"]),
+ copts = COMMON_COPTS,
+ linkstatic = 1,
+ visibility = ["//visibility:public"],
+ deps = [":spirv_tools"],
+)
+
+# Tools
+
+cc_binary(
+ name = "spirv-as",
+ srcs = [
+ "tools/as/as.cpp",
+ "tools/io.h",
+ ],
+ copts = COMMON_COPTS,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":spirv_tools",
+ ],
+)
+
+cc_binary(
+ name = "spirv-dis",
+ srcs = [
+ "tools/dis/dis.cpp",
+ "tools/io.h",
+ ],
+ copts = COMMON_COPTS,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":spirv_tools",
+ ],
+)
+
+cc_binary(
+ name = "spirv-val",
+ srcs = [
+ "tools/io.h",
+ "tools/val/val.cpp",
+ ],
+ copts = COMMON_COPTS,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":spirv_tools",
+ ":tools_util",
+ ],
+)
+
+cc_binary(
+ name = "spirv-opt",
+ srcs = [
+ "tools/io.h",
+ "tools/opt/opt.cpp",
+ ],
+ copts = COMMON_COPTS,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":spirv_tools",
+ ":spirv_tools_opt",
+ ":tools_util",
+ ],
+)
+
+cc_binary(
+ name = "spirv-reduce",
+ srcs = [
+ "tools/io.h",
+ "tools/reduce/reduce.cpp",
+ ],
+ copts = COMMON_COPTS,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":spirv_tools",
+ ":spirv_tools_opt",
+ ":spirv_tools_reduce",
+ ":tools_util",
+ ],
+)
+
+cc_binary(
+ name = "spirv-link",
+ srcs = [
+ "tools/io.h",
+ "tools/link/linker.cpp",
+ ],
+ copts = COMMON_COPTS,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":spirv_tools",
+ ":spirv_tools_link",
+ ],
+)
+
+cc_binary(
+ name = "spirv-cfg",
+ srcs = [
+ "tools/cfg/bin_to_dot.cpp",
+ "tools/cfg/bin_to_dot.h",
+ "tools/cfg/cfg.cpp",
+ "tools/io.h",
+ ],
+ copts = COMMON_COPTS,
+ visibility = ["//visibility:public"],
+ deps = [":spirv_tools"],
+)
+
+# Unit tests
+
+cc_library(
+ name = "test_common",
+ testonly = 1,
+ srcs = [
+ "test/test_fixture.h",
+ "test/unit_spirv.cpp",
+ "test/unit_spirv.h",
+ ],
+ compatible_with = [],
+ copts = TEST_COPTS,
+ includes = ["test"],
+ linkstatic = 1,
+ deps = [
+ ":spirv_tools",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_library(
+ name = "link_test_common",
+ testonly = 1,
+ srcs = ["test/link/linker_fixture.h"],
+ compatible_with = [],
+ copts = TEST_COPTS,
+ linkstatic = 1,
+ deps = [
+ ":spirv_tools_link",
+ ":test_common",
+ ],
+)
+
+cc_library(
+ name = "opt_test_common",
+ testonly = 1,
+ srcs = ["test/opt/pass_utils.cpp"],
+ hdrs = [
+ "test/opt/assembly_builder.h",
+ "test/opt/function_utils.h",
+ "test/opt/module_utils.h",
+ "test/opt/pass_fixture.h",
+ "test/opt/pass_utils.h",
+ ],
+ compatible_with = [],
+ copts = TEST_COPTS,
+ linkstatic = 1,
+ deps = [
+ ":spirv_tools_opt",
+ ":test_common",
+ ],
+)
+
+cc_library(
+ name = "reduce_test_common",
+ testonly = 1,
+ srcs = [
+ "test/reduce/reduce_test_util.cpp",
+ "tools/io.h",
+ ],
+ hdrs = ["test/reduce/reduce_test_util.h"],
+ compatible_with = [],
+ copts = TEST_COPTS,
+ linkstatic = 1,
+ deps = [
+ ":spirv_tools_reduce",
+ ":test_common",
+ ],
+)
+
+cc_library(
+ name = "val_test_common",
+ testonly = 1,
+ srcs = [
+ "test/val/val_code_generator.cpp",
+ "test/val/val_fixtures.h",
+ ],
+ hdrs = [
+ "test/val/val_code_generator.h",
+ ],
+ compatible_with = [],
+ copts = TEST_COPTS,
+ linkstatic = 1,
+ deps = [":test_common"],
+)
+
+# PCH (precompiled header) tests only work when using CMake and MSVC on Windows,
+# so they will be skipped in the Bazel builds.
+
+[base_test(
+ name = f[5:-4], # strip test/, .cpp
+ srcs = [f],
+) for f in glob(
+ ["test/*.cpp"],
+ exclude = [
+ "test/cpp_interface_test.cpp", # has its own base_test below.
+ "test/log_test.cpp", # has its own base_test below.
+ "test/pch_test.cpp", # pch tests are skipped.
+ "test/timer_test.cpp", # has its own base_test below.
+ ],
+)]
+
+# This test uses unistd.h and does not run on Windows.
+base_test(
+ name = "timer_test",
+ srcs = select({
+ "@bazel_tools//src/conditions:windows": [],
+ "//conditions:default": ["test/timer_test.cpp"],
+ }),
+)
+
+base_test(
+ name = "cpp_interface_test",
+ srcs = ["test/cpp_interface_test.cpp"],
+ deps = [":spirv_tools_opt"],
+)
+
+base_test(
+ name = "log_test",
+ srcs = ["test/log_test.cpp"],
+ deps = [":spirv_tools_opt"],
+)
+
+[link_test(
+ name = f[10:-4], # strip test/link/, .cpp
+ srcs = [f],
+) for f in glob(
+ ["test/link/*.cpp"],
+)]
+
+[opt_test(
+ name = f[9:-4], # strip test/opt/, .cpp
+ srcs = [f],
+) for f in glob(
+ ["test/opt/*.cpp"],
+ # pch tests are skipped.
+ exclude = ["test/opt/pch_test_opt.cpp"],
+)]
+
+[opt_test(
+ name = "dom_tree_" + f[24:-4], # strip test/opt/dominator_tree/, .cpp
+ srcs = [f],
+) for f in glob(
+ ["test/opt/dominator_tree/*.cpp"],
+ # pch tests are skipped.
+ exclude = ["test/opt/dominator_tree/pch_test_opt_dom.cpp"],
+)]
+
+[opt_test(
+ name = "loop_" + f[28:-4], # strip test/opt/loop_optimizations/, .cpp
+ srcs = [f],
+) for f in glob(
+ ["test/opt/loop_optimizations/*.cpp"],
+ # pch tests are skipped.
+ exclude = ["test/opt/loop_optimizations/pch_test_opt_loop.cpp"],
+)]
+
+[reduce_test(
+ name = f[12:-4], # strip test/reduce/, .cpp
+ srcs = [f],
+) for f in glob(["test/reduce/*.cpp"])]
+
+[util_test(
+ name = f[10:-4], # strip test/util/, .cpp
+ srcs = [f],
+) for f in glob(["test/util/*.cpp"])]
+
+[val_test(
+ name = f[9:-4], # strip test/val/, .cpp
+ srcs = [f],
+) for f in glob(
+ ["test/val/*.cpp"],
+ exclude = [
+ "test/val/pch_test_val.cpp", # pch tests are skipped.
+ ],
+)]
+
diff --git a/BUILD.gn b/BUILD.gn
index d62aaab..5c8eb9a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -288,10 +288,21 @@
configs = [ ":spvtools_public_config" ]
if (is_clang) {
- cflags = [ "-Wno-implicit-fallthrough" ]
+ cflags = [
+ "-Wno-implicit-fallthrough",
+ "-Wno-newline-eof",
+ ]
}
}
+source_set("spv_headers") {
+ sources = [
+ "$spirv_headers/include/spirv/1.2/GLSL.std.450.h",
+ "$spirv_headers/include/spirv/unified1/OpenCL.std.h",
+ "$spirv_headers/include/spirv/unified1/spirv.h",
+ ]
+}
+
source_set("spvtools_headers") {
sources = [
"include/spirv-tools/instrument.hpp",
@@ -321,16 +332,22 @@
"source/assembly_grammar.h",
"source/binary.cpp",
"source/binary.h",
+ "source/cfa.h",
"source/diagnostic.cpp",
"source/diagnostic.h",
"source/disassemble.cpp",
+ "source/disassemble.h",
"source/enum_set.h",
"source/enum_string_mapping.cpp",
+ "source/enum_string_mapping.h",
"source/ext_inst.cpp",
"source/ext_inst.h",
"source/extensions.cpp",
"source/extensions.h",
"source/instruction.h",
+ "source/latest_version_glsl_std_450_header.h",
+ "source/latest_version_opencl_std_header.h",
+ "source/latest_version_spirv_header.h",
"source/libspirv.cpp",
"source/macro.h",
"source/name_mapper.cpp",
@@ -376,6 +393,7 @@
]
public_deps = [
+ ":spv_headers",
":spvtools_core_enums_unified1",
":spvtools_headers",
]
@@ -390,8 +408,12 @@
static_library("spvtools_val") {
sources = [
"source/val/basic_block.cpp",
+ "source/val/basic_block.h",
"source/val/construct.cpp",
+ "source/val/construct.h",
+ "source/val/decoration.h",
"source/val/function.cpp",
+ "source/val/function.h",
"source/val/instruction.cpp",
"source/val/validate.cpp",
"source/val/validate.h",
@@ -407,7 +429,6 @@
"source/val/validate_composites.cpp",
"source/val/validate_constants.cpp",
"source/val/validate_conversion.cpp",
- "source/val/validate_datarules.cpp",
"source/val/validate_debug.cpp",
"source/val/validate_decorations.cpp",
"source/val/validate_derivatives.cpp",
@@ -423,14 +444,17 @@
"source/val/validate_logicals.cpp",
"source/val/validate_memory.cpp",
"source/val/validate_memory_semantics.cpp",
+ "source/val/validate_memory_semantics.h",
"source/val/validate_misc.cpp",
"source/val/validate_mode_setting.cpp",
"source/val/validate_non_uniform.cpp",
"source/val/validate_primitives.cpp",
"source/val/validate_scopes.cpp",
+ "source/val/validate_scopes.h",
"source/val/validate_small_type_uses.cpp",
"source/val/validate_type.cpp",
"source/val/validation_state.cpp",
+ "source/val/validation_state.h",
]
deps = [
@@ -479,6 +503,8 @@
"source/opt/const_folding_rules.h",
"source/opt/constants.cpp",
"source/opt/constants.h",
+ "source/opt/convert_to_half_pass.cpp",
+ "source/opt/convert_to_half_pass.h",
"source/opt/copy_prop_arrays.cpp",
"source/opt/copy_prop_arrays.h",
"source/opt/dead_branch_elim_pass.cpp",
@@ -563,8 +589,6 @@
"source/opt/local_single_block_elim_pass.h",
"source/opt/local_single_store_elim_pass.cpp",
"source/opt/local_single_store_elim_pass.h",
- "source/opt/local_ssa_elim_pass.cpp",
- "source/opt/local_ssa_elim_pass.h",
"source/opt/log.h",
"source/opt/loop_dependence.cpp",
"source/opt/loop_dependence.h",
@@ -611,6 +635,8 @@
"source/opt/reflect.h",
"source/opt/register_pressure.cpp",
"source/opt/register_pressure.h",
+ "source/opt/relax_float_ops_pass.cpp",
+ "source/opt/relax_float_ops_pass.h",
"source/opt/remove_duplicates_pass.cpp",
"source/opt/remove_duplicates_pass.h",
"source/opt/replace_invalid_opc.cpp",
@@ -716,6 +742,7 @@
"source/reduce/reducer.h",
"source/reduce/reduction_opportunity.cpp",
"source/reduce/reduction_opportunity.h",
+ "source/reduce/reduction_opportunity_finder.h",
"source/reduce/reduction_pass.cpp",
"source/reduce/reduction_pass.h",
"source/reduce/reduction_util.cpp",
@@ -730,10 +757,6 @@
"source/reduce/remove_function_reduction_opportunity_finder.h",
"source/reduce/remove_instruction_reduction_opportunity.cpp",
"source/reduce/remove_instruction_reduction_opportunity.h",
- "source/reduce/remove_opname_instruction_reduction_opportunity_finder.cpp",
- "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h",
- "source/reduce/remove_relaxed_precision_decoration_opportunity_finder.cpp",
- "source/reduce/remove_relaxed_precision_decoration_opportunity_finder.h",
"source/reduce/remove_selection_reduction_opportunity.cpp",
"source/reduce/remove_selection_reduction_opportunity.h",
"source/reduce/remove_selection_reduction_opportunity_finder.cpp",
@@ -766,7 +789,7 @@
}
group("SPIRV-Tools") {
- deps = [
+ public_deps = [
":spvtools",
":spvtools_link",
":spvtools_opt",
@@ -846,6 +869,8 @@
"//testing/gmock",
"//testing/gtest",
"//testing/gtest:gtest_main",
+ "//third_party/googletest:gmock",
+ "//third_party/googletest:gtest",
]
if (is_clang) {
@@ -870,6 +895,9 @@
"tools/util/cli_consumer.cpp",
"tools/util/cli_consumer.h",
]
+ deps = [
+ ":spvtools_headers",
+ ]
configs += [ ":spvtools_internal_config" ]
}
diff --git a/CHANGES b/CHANGES
index 57afc63..5263f12 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,7 +1,69 @@
Revision history for SPIRV-Tools
-v2019.5-dev 2019-08-08
- - Start v2019.5-dev
+v2019.5-dev 2019-10-21
+ - General:
+ - Export SPIRV-Tools targets on installation
+ - SPIRV-Tools support for SPIR-V 1.5 (#2865)
+ - Add WebGPU SPIR-V Assembler in JavaScript. (#2876)
+ - Add Bazel build configuration. (#2891)
+ - Add support for building with emscripten (#2948)
+ - Update SPIR-V binary header test for SPIR-V 1.5 (#2967)
+ - Add fuzzer for spirv-as call path (#2976)
+ - Improved CMake install step. (#2963)
+ - Add fuzzer for spirv-dis call path (#2977)
+ - Ensure timestamp does not vary with timezone. (#2982)
+ - Optimizer
+ - Add descriptor array scalar replacement (#2742)
+ - Add pass to wrap OpKill in a function call (#2790)
+ - Fold FMix during constant folding. (#2818)
+ - Add pass to replace AMD shader ballot extension (#2811)
+ - Add pass to make Float32 operation relax precision (#2808)
+ - Add pass to make relax precision operation Float16 (#2808)
+ - Add pass to replace uses of 3 AMD extensions (#2814)
+ - Fold Min, Max, and Clamp instructions. (#2836)
+ - Better handling of OpKill in continues (#2842,#2922,#2933)
+ - Enable OpTypeCooperativeMatrix specialization (#2927)
+ - Support constant-folding UConvert and SConvert (#2960)
+ Fixes:
+ - Instrument: Fix version 2 output record write for tess eval shaders. (#2782)
+ - Instrument: Add support for Buffer Device Address extension (#2792)
+ - Fix check for changed binary in API call. (#2798)
+ - For WebGPU<->Vulkan optimization, set correct execution environment (#2834)
+ - Handle OpConstantNull in copy-prop-arrays. (#2870)
+ - Use OpReturn* in wrap-opkill (#2886)
+ - Validator
+ - Add generic builtin validation of target (#2843)
+ - Extra resource interface validation (#2864)
+ - Adding valilidation checks for OpEntryPoint duplicate names and execution mode (#2862)
+ - Relaxed bitcast with pointers (#2878)
+ - Validate physical storage buffer restrictions (#2930)
+ - Add SPV_KHR_shader_clock validation (#2879)
+ - Validate that selections are structured (#2962)
+ - Disallow use of OpCompositeExtract/OpCompositeInsert with no indices (#2980)
+ - Check that derivatives operate on 32-bit values (#2983)
+ Fixes:
+ - Fix validation of constant matrices (#2794)
+ - Update "remquor" validation
+ - Only allow previously declared forward refs in structs (#2920)
+ - Reduce
+ - Remove relaxed precision decorations (#2797)
+ - Reduce/fuzz: improve command line args (#2932)
+ - Improve remove unref instr pass (#2945)
+ Fixes:
+ - Fuzz
+ - Fix add-dead-break and add-dead-continue passes to respect dominance (#2838)
+ - Add fuzzer pass to copy objects (#2853)
+ - Add fuzzer pass to replace ids with synonyms (#2857)
+ - Allow validation during spirv-fuzz replay (#2873)
+ - Employ the "swarm testing" idea in spirv-fuzz (#2890)
+ - reduce/fuzz: improve command line args (#2932)
+ - option to convert shader into a form that renders red (#2934)
+ - Add fuzzer pass to change selection controls (#2944)
+ - add transformation and pass to construct composites (#2941)
+ - Add fuzzer pass to change loop controls (#2949)
+ - Add fuzzer pass to change function controls (#2951)
+ - Add fuzzer pass to add NoContraction decorations (#2950)
+
v2019.4 2019-08-08
- General:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b95b714..19108f3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -39,12 +39,16 @@
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
add_definitions(-DSPIRV_LINUX)
set(SPIRV_TIMER_ENABLED ${SPIRV_ALLOW_TIMERS})
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Emscripten")
+ add_definitions(-DSPIRV_EMSCRIPTEN)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
add_definitions(-DSPIRV_WINDOWS)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
add_definitions(-DSPIRV_WINDOWS)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
add_definitions(-DSPIRV_MAC)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "iOS")
+ add_definitions(-DSPIRV_IOS)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
add_definitions(-DSPIRV_ANDROID)
set(SPIRV_TIMER_ENABLED ${SPIRV_ALLOW_TIMERS})
@@ -204,6 +208,27 @@
endmacro()
endif()
+if(ENABLE_SPIRV_TOOLS_INSTALL)
+ if(WIN32)
+ macro(spvtools_config_package_dir TARGET PATH)
+ set(${PATH} ${TARGET}/cmake)
+ endmacro()
+ else()
+ macro(spvtools_config_package_dir TARGET PATH)
+ set(${PATH} lib/cmake/${TARGET})
+ endmacro()
+ endif()
+
+ macro(spvtools_generate_config_file TARGET)
+ file(WRITE ${CMAKE_BINARY_DIR}/${TARGET}Config.cmake
+ "include(CMakeFindDependencyMacro)\n"
+ "find_dependency(${SPIRV_TOOLS})\n"
+ "include(\${CMAKE_CURRENT_LIST_DIR}/${TARGET}Targets.cmake)\n"
+ "set(${TARGET}_LIBRARIES ${TARGET})\n"
+ "get_target_property(${TARGET}_INCLUDE_DIRS ${TARGET} INTERFACE_INCLUDE_DIRECTORIES)\n")
+ endmacro()
+endif()
+
# Defaults to OFF if the user didn't set it.
option(SPIRV_SKIP_EXECUTABLES
"Skip building the executable and tests along with the library"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 93a5610..b46ae31 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,7 +4,7 @@
We organize known future work in GitHub projects. See [Tracking SPIRV-Tools work
with GitHub
-projects](https://github.com/KhronosGroup/SPIRV-Tools/blob/master/projects.md)
+projects](https://github.com/KhronosGroup/SPIRV-Tools/blob/master/docs/projects.md)
for more.
To report a new bug or request a new feature, please file a GitHub issue. Please
diff --git a/DEPS b/DEPS
index 70685ad..311b7ed 100644
--- a/DEPS
+++ b/DEPS
@@ -3,10 +3,10 @@
vars = {
'github': 'https://github.com',
- 'effcee_revision': 'b83b58d177b797edd1f94c5f10837f2cc2863f0a',
- 'googletest_revision': '2f42d769ad1b08742f7ccb5ad4dd357fc5ff248c',
- 're2_revision': 'e356bd3f80e0c15c1050323bb5a2d0f8ea4845f4',
- 'spirv_headers_revision': '123dc278f204f8e833e1a88d31c46d0edf81d4b2',
+ 'effcee_revision': 'cd25ec17e9382f99a895b9ef53ff3c277464d07d',
+ 'googletest_revision': 'f2fb48c3b3d79a75a88a99fba6576b25d42ec528',
+ 're2_revision': '5bd613749fd530b576b890283bfb6bc6ea6246cb',
+ 'spirv_headers_revision': 'af64a9e826bf5bb5fcd2434dd71be1e41e922563',
}
deps = {
diff --git a/README.md b/README.md
index 8a5c85e..5714976 100644
--- a/README.md
+++ b/README.md
@@ -26,14 +26,14 @@
<img alt="MacOS" src="kokoro/img/macos.png" width="20px" height="20px" hspace="2px"/>[![MacOS Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_macos_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html)
<img alt="Windows" src="kokoro/img/windows.png" width="20px" height="20px" hspace="2px"/>[![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_release.html)
-[More downloads](downloads.md)
+[More downloads](docs/downloads.md)
## Versioning SPIRV-Tools
See [`CHANGES`](CHANGES) for a high level summary of recent changes, by version.
SPIRV-Tools project version numbers are of the form `v`*year*`.`*index* and with
-an optional `-dev` suffix to indicate work in progress. For exampe, the
+an optional `-dev` suffix to indicate work in progress. For example, the
following versions are ordered from oldest to newest:
* `v2016.0`
@@ -49,9 +49,11 @@
### Assembler, binary parser, and disassembler
-* Support for SPIR-V 1.0, 1.1, 1.2, and 1.3
+* Support for SPIR-V 1.0, through 1.5
* Based on SPIR-V syntax described by JSON grammar files in the
[SPIRV-Headers](https://github.com/KhronosGroup/SPIRV-Headers) repository.
+ * Usually, support for a new version of SPIR-V is ready within days after
+ publication.
* Support for extended instruction sets:
* GLSL std450 version 1.0 Rev 3
* OpenCL version 1.0 Rev 2
@@ -59,7 +61,7 @@
IDs or types is performed, except to check literal arguments to
`OpConstant`, `OpSpecConstant`, and `OpSwitch`.
-See [`syntax.md`](syntax.md) for the assembly language syntax.
+See [`docs/syntax.md`](docs/syntax.md) for the assembly language syntax.
### Validator
@@ -88,14 +90,22 @@
### Optimizer
-*Note:* The optimizer is still under development.
+The optimizer is a collection of code transforms, or "passes".
+Transforms are written for a diverse set of reasons:
-Currently supported optimizations:
-* General
+* To restructure, simplify, or normalize the code for further processing.
+* To eliminate undesirable code.
+* To improve code quality in some metric such as size or performance.
+ **Note**: These transforms are not guaranteed to actually improve any
+ given metric. Users should always measure results for their own situation.
+
+As of this writing, there are 67 transforms including examples such as:
+* Simplification
* Strip debug info
+ * Strip reflection info
* Specialization Constants
* Set spec constant default value
- * Freeze spec constant
+ * Freeze spec constant to default value
* Fold `OpSpecConstantOp` and `OpSpecConstantComposite`
* Unify constants
* Eliminate dead constant
@@ -112,6 +122,29 @@
* Eliminate common uniform loads
* Remove duplicates: Capabilities, extended instruction imports, types, and
decorations.
+* Normalization
+ * Compact IDs
+ * CFG cleanup
+ * Flatten decorations
+ * Merge returns
+ * Convert AMD-specific instructions to KHR instructions
+* Code improvement
+ * Conditional constant propagation
+ * If-conversion
+ * Loop fission
+ * Loop fusion
+ * Loop-invariant code motion
+ * Loop unroll
+* Other
+ * Generate WebGPU initializers
+ * Graphics robust access
+ * Upgrade memory model to VulkanKHR
+
+Additionally, certain sets of transformations have been packaged into
+higher-level recipes. These include:
+
+* Optimization for size (`spirv-opt -Os`)
+* Optimization for performance (`spirv-opt -O`)
For the latest list with detailed documentation, please refer to
[`include/spirv-tools/optimizer.hpp`](include/spirv-tools/optimizer.hpp).
@@ -149,6 +182,24 @@
"Reducer:" as the start of its title.
+### Fuzzer
+
+*Note:* The fuzzer is still under development.
+
+The fuzzer applies semantics-preserving transformations to a SPIR-V binary
+module, to produce an equivalent module. The original and transformed modules
+should produce essentially identical results when executed on identical inputs:
+their results should differ only due to floating-point round-off, if at all.
+Significant differences in results can pinpoint bugs in tools that process
+SPIR-V binaries, such as miscompilations. This *metamorphic testing* approach
+is similar to the method used by the [GraphicsFuzz
+project](https://github.com/google/graphicsfuzz) for fuzzing of GLSL shaders.
+
+To suggest an additional capability for the fuzzer, [file an
+issue](https://github.com/KhronosGroup/SPIRV-Tools/issues]) with
+"Fuzzer:" as the start of its title.
+
+
### Extras
* [Utility filters](#utility-filters)
@@ -171,7 +222,7 @@
(To provide feedback on the SPIR-V _specification_, file an issue on the
[SPIRV-Headers][spirv-headers] GitHub repository.)
-See [`projects.md`](projects.md) to see how we use the
+See [`docs/projects.md`](docs/projects.md) to see how we use the
[GitHub Project
feature](https://help.github.com/articles/tracking-the-progress-of-your-work-with-projects/)
to organize planned and in-progress work.
@@ -255,9 +306,9 @@
testing and they always reflect the current top of the tree of the master
branch.
-The project uses [CMake][cmake] to generate platform-specific build
-configurations. Assume that `<spirv-dir>` is the root directory of the checked
-out code:
+In order to build the code, you first need to sync the external repositories
+that it depends on. Assume that `<spirv-dir>` is the root directory of the
+checked out code:
```sh
cd <spirv-dir>
@@ -266,28 +317,46 @@
git clone https://github.com/google/re2.git external/re2
git clone https://github.com/google/googletest.git external/googletest # optional
-mkdir build && cd build
-cmake [-G <platform-generator>] <spirv-dir>
```
*Note*:
The script `utils/git-sync-deps` can be used to checkout and/or update the
contents of the repos under `external/` instead of manually maintaining them.
+### Build using CMake
+You can build The project using [CMake][cmake] to generate platform-specific
+build configurations.
+
+```sh
+cd <spirv-dir>
+mkdir build && cd build
+cmake [-G <platform-generator>] <spirv-dir>
+```
+
Once the build files have been generated, build using your preferred
development environment.
+### Build using Bazel
+You can also use [Bazel](https://bazel.build/) to build the project.
+```sh
+cd <spirv-dir>
+bazel build :all
+```
+
### Tools you'll need
For building and testing SPIRV-Tools, the following tools should be
installed regardless of your OS:
-- [CMake](http://www.cmake.org/): for generating compilation targets. Version
- 2.8.12 or later.
+- [CMake](http://www.cmake.org/): if using CMake for generating compilation
+targets, you need to install CMake Version 2.8.12 or later.
- [Python 3](http://www.python.org/): for utility scripts and running the test
suite.
+- [Bazel](https://bazel.build/) (optional): if building the source with Bazel,
+you need to install Bazel Version 0.29.1 on your machine. Other versions may
+also work, but are not verified.
-SPIRV-Tools is regularly tested with the the following compilers:
+SPIRV-Tools is regularly tested with the following compilers:
On Linux
- GCC version 4.8.5
@@ -306,6 +375,7 @@
The following CMake options are supported:
+* `SPIRV_BUILD_FUZZER={ON|OFF}`, default `OFF` - Build the spirv-fuzz tool.
* `SPIRV_COLOR_TERMINAL={ON|OFF}`, default `ON` - Enables color console output.
* `SPIRV_SKIP_TESTS={ON|OFF}`, default `OFF`- Build only the library and
the command line tools. This will prevent the tests from being built.
@@ -482,6 +552,19 @@
Run `spirv-reduce --help` to see how to specify interestingness.
+### Fuzzer tool
+
+The fuzzer transforms a SPIR-V binary module into a semantically-equivalent
+SPIR-V binary module by applying transformations in a randomized fashion.
+
+This is a work in progress, with initially only a few semantics-preserving
+transformations.
+
+* `spirv-fuzz` - the standalone fuzzer
+ * `<spirv-dir>/tools/fuzz`
+
+Run `spirv-fuzz --help` for a detailed list of options.
+
### Control flow dumper tool
The control flow dumper prints the control flow graph for a SPIR-V module as a
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..5abfc98
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,19 @@
+local_repository(
+ name = "spirv_headers",
+ path = "external/spirv-headers",
+)
+
+local_repository(
+ name = "com_google_googletest",
+ path = "external/googletest",
+)
+
+local_repository(
+ name = "com_googlesource_code_re2",
+ path = "external/re2",
+)
+
+local_repository(
+ name = "com_google_effcee",
+ path = "external/effcee",
+)
diff --git a/build_defs.bzl b/build_defs.bzl
new file mode 100644
index 0000000..483fd2a
--- /dev/null
+++ b/build_defs.bzl
@@ -0,0 +1,284 @@
+COMMON_COPTS = [
+ "-DSPIRV_CHECK_CONTEXT",
+ "-DSPIRV_COLOR_TERMINAL",
+ ] + select({
+ "@bazel_tools//src/conditions:windows": [""],
+ "//conditions:default": [
+ "-DSPIRV_LINUX",
+ "-DSPIRV_TIMER_ENABLED",
+ "-Wall",
+ "-Wextra",
+ "-Wnon-virtual-dtor",
+ "-Wno-missing-field-initializers",
+ "-Werror",
+ "-std=c++11",
+ "-fvisibility=hidden",
+ "-fno-exceptions",
+ "-fno-rtti",
+ "-Wno-long-long",
+ "-Wshadow",
+ "-Wundef",
+ "-Wconversion",
+ "-Wno-sign-conversion",
+ ],
+})
+
+TEST_COPTS = COMMON_COPTS + select({
+ "@bazel_tools//src/conditions:windows": [
+ # Disable C4503 "decorated name length exceeded" warning,
+ # triggered by some heavily templated types.
+ # We don't care much about that in test code.
+ # Important to do since we have warnings-as-errors.
+ "/wd4503"
+ ],
+ "//conditions:default": [
+ "-Wno-undef",
+ "-Wno-self-assign",
+ "-Wno-shadow",
+ "-Wno-unused-parameter"
+ ],
+})
+
+DEBUGINFO_GRAMMAR_JSON_FILE = "source/extinst.debuginfo.grammar.json"
+
+def generate_core_tables(version = None):
+ if not version:
+ fail("Must specify version", "version")
+ grammars = [
+ "@spirv_headers//:spirv_core_grammar_" + version,
+ DEBUGINFO_GRAMMAR_JSON_FILE,
+ ]
+ outs = [
+ "core.insts-{}.inc".format(version),
+ "operand.kinds-{}.inc".format(version),
+ ]
+ fmtargs = grammars + outs
+ native.genrule(
+ name = "gen_core_tables_" + version,
+ srcs = grammars,
+ outs = outs,
+ cmd = (
+ "$(location :generate_grammar_tables) " +
+ "--spirv-core-grammar=$(location {0}) " +
+ "--extinst-debuginfo-grammar=$(location {1}) " +
+ "--core-insts-output=$(location {2}) " +
+ "--operand-kinds-output=$(location {3})"
+ ).format(*fmtargs),
+ tools = [":generate_grammar_tables"],
+ visibility = ["//visibility:private"],
+ )
+
+def generate_enum_string_mapping(version = None):
+ if not version:
+ fail("Must specify version", "version")
+ grammars = [
+ "@spirv_headers//:spirv_core_grammar_" + version,
+ DEBUGINFO_GRAMMAR_JSON_FILE,
+ ]
+ outs = [
+ "extension_enum.inc",
+ "enum_string_mapping.inc",
+ ]
+ fmtargs = grammars + outs
+ native.genrule(
+ name = "gen_enum_string_mapping",
+ srcs = grammars,
+ outs = outs,
+ cmd = (
+ "$(location :generate_grammar_tables) " +
+ "--spirv-core-grammar=$(location {0}) " +
+ "--extinst-debuginfo-grammar=$(location {1}) " +
+ "--extension-enum-output=$(location {2}) " +
+ "--enum-string-mapping-output=$(location {3})"
+ ).format(*fmtargs),
+ tools = [":generate_grammar_tables"],
+ visibility = ["//visibility:private"],
+ )
+
+def generate_opencl_tables(version = None):
+ if not version:
+ fail("Must specify version", "version")
+ grammars = [
+ "@spirv_headers//:spirv_opencl_grammar_" + version,
+ ]
+ outs = ["opencl.std.insts.inc"]
+ fmtargs = grammars + outs
+ native.genrule(
+ name = "gen_opencl_tables_" + version,
+ srcs = grammars,
+ outs = outs,
+ cmd = (
+ "$(location :generate_grammar_tables) " +
+ "--extinst-opencl-grammar=$(location {0}) " +
+ "--opencl-insts-output=$(location {1})"
+ ).format(*fmtargs),
+ tools = [":generate_grammar_tables"],
+ visibility = ["//visibility:private"],
+ )
+
+def generate_glsl_tables(version = None):
+ if not version:
+ fail("Must specify version", "version")
+ grammars = [
+ "@spirv_headers//:spirv_glsl_grammar_" + version,
+ ]
+ outs = ["glsl.std.450.insts.inc"]
+ fmtargs = grammars + outs
+ native.genrule(
+ name = "gen_glsl_tables_" + version,
+ srcs = grammars,
+ outs = outs,
+ cmd = (
+ "$(location :generate_grammar_tables) " +
+ "--extinst-glsl-grammar=$(location {0}) " +
+ "--glsl-insts-output=$(location {1})"
+ ).format(*fmtargs),
+ tools = [":generate_grammar_tables"],
+ visibility = ["//visibility:private"],
+ )
+
+def generate_vendor_tables(extension = None):
+ if not extension:
+ fail("Must specify extension", "extension")
+ extension_rule = extension.replace("-", "_")
+ grammars = ["source/extinst.{}.grammar.json".format(extension)]
+ outs = ["{}.insts.inc".format(extension)]
+ fmtargs = grammars + outs
+ native.genrule(
+ name = "gen_vendor_tables_" + extension_rule,
+ srcs = grammars,
+ outs = outs,
+ cmd = (
+ "$(location :generate_grammar_tables) " +
+ "--extinst-vendor-grammar=$(location {0}) " +
+ "--vendor-insts-output=$(location {1})"
+ ).format(*fmtargs),
+ tools = [":generate_grammar_tables"],
+ visibility = ["//visibility:private"],
+ )
+
+def generate_extinst_lang_headers(name, grammar = None):
+ if not grammar:
+ fail("Must specify grammar", "grammar")
+ fmtargs = [name]
+ native.genrule(
+ name = "gen_extinst_lang_headers_" + name,
+ srcs = [grammar],
+ outs = [name + ".h"],
+ cmd = (
+ "$(location :generate_language_headers) " +
+ "--extinst-name={0} " +
+ "--extinst-grammar=$< " +
+ "--extinst-output-base=$(@D)/{0}"
+ ).format(*fmtargs),
+ tools = [":generate_language_headers"],
+ visibility = ["//visibility:private"],
+ )
+
+def base_test(name, srcs, deps = []):
+ if srcs == []:
+ return
+ if name[-5:] != "_test":
+ name = name + "_test"
+ native.cc_test(
+ name = "base_" + name,
+ srcs = srcs,
+ compatible_with = [],
+ copts = TEST_COPTS,
+ size = "large",
+ deps = [
+ ":test_common",
+ "@com_google_googletest//:gtest_main",
+ "@com_google_googletest//:gtest",
+ "@com_google_effcee//:effcee",
+ ] + deps,
+ )
+
+def link_test(name, srcs, deps = []):
+ if name[-5:] != "_test":
+ name = name + "_test"
+ native.cc_test(
+ name = "link_" + name,
+ srcs = srcs,
+ compatible_with = [],
+ copts = TEST_COPTS,
+ size = "large",
+ deps = [
+ ":link_test_common",
+ "@com_google_googletest//:gtest_main",
+ "@com_google_googletest//:gtest",
+ "@com_google_effcee//:effcee",
+ ] + deps,
+ )
+
+def opt_test(name, srcs, deps = []):
+ if name[-5:] != "_test":
+ name = name + "_test"
+ native.cc_test(
+ name = "opt_" + name,
+ srcs = srcs,
+ compatible_with = [],
+ copts = TEST_COPTS,
+ size = "large",
+ deps = [
+ ":opt_test_common",
+ "@com_google_googletest//:gtest_main",
+ "@com_google_googletest//:gtest",
+ "@com_google_effcee//:effcee",
+ ] + deps,
+ )
+
+def reduce_test(name, srcs, deps = []):
+ if name[-5:] != "_test":
+ name = name + "_test"
+ native.cc_test(
+ name = "reduce_" + name,
+ srcs = srcs,
+ compatible_with = [],
+ copts = TEST_COPTS,
+ size = "large",
+ deps = [
+ ":reduce_test_common",
+ ":spirv_tools_reduce",
+ "@com_google_googletest//:gtest_main",
+ "@com_google_googletest//:gtest",
+ "@com_google_effcee//:effcee",
+ ] + deps,
+ )
+
+def util_test(name, srcs, deps = []):
+ if name[-5:] != "_test":
+ name = name + "_test"
+ native.cc_test(
+ name = "util_" + name,
+ srcs = srcs,
+ compatible_with = [],
+ copts = TEST_COPTS,
+ size = "large",
+ deps = [
+ ":opt_test_common",
+ "@com_google_googletest//:gtest_main",
+ "@com_google_googletest//:gtest",
+ "@com_google_effcee//:effcee",
+ ] + deps,
+ )
+
+def val_test(name, srcs = [], copts = [], deps = [], **kwargs):
+ if name[-5:] != "_test":
+ name = name + "_test"
+ if name[:4] != "val_":
+ name = "val_" + name
+ native.cc_test(
+ name = name,
+ srcs = srcs,
+ compatible_with = [],
+ copts = TEST_COPTS + copts,
+ size = "large",
+ deps = [
+ ":val_test_common",
+ "@com_google_googletest//:gtest_main",
+ "@com_google_googletest//:gtest",
+ "@com_google_effcee//:effcee",
+ ] + deps,
+ **kwargs
+ )
diff --git a/downloads.md b/docs/downloads.md
similarity index 100%
rename from downloads.md
rename to docs/downloads.md
diff --git a/projects.md b/docs/projects.md
similarity index 100%
rename from projects.md
rename to docs/projects.md
diff --git a/syntax.md b/docs/syntax.md
similarity index 100%
rename from syntax.md
rename to docs/syntax.md
diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h
index e21b058..dd2526b 100644
--- a/include/spirv-tools/libspirv.h
+++ b/include/spirv-tools/libspirv.h
@@ -433,6 +433,7 @@
SPV_ENV_WEBGPU_0, // Work in progress WebGPU 1.0.
SPV_ENV_UNIVERSAL_1_4, // SPIR-V 1.4 latest revision, no other restrictions.
SPV_ENV_VULKAN_1_1_SPIRV_1_4, // Vulkan 1.1 with SPIR-V 1.4 binary.
+ SPV_ENV_UNIVERSAL_1_5, // SPIR-V 1.5 latest revision, no other restrictions.
} spv_target_env;
// SPIR-V Validator can be parameterized with the following Universal Limits.
@@ -611,6 +612,11 @@
// Destroys the given fuzzer options object.
SPIRV_TOOLS_EXPORT void spvFuzzerOptionsDestroy(spv_fuzzer_options options);
+// Enables running the validator after every transformation is applied during
+// a replay.
+SPIRV_TOOLS_EXPORT void spvFuzzerOptionsEnableReplayValidation(
+ spv_fuzzer_options options);
+
// Sets the seed with which the random number generator used by the fuzzer
// should be initialized.
SPIRV_TOOLS_EXPORT void spvFuzzerOptionsSetRandomSeed(
diff --git a/include/spirv-tools/libspirv.hpp b/include/spirv-tools/libspirv.hpp
index 2da1152..b09fdd4 100644
--- a/include/spirv-tools/libspirv.hpp
+++ b/include/spirv-tools/libspirv.hpp
@@ -214,6 +214,11 @@
return options_;
}
+ // See spvFuzzerOptionsEnableReplayValidation.
+ void enable_replay_validation() {
+ spvFuzzerOptionsEnableReplayValidation(options_);
+ }
+
// See spvFuzzerOptionsSetRandomSeed.
void set_random_seed(uint32_t seed) {
spvFuzzerOptionsSetRandomSeed(options_, seed);
diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
index 4e54b1a..509051d 100644
--- a/include/spirv-tools/optimizer.hpp
+++ b/include/spirv-tools/optimizer.hpp
@@ -68,6 +68,11 @@
// The constructed instance will have an empty message consumer, which just
// ignores all messages from the library. Use SetMessageConsumer() to supply
// one 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.
@@ -674,6 +679,22 @@
// processed (see IsSSATargetVar for details).
Optimizer::PassToken CreateSSARewritePass();
+// Create pass to convert relaxed precision instructions to half precision.
+// This pass converts as many relaxed float32 arithmetic operations to half as
+// possible. It converts any float32 operands to half if needed. It converts
+// any resulting half precision values back to float32 as needed. No variables
+// are changed. No image operations are changed.
+//
+// Best if run late since it will generate better code with unneeded function
+// scope loads and stores and composite inserts and extracts removed. Also best
+// if followed by instruction simplification, redundancy elimination and DCE.
+Optimizer::PassToken CreateConvertRelaxedToHalfPass();
+
+// Create relax float ops pass.
+// This pass decorates all float32 result instructions with RelaxedPrecision
+// if not already so decorated.
+Optimizer::PassToken CreateRelaxFloatOpsPass();
+
// Create copy propagate arrays pass.
// This pass looks to copy propagate memory references for arrays. It looks
// for specific code patterns to recognize array copies.
diff --git a/kokoro/linux-clang-release-bazel/build.sh b/kokoro/linux-clang-release-bazel/build.sh
new file mode 100644
index 0000000..cc38bd4
--- /dev/null
+++ b/kokoro/linux-clang-release-bazel/build.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+# 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.
+#
+# Linux Build Script.
+
+# Fail on any error.
+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 --depth=1 https://github.com/google/googletest external/googletest
+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.
diff --git a/kokoro/linux-clang-release-bazel/continuous.cfg b/kokoro/linux-clang-release-bazel/continuous.cfg
new file mode 100644
index 0000000..8b33a24
--- /dev/null
+++ b/kokoro/linux-clang-release-bazel/continuous.cfg
@@ -0,0 +1,16 @@
+# 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.
+
+# Continuous build configuration.
+build_file: "SPIRV-Tools/kokoro/linux-clang-release-bazel/build.sh"
diff --git a/kokoro/linux-clang-release-bazel/presubmit.cfg b/kokoro/linux-clang-release-bazel/presubmit.cfg
new file mode 100644
index 0000000..c7a2e6f
--- /dev/null
+++ b/kokoro/linux-clang-release-bazel/presubmit.cfg
@@ -0,0 +1,16 @@
+# 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.
+
+# Presubmit build configuration.
+build_file: "SPIRV-Tools/kokoro/linux-clang-release-bazel/build.sh"
diff --git a/kokoro/macos-clang-release-bazel/build.sh b/kokoro/macos-clang-release-bazel/build.sh
new file mode 100644
index 0000000..e92fa74
--- /dev/null
+++ b/kokoro/macos-clang-release-bazel/build.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# 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.
+#
+# Linux Build Script.
+
+# Fail on any error.
+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 --depth=1 https://github.com/google/googletest external/googletest
+git clone --depth=1 https://github.com/google/effcee external/effcee
+git clone --depth=1 https://github.com/google/re2 external/re2
+
+# Get bazel 0.29.1.
+gsutil cp gs://bazel/0.29.1/release/bazel-0.29.1-darwin-x86_64 .
+chmod +x bazel-0.29.1-darwin-x86_64
+
+echo $(date): Build everything...
+./bazel-0.29.1-darwin-x86_64 build :all
+echo $(date): Build completed.
+
+echo $(date): Starting bazel test...
+./bazel-0.29.1-darwin-x86_64 test :all
+echo $(date): Bazel test completed.
diff --git a/kokoro/macos-clang-release-bazel/continuous.cfg b/kokoro/macos-clang-release-bazel/continuous.cfg
new file mode 100644
index 0000000..9765489
--- /dev/null
+++ b/kokoro/macos-clang-release-bazel/continuous.cfg
@@ -0,0 +1,16 @@
+# 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.
+
+# Continuous build configuration.
+build_file: "SPIRV-Tools/kokoro/macos-clang-release-bazel/build.sh"
diff --git a/kokoro/macos-clang-release-bazel/presubmit.cfg b/kokoro/macos-clang-release-bazel/presubmit.cfg
new file mode 100644
index 0000000..3b13602
--- /dev/null
+++ b/kokoro/macos-clang-release-bazel/presubmit.cfg
@@ -0,0 +1,16 @@
+# 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.
+
+# Presubmit build configuration.
+build_file: "SPIRV-Tools/kokoro/macos-clang-release-bazel/build.sh"
diff --git a/kokoro/windows-msvc-2015-release-bazel/build.bat b/kokoro/windows-msvc-2015-release-bazel/build.bat
new file mode 100644
index 0000000..ddb4f54
--- /dev/null
+++ b/kokoro/windows-msvc-2015-release-bazel/build.bat
@@ -0,0 +1,59 @@
+:: 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.
+::
+:: Windows Build Script.
+
+@echo on
+
+set SRC=%cd%\github\SPIRV-Tools
+
+:: Force usage of python 3.6
+set PATH=C:\python36;%PATH%
+
+:: Get dependencies
+cd %SRC%
+git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers
+git clone --depth=1 https://github.com/google/googletest external/googletest
+git clone --depth=1 https://github.com/google/effcee external/effcee
+git clone --depth=1 https://github.com/google/re2 external/re2
+
+:: REM Install Bazel.
+wget -q https://github.com/bazelbuild/bazel/releases/download/0.29.1/bazel-0.29.1-windows-x86_64.zip
+unzip -q bazel-0.29.1-windows-x86_64.zip
+
+:: Set up MSVC
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
+set BAZEL_VS=C:\Program Files (x86)\Microsoft Visual Studio 14.0
+set BAZEL_VC=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
+set BAZEL_SH=c:\tools\msys64\usr\bin\bash.exe
+set BAZEL_PYTHON=c:\tools\python2\python.exe
+
+:: #########################################
+:: Start building.
+:: #########################################
+echo "Build everything... %DATE% %TIME%"
+bazel.exe build :all
+if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
+echo "Build Completed %DATE% %TIME%"
+
+:: ##############
+:: Run the tests
+:: ##############
+echo "Running Tests... %DATE% %TIME%"
+bazel.exe test :all
+if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
+echo "Tests Completed %DATE% %TIME%"
+
+exit /b 0
+
diff --git a/kokoro/windows-msvc-2015-release-bazel/continuous.cfg b/kokoro/windows-msvc-2015-release-bazel/continuous.cfg
new file mode 100644
index 0000000..f72cf05
--- /dev/null
+++ b/kokoro/windows-msvc-2015-release-bazel/continuous.cfg
@@ -0,0 +1,16 @@
+# 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.
+
+# Continuous build configuration.
+build_file: "SPIRV-Tools/kokoro/windows-msvc-2015-release-bazel/build.bat"
diff --git a/kokoro/windows-msvc-2015-release-bazel/presubmit.cfg b/kokoro/windows-msvc-2015-release-bazel/presubmit.cfg
new file mode 100644
index 0000000..148972c
--- /dev/null
+++ b/kokoro/windows-msvc-2015-release-bazel/presubmit.cfg
@@ -0,0 +1,16 @@
+# 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.
+
+# Presubmit build configuration.
+build_file: "SPIRV-Tools/kokoro/windows-msvc-2015-release-bazel/build.bat"
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index cb63ff0..f3b5942 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -283,7 +283,6 @@
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_composites.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_constants.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_conversion.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_datarules.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_debug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_decorations.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_derivatives.cpp
@@ -339,7 +338,9 @@
add_library(${SPIRV_TOOLS} ${SPIRV_SOURCES})
spvtools_default_compile_options(${SPIRV_TOOLS})
target_include_directories(${SPIRV_TOOLS}
- PUBLIC ${spirv-tools_SOURCE_DIR}/include
+ PUBLIC
+ $<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
PRIVATE ${SPIRV_HEADER_INCLUDE_DIR}
)
@@ -350,7 +351,9 @@
add_library(${SPIRV_TOOLS}-shared SHARED ${SPIRV_SOURCES})
spvtools_default_compile_options(${SPIRV_TOOLS}-shared)
target_include_directories(${SPIRV_TOOLS}-shared
- PUBLIC ${spirv-tools_SOURCE_DIR}/include
+ PUBLIC
+ $<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
PRIVATE ${SPIRV_HEADER_INCLUDE_DIR}
)
@@ -372,10 +375,21 @@
endif()
if(ENABLE_SPIRV_TOOLS_INSTALL)
- install(TARGETS ${SPIRV_TOOLS} ${SPIRV_TOOLS}-shared
+ install(TARGETS ${SPIRV_TOOLS} ${SPIRV_TOOLS}-shared EXPORT ${SPIRV_TOOLS}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ export(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake)
+
+ spvtools_config_package_dir(${SPIRV_TOOLS} PACKAGE_DIR)
+ install(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake DESTINATION ${PACKAGE_DIR})
+
+ # Special config file for root library compared to other libs.
+ file(WRITE ${CMAKE_BINARY_DIR}/${SPIRV_TOOLS}Config.cmake
+ "include(\${CMAKE_CURRENT_LIST_DIR}/${SPIRV_TOOLS}Target.cmake)\n"
+ "set(${SPIRV_TOOLS}_LIBRARIES ${SPIRV_TOOLS})\n"
+ "get_target_property(${SPIRV_TOOLS}_INCLUDE_DIRS ${SPIRV_TOOLS} INTERFACE_INCLUDE_DIRECTORIES)\n")
+ install(FILES ${CMAKE_BINARY_DIR}/${SPIRV_TOOLS}Config.cmake DESTINATION ${PACKAGE_DIR})
endif(ENABLE_SPIRV_TOOLS_INSTALL)
if(MSVC)
diff --git a/source/binary.cpp b/source/binary.cpp
index 636dac8..1d31283 100644
--- a/source/binary.cpp
+++ b/source/binary.cpp
@@ -781,9 +781,10 @@
// TODO(dneto): This probably belongs in text.cpp since that's the only place
// that a spv_binary_t value is created.
void spvBinaryDestroy(spv_binary binary) {
- if (!binary) return;
- delete[] binary->code;
- delete binary;
+ if (binary) {
+ if (binary->code) delete[] binary->code;
+ delete binary;
+ }
}
size_t spv_strnlen_s(const char* str, size_t strsz) {
diff --git a/source/ext_inst.cpp b/source/ext_inst.cpp
index 1198f76..0499e23 100644
--- a/source/ext_inst.cpp
+++ b/source/ext_inst.cpp
@@ -84,6 +84,7 @@
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:
*pExtInstTable = &kTable_1_0;
return SPV_SUCCESS;
default:
diff --git a/source/fuzz/CMakeLists.txt b/source/fuzz/CMakeLists.txt
index 49ee843..97f8976 100644
--- a/source/fuzz/CMakeLists.txt
+++ b/source/fuzz/CMakeLists.txt
@@ -13,6 +13,9 @@
# limitations under the License.
if(SPIRV_BUILD_FUZZER)
+
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/protobufs)
+
set(PROTOBUF_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/protobufs/spvtoolsfuzz.proto)
add_custom_command(
@@ -27,18 +30,29 @@
set(SPIRV_TOOLS_FUZZ_SOURCES
data_descriptor.h
+ equivalence_relation.h
fact_manager.h
+ force_render_red.h
fuzzer.h
fuzzer_context.h
fuzzer_pass.h
fuzzer_pass_add_dead_breaks.h
fuzzer_pass_add_dead_continues.h
+ fuzzer_pass_add_no_contraction_decorations.h
fuzzer_pass_add_useful_constructs.h
+ fuzzer_pass_adjust_function_controls.h
+ fuzzer_pass_adjust_loop_controls.h
+ fuzzer_pass_adjust_memory_operands_masks.h
+ fuzzer_pass_adjust_selection_controls.h
+ fuzzer_pass_apply_id_synonyms.h
+ fuzzer_pass_construct_composites.h
+ fuzzer_pass_copy_objects.h
fuzzer_pass_obfuscate_constants.h
fuzzer_pass_permute_blocks.h
fuzzer_pass_split_blocks.h
fuzzer_util.h
id_use_descriptor.h
+ instruction_descriptor.h
protobufs/spirvfuzz_protobufs.h
pseudo_random_generator.h
random_generator.h
@@ -49,31 +63,50 @@
transformation_add_constant_scalar.h
transformation_add_dead_break.h
transformation_add_dead_continue.h
+ transformation_add_no_contraction_decoration.h
transformation_add_type_boolean.h
transformation_add_type_float.h
transformation_add_type_int.h
transformation_add_type_pointer.h
+ transformation_composite_construct.h
+ transformation_composite_extract.h
transformation_copy_object.h
transformation_move_block_down.h
transformation_replace_boolean_constant_with_constant_binary.h
transformation_replace_constant_with_uniform.h
+ transformation_replace_id_with_synonym.h
+ transformation_set_function_control.h
+ transformation_set_loop_control.h
+ transformation_set_memory_operands_mask.h
+ transformation_set_selection_control.h
transformation_split_block.h
+ transformation_vector_shuffle.h
uniform_buffer_element_descriptor.h
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h
data_descriptor.cpp
fact_manager.cpp
+ force_render_red.cpp
fuzzer.cpp
fuzzer_context.cpp
fuzzer_pass.cpp
fuzzer_pass_add_dead_breaks.cpp
fuzzer_pass_add_dead_continues.cpp
+ fuzzer_pass_add_no_contraction_decorations.cpp
fuzzer_pass_add_useful_constructs.cpp
+ fuzzer_pass_adjust_function_controls.cpp
+ fuzzer_pass_adjust_loop_controls.cpp
+ fuzzer_pass_adjust_memory_operands_masks.cpp
+ fuzzer_pass_adjust_selection_controls.cpp
+ fuzzer_pass_apply_id_synonyms.cpp
+ fuzzer_pass_construct_composites.cpp
+ fuzzer_pass_copy_objects.cpp
fuzzer_pass_obfuscate_constants.cpp
fuzzer_pass_permute_blocks.cpp
fuzzer_pass_split_blocks.cpp
fuzzer_util.cpp
id_use_descriptor.cpp
+ instruction_descriptor.cpp
pseudo_random_generator.cpp
random_generator.cpp
replayer.cpp
@@ -83,15 +116,24 @@
transformation_add_constant_scalar.cpp
transformation_add_dead_break.cpp
transformation_add_dead_continue.cpp
+ transformation_add_no_contraction_decoration.cpp
transformation_add_type_boolean.cpp
transformation_add_type_float.cpp
transformation_add_type_int.cpp
transformation_add_type_pointer.cpp
+ transformation_composite_construct.cpp
+ transformation_composite_extract.cpp
transformation_copy_object.cpp
transformation_move_block_down.cpp
transformation_replace_boolean_constant_with_constant_binary.cpp
transformation_replace_constant_with_uniform.cpp
+ transformation_replace_id_with_synonym.cpp
+ transformation_set_function_control.cpp
+ transformation_set_loop_control.cpp
+ transformation_set_memory_operands_mask.cpp
+ transformation_set_selection_control.cpp
transformation_split_block.cpp
+ transformation_vector_shuffle.cpp
uniform_buffer_element_descriptor.cpp
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc
)
@@ -118,8 +160,10 @@
endif()
target_include_directories(SPIRV-Tools-fuzz
- PUBLIC ${spirv-tools_SOURCE_DIR}/include
- PUBLIC ${SPIRV_HEADER_INCLUDE_DIR}
+ PUBLIC
+ $<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
+ $<BUILD_INTERFACE:${SPIRV_HEADER_INCLUDE_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
PRIVATE ${CMAKE_BINARY_DIR})
@@ -133,10 +177,18 @@
spvtools_check_symbol_exports(SPIRV-Tools-fuzz)
if(ENABLE_SPIRV_TOOLS_INSTALL)
- install(TARGETS SPIRV-Tools-fuzz
+ install(TARGETS SPIRV-Tools-fuzz EXPORT SPIRV-Tools-fuzzTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ export(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake)
+
+ spvtools_config_package_dir(SPIRV-Tools-fuzz PACKAGE_DIR)
+ install(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake
+ DESTINATION ${PACKAGE_DIR})
+
+ spvtools_generate_config_file(SPIRV-Tools-fuzz)
+ install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-fuzzConfig.cmake DESTINATION ${PACKAGE_DIR})
endif(ENABLE_SPIRV_TOOLS_INSTALL)
endif(SPIRV_BUILD_FUZZER)
diff --git a/source/fuzz/data_descriptor.cpp b/source/fuzz/data_descriptor.cpp
index 9cdb2c5..86e5325 100644
--- a/source/fuzz/data_descriptor.cpp
+++ b/source/fuzz/data_descriptor.cpp
@@ -29,6 +29,16 @@
return result;
}
+size_t DataDescriptorHash::operator()(
+ const protobufs::DataDescriptor* data_descriptor) const {
+ std::u32string hash;
+ hash.push_back(data_descriptor->object());
+ for (auto an_index : data_descriptor->index()) {
+ hash.push_back(an_index);
+ }
+ return std::hash<std::u32string>()(hash);
+}
+
bool DataDescriptorEquals::operator()(
const protobufs::DataDescriptor* first,
const protobufs::DataDescriptor* second) const {
@@ -38,5 +48,22 @@
second->index().begin());
}
+std::ostream& operator<<(std::ostream& out,
+ const protobufs::DataDescriptor& data_descriptor) {
+ out << data_descriptor.object();
+ out << "[";
+ bool first = true;
+ for (auto index : data_descriptor.index()) {
+ if (first) {
+ first = false;
+ } else {
+ out << ", ";
+ }
+ out << index;
+ }
+ out << "]";
+ return out;
+}
+
} // namespace fuzz
} // namespace spvtools
diff --git a/source/fuzz/data_descriptor.h b/source/fuzz/data_descriptor.h
index 731bd21..c569ac8 100644
--- a/source/fuzz/data_descriptor.h
+++ b/source/fuzz/data_descriptor.h
@@ -17,6 +17,7 @@
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include <ostream>
#include <vector>
namespace spvtools {
@@ -27,13 +28,21 @@
protobufs::DataDescriptor MakeDataDescriptor(uint32_t object,
std::vector<uint32_t>&& indices);
+// Hash function for data descriptors.
+struct DataDescriptorHash {
+ size_t operator()(const protobufs::DataDescriptor* data_descriptor) const;
+};
+
// Equality function for data descriptors.
struct DataDescriptorEquals {
bool operator()(const protobufs::DataDescriptor* first,
const protobufs::DataDescriptor* second) const;
};
+std::ostream& operator<<(std::ostream& out,
+ const protobufs::DataDescriptor& data_descriptor);
+
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_DATA_DESCRIPTOR_H_
+#endif // SOURCE_FUZZ_DATA_DESCRIPTOR_H_
diff --git a/source/fuzz/equivalence_relation.h b/source/fuzz/equivalence_relation.h
new file mode 100644
index 0000000..046536f
--- /dev/null
+++ b/source/fuzz/equivalence_relation.h
@@ -0,0 +1,237 @@
+// 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_FUZZ_EQUIVALENCE_RELATION_H_
+#define SOURCE_FUZZ_EQUIVALENCE_RELATION_H_
+
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "source/util/make_unique.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A class for representing an equivalence relation on objects of type |T|,
+// which should be a value type. The type |T| is required to have a copy
+// constructor, and |PointerHashT| and |PointerEqualsT| must be functors
+// providing hashing and equality testing functionality for pointers to objects
+// of type |T|.
+//
+// A disjoint-set (a.k.a. union-find or merge-find) data structure is used to
+// represent the equivalence relation. Path compression is used. Union by
+// rank/size is not used.
+//
+// Each disjoint set is represented as a tree, rooted at the representative
+// of the set.
+//
+// Getting the representative of a value simply requires chasing parent pointers
+// from the value until you reach the root.
+//
+// Checking equivalence of two elements requires checking that the
+// representatives are equal.
+//
+// Traversing the tree rooted at a value's representative visits the value's
+// equivalence class.
+//
+// |PointerHashT| and |PointerEqualsT| are used to define *equality* between
+// values, and otherwise are *not* used to define the equivalence relation
+// (except that equal values are equivalent). The equivalence relation is
+// constructed by repeatedly adding pairs of (typically non-equal) values that
+// are deemed to be equivalent.
+//
+// For example in an equivalence relation on integers, 1 and 5 might be added
+// as equivalent, so that IsEquivalent(1, 5) holds, because they represent
+// IDs in a SPIR-V binary that are known to contain the same value at run time,
+// but clearly 1 != 5. Since 1 and 1 are equal, IsEquivalent(1, 1) will also
+// hold.
+//
+// Each unique (up to equality) value added to the relation is copied into
+// |owned_values_|, so there is one canonical memory address per unique value.
+// Uniqueness is ensured by storing (and checking) a set of pointers to these
+// values in |value_set_|, which uses |PointerHashT| and |PointerEqualsT|.
+//
+// |parent_| and |children_| encode the equivalence relation, i.e., the trees.
+template <typename T, typename PointerHashT, typename PointerEqualsT>
+class EquivalenceRelation {
+ public:
+ // Merges the equivalence classes associated with |value1| and |value2|.
+ // If any of these values was not previously in the equivalence relation, it
+ // is added to the pool of values known to be in the relation.
+ void MakeEquivalent(const T& value1, const T& value2) {
+ // Register each value if necessary.
+ for (auto value : {value1, value2}) {
+ if (!Exists(value)) {
+ // Register the value in the equivalence relation. This relies on
+ // T having a copy constructor.
+ auto unique_pointer_to_value = MakeUnique<T>(value);
+ auto pointer_to_value = unique_pointer_to_value.get();
+ owned_values_.push_back(std::move(unique_pointer_to_value));
+ value_set_.insert(pointer_to_value);
+
+ // Initially say that the value is its own parent and that it has no
+ // children.
+ assert(pointer_to_value && "Representatives should never be null.");
+ parent_[pointer_to_value] = pointer_to_value;
+ children_[pointer_to_value] = std::vector<const T*>();
+ }
+ }
+
+ // Look up canonical pointers to each of the values in the value pool.
+ const T* value1_ptr = *value_set_.find(&value1);
+ const T* value2_ptr = *value_set_.find(&value2);
+
+ // If the values turn out to be identical, they are already in the same
+ // equivalence class so there is nothing to do.
+ if (value1_ptr == value2_ptr) {
+ return;
+ }
+
+ // Find the representative for each value's equivalence class, and if they
+ // are not already in the same class, make one the parent of the other.
+ const T* representative1 = Find(value1_ptr);
+ const T* representative2 = Find(value2_ptr);
+ assert(representative1 && "Representatives should never be null.");
+ assert(representative2 && "Representatives should never be null.");
+ if (representative1 != representative2) {
+ parent_[representative1] = representative2;
+ children_[representative2].push_back(representative1);
+ }
+ }
+
+ // Returns exactly one representative per equivalence class.
+ std::vector<const T*> GetEquivalenceClassRepresentatives() const {
+ std::vector<const T*> result;
+ for (auto& value : owned_values_) {
+ if (parent_[value.get()] == value.get()) {
+ result.push_back(value.get());
+ }
+ }
+ return result;
+ }
+
+ // Returns pointers to all values in the equivalence class of |value|, which
+ // must already be part of the equivalence relation.
+ std::vector<const T*> GetEquivalenceClass(const T& value) const {
+ assert(Exists(value));
+
+ std::vector<const T*> result;
+
+ // Traverse the tree of values rooted at the representative of the
+ // equivalence class to which |value| belongs, and collect up all the values
+ // that are encountered. This constitutes the whole equivalence class.
+ std::vector<const T*> stack;
+ stack.push_back(Find(*value_set_.find(&value)));
+ while (!stack.empty()) {
+ const T* item = stack.back();
+ result.push_back(item);
+ stack.pop_back();
+ for (auto child : children_[item]) {
+ stack.push_back(child);
+ }
+ }
+ return result;
+ }
+
+ // Returns true if and only if |value1| and |value2| are in the same
+ // equivalence class. Both values must already be known to the equivalence
+ // relation.
+ bool IsEquivalent(const T& value1, const T& value2) const {
+ return Find(&value1) == Find(&value2);
+ }
+
+ // Returns all values known to be part of the equivalence relation.
+ std::vector<const T*> GetAllKnownValues() const {
+ std::vector<const T*> result;
+ for (auto& value : owned_values_) {
+ result.push_back(value.get());
+ }
+ return result;
+ }
+
+ // Returns true if and only if |value| is known to be part of the equivalence
+ // relation.
+ bool Exists(const T& value) const {
+ return value_set_.find(&value) != value_set_.end();
+ }
+
+ private:
+ // Returns the representative of the equivalence class of |value|, which must
+ // already be known to the equivalence relation. This is the 'Find' operation
+ // in a classic union-find data structure.
+ const T* Find(const T* value) const {
+ assert(Exists(*value));
+
+ // Get the canonical pointer to the value from the value pool.
+ const T* known_value = *value_set_.find(value);
+ assert(parent_[known_value] && "Every known value should have a parent.");
+
+ // Compute the result by chasing parents until we find a value that is its
+ // own parent.
+ const T* result = known_value;
+ while (parent_[result] != result) {
+ result = parent_[result];
+ }
+ assert(result && "Representatives should never be null.");
+
+ // At this point, |result| is the representative of the equivalence class.
+ // Now perform the 'path compression' optimization by doing another pass up
+ // the parent chain, setting the parent of each node to be the
+ // representative, and rewriting children correspondingly.
+ const T* current = known_value;
+ while (parent_[current] != result) {
+ const T* next = parent_[current];
+ parent_[current] = result;
+ children_[result].push_back(current);
+ auto child_iterator =
+ std::find(children_[next].begin(), children_[next].end(), current);
+ assert(child_iterator != children_[next].end() &&
+ "'next' is the parent of 'current', so 'current' should be a "
+ "child of 'next'");
+ children_[next].erase(child_iterator);
+ current = next;
+ }
+ return result;
+ }
+
+ // Maps every value to a parent. The representative of an equivalence class
+ // is its own parent. A value's representative can be found by walking its
+ // chain of ancestors.
+ //
+ // Mutable because the intuitively const method, 'Find', performs path
+ // compression.
+ mutable std::unordered_map<const T*, const T*> parent_;
+
+ // Stores the children of each value. This allows the equivalence class of
+ // a value to be calculated by traversing all descendents of the class's
+ // representative.
+ //
+ // Mutable because the intuitively const method, 'Find', performs path
+ // compression.
+ mutable std::unordered_map<const T*, std::vector<const T*>> children_;
+
+ // The values known to the equivalence relation are allocated in
+ // |owned_values_|, and |value_pool_| provides (via |PointerHashT| and
+ // |PointerEqualsT|) a means for mapping a value of interest to a pointer
+ // into an equivalent value in |owned_values_|.
+ std::unordered_set<const T*, PointerHashT, PointerEqualsT> value_set_;
+ std::vector<std::unique_ptr<T>> owned_values_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_EQUIVALENCE_RELATION_H_
diff --git a/source/fuzz/fact_manager.cpp b/source/fuzz/fact_manager.cpp
index 61daa64..ac3ea30 100644
--- a/source/fuzz/fact_manager.cpp
+++ b/source/fuzz/fact_manager.cpp
@@ -15,7 +15,11 @@
#include "source/fuzz/fact_manager.h"
#include <sstream>
+#include <unordered_map>
+#include <unordered_set>
+#include "source/fuzz/equivalence_relation.h"
+#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "source/opt/ir_context.h"
@@ -26,7 +30,7 @@
std::string ToString(const protobufs::Fact& fact) {
assert(fact.fact_case() == protobufs::Fact::kConstantUniformFact &&
- "Right now this is the only fact.");
+ "Right now this is the only fact we know how to stringify.");
std::stringstream stream;
stream << "("
<< fact.constant_uniform_fact()
@@ -71,9 +75,10 @@
//=======================
// Constant uniform facts
-// The purpose of this struct is to group the fields and data used to represent
+// The purpose of this class is to group the fields and data used to represent
// facts about uniform constants.
-struct FactManager::ConstantUniformFacts {
+class FactManager::ConstantUniformFacts {
+ public:
// See method in FactManager which delegates to this method.
bool AddFact(const protobufs::FactConstantUniform& fact,
opt::IRContext* context);
@@ -96,6 +101,11 @@
// See method in FactManager which delegates to this method.
std::vector<uint32_t> GetTypesForWhichUniformValuesAreKnown() const;
+ // See method in FactManager which delegates to this method.
+ const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
+ GetConstantUniformFactsAndTypes() const;
+
+ private:
// Returns true if and only if the words associated with
// |constant_instruction| exactly match the words for the constant associated
// with |constant_uniform_fact|.
@@ -121,7 +131,7 @@
uint32_t width) const;
std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>
- facts_and_type_ids;
+ facts_and_type_ids_;
};
uint32_t FactManager::ConstantUniformFacts::GetConstantId(
@@ -160,7 +170,7 @@
opt::IRContext* ir_context, uint32_t type_id) const {
std::vector<uint32_t> result;
std::set<uint32_t> already_seen;
- for (auto& fact_and_type_id : facts_and_type_ids) {
+ for (auto& fact_and_type_id : facts_and_type_ids_) {
if (fact_and_type_id.second != type_id) {
continue;
}
@@ -183,7 +193,7 @@
assert(constant_inst->opcode() == SpvOpConstant &&
"The given id must be that of a constant");
auto type_id = constant_inst->type_id();
- for (auto& fact_and_type_id : facts_and_type_ids) {
+ for (auto& fact_and_type_id : facts_and_type_ids_) {
if (fact_and_type_id.second != type_id) {
continue;
}
@@ -199,7 +209,7 @@
opt::IRContext* context,
const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const {
// Consider each fact.
- for (auto& fact_and_type : facts_and_type_ids) {
+ for (auto& fact_and_type : facts_and_type_ids_) {
// Check whether the uniform descriptor associated with the fact matches
// |uniform_descriptor|.
if (UniformBufferElementDescriptorEquals()(
@@ -216,7 +226,7 @@
FactManager::ConstantUniformFacts::GetTypesForWhichUniformValuesAreKnown()
const {
std::vector<uint32_t> result;
- for (auto& fact_and_type : facts_and_type_ids) {
+ for (auto& fact_and_type : facts_and_type_ids_) {
if (std::find(result.begin(), result.end(), fact_and_type.second) ==
result.end()) {
result.push_back(fact_and_type.second);
@@ -276,42 +286,20 @@
}
auto should_be_uniform_pointer_instruction =
context->get_def_use_mgr()->GetDef(uniform_variable->type_id());
- auto element_type =
+ auto composite_type =
should_be_uniform_pointer_instruction->GetSingleWordInOperand(1);
- for (auto index : fact.uniform_buffer_element_descriptor().index()) {
- auto should_be_composite_type =
- context->get_def_use_mgr()->GetDef(element_type);
- if (SpvOpTypeStruct == should_be_composite_type->opcode()) {
- if (index >= should_be_composite_type->NumInOperands()) {
- return false;
- }
- element_type = should_be_composite_type->GetSingleWordInOperand(index);
- } else if (SpvOpTypeArray == should_be_composite_type->opcode()) {
- auto array_length_constant =
- context->get_constant_mgr()
- ->GetConstantFromInst(context->get_def_use_mgr()->GetDef(
- should_be_composite_type->GetSingleWordInOperand(1)))
- ->AsIntConstant();
- if (array_length_constant->words().size() != 1) {
- return false;
- }
- auto array_length = array_length_constant->GetU32();
- if (index >= array_length) {
- return false;
- }
- element_type = should_be_composite_type->GetSingleWordInOperand(0);
- } else if (SpvOpTypeVector == should_be_composite_type->opcode()) {
- auto vector_length = should_be_composite_type->GetSingleWordInOperand(1);
- if (index >= vector_length) {
- return false;
- }
- element_type = should_be_composite_type->GetSingleWordInOperand(0);
- } else {
- return false;
- }
+ auto final_element_type_id = fuzzerutil::WalkCompositeTypeIndices(
+ context, composite_type,
+ fact.uniform_buffer_element_descriptor().index());
+ if (!final_element_type_id) {
+ return false;
}
- auto final_element_type = context->get_type_mgr()->GetType(element_type);
+ auto final_element_type =
+ context->get_type_mgr()->GetType(final_element_type_id);
+ assert(final_element_type &&
+ "There should be a type corresponding to this id.");
+
if (!(final_element_type->AsFloat() || final_element_type->AsInteger())) {
return false;
}
@@ -328,48 +316,493 @@
if (static_cast<uint32_t>(fact.constant_word().size()) != required_words) {
return false;
}
- facts_and_type_ids.emplace_back(
- std::pair<protobufs::FactConstantUniform, uint32_t>(fact, element_type));
+ facts_and_type_ids_.emplace_back(
+ std::pair<protobufs::FactConstantUniform, uint32_t>(
+ fact, final_element_type_id));
return true;
}
+const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
+FactManager::ConstantUniformFacts::GetConstantUniformFactsAndTypes() const {
+ return facts_and_type_ids_;
+}
+
// End of uniform constant facts
//==============================
//==============================
-// Id synonym facts
+// Data synonym facts
-// The purpose of this struct is to group the fields and data used to represent
-// facts about id synonyms.
-struct FactManager::IdSynonymFacts {
+// The purpose of this class is to group the fields and data used to represent
+// facts about data synonyms.
+class FactManager::DataSynonymFacts {
+ public:
// See method in FactManager which delegates to this method.
- void AddFact(const protobufs::FactIdSynonym& fact);
+ void AddFact(const protobufs::FactDataSynonym& fact, opt::IRContext* context);
- // A record of all the synonyms that are available.
- std::map<uint32_t, std::vector<protobufs::DataDescriptor>> synonyms;
+ // See method in FactManager which delegates to this method.
+ std::vector<const protobufs::DataDescriptor*> GetSynonymsForDataDescriptor(
+ const protobufs::DataDescriptor& data_descriptor,
+ opt::IRContext* context) const;
- // The set of keys to the above map; useful if you just want to know which ids
- // have synonyms.
- std::set<uint32_t> ids_with_synonyms;
+ // See method in FactManager which delegates to this method.
+ std::vector<uint32_t> GetIdsForWhichSynonymsAreKnown(
+ opt::IRContext* context) const;
+
+ // See method in FactManager which delegates to this method.
+ bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1,
+ const protobufs::DataDescriptor& data_descriptor2,
+ opt::IRContext* context) const;
+
+ private:
+ // Adds |fact| to the set of managed facts, and recurses into sub-components
+ // of the data descriptors referenced in |fact|, if they are composites, to
+ // record that their components are pairwise-synonymous.
+ void AddFactRecursive(const protobufs::FactDataSynonym& fact,
+ opt::IRContext* context);
+
+ // Inspects all known facts and adds corollary facts; e.g. if we know that
+ // a.x == b.x and a.y == b.y, where a and b have vec2 type, we can record
+ // that a == b holds.
+ //
+ // This method is expensive, and is thus called on demand: rather than
+ // computing the closure of facts each time a data synonym fact is added, we
+ // compute the closure only when a data synonym fact is *queried*.
+ void ComputeClosureOfFacts(opt::IRContext* context) const;
+
+ // Returns true if and only if |dd1| and |dd2| are valid data descriptors
+ // whose associated data have the same type.
+ bool DataDescriptorsAreWellFormedAndComparable(
+ opt::IRContext* context, const protobufs::DataDescriptor& dd1,
+ const protobufs::DataDescriptor& dd2) const;
+
+ // The data descriptors that are known to be synonymous with one another are
+ // captured by this equivalence relation.
+ //
+ // This member is mutable in order to allow the closure of facts captured by
+ // the relation to be computed lazily when a question about data synonym
+ // facts is asked.
+ mutable EquivalenceRelation<protobufs::DataDescriptor, DataDescriptorHash,
+ DataDescriptorEquals>
+ synonymous_;
+
+ // When a new synonym fact is added, it may be possible to deduce further
+ // synonym facts by computing a closure of all known facts. However, there is
+ // no point computing this closure until a question regarding synonym facts is
+ // actually asked: if several facts are added in succession with no questions
+ // asked in between, we can avoid computing fact closures multiple times.
+ //
+ // This boolean tracks whether a closure computation is required - i.e.,
+ // whether a new fact has been added since the last time such a computation
+ // was performed.
+ //
+ // It is mutable so faciliate having const methods, that provide answers to
+ // questions about data synonym facts, triggering closure computation on
+ // demand.
+ mutable bool closure_computation_required = false;
};
-void FactManager::IdSynonymFacts::AddFact(
- const protobufs::FactIdSynonym& fact) {
- if (synonyms.count(fact.id()) == 0) {
- assert(ids_with_synonyms.count(fact.id()) == 0);
- ids_with_synonyms.insert(fact.id());
- synonyms[fact.id()] = std::vector<protobufs::DataDescriptor>();
- }
- assert(ids_with_synonyms.count(fact.id()) == 1);
- synonyms[fact.id()].push_back(fact.data_descriptor());
+void FactManager::DataSynonymFacts::AddFact(
+ const protobufs::FactDataSynonym& fact, opt::IRContext* context) {
+ // Add the fact, including all facts relating sub-components of the data
+ // descriptors that are involved.
+ AddFactRecursive(fact, context);
}
-// End of id synonym facts
+void FactManager::DataSynonymFacts::AddFactRecursive(
+ const protobufs::FactDataSynonym& fact, opt::IRContext* context) {
+ assert(DataDescriptorsAreWellFormedAndComparable(context, fact.data1(),
+ fact.data2()));
+
+ // Record that the data descriptors provided in the fact are equivalent.
+ synonymous_.MakeEquivalent(fact.data1(), fact.data2());
+ // As we have updated the equivalence relation, we might be able to deduce
+ // more facts by performing a closure computation, so we record that such a
+ // computation is required; it will be performed next time a method answering
+ // a data synonym fact-related question is invoked.
+ closure_computation_required = true;
+
+ // We now check whether this is a synonym about composite objects. If it is,
+ // we can recursively add synonym facts about their associated sub-components.
+
+ // Get the type of the object referred to by the first data descriptor in the
+ // synonym fact.
+ uint32_t type_id = fuzzerutil::WalkCompositeTypeIndices(
+ context,
+ context->get_def_use_mgr()->GetDef(fact.data1().object())->type_id(),
+ fact.data1().index());
+ auto type = context->get_type_mgr()->GetType(type_id);
+ auto type_instruction = context->get_def_use_mgr()->GetDef(type_id);
+ assert(type != nullptr &&
+ "Invalid data synonym fact: one side has an unknown type.");
+
+ // Check whether the type is composite, recording the number of elements
+ // associated with the composite if so.
+ uint32_t num_composite_elements;
+ if (type->AsArray()) {
+ num_composite_elements =
+ fuzzerutil::GetArraySize(*type_instruction, context);
+ } else if (type->AsMatrix()) {
+ num_composite_elements = type->AsMatrix()->element_count();
+ } else if (type->AsStruct()) {
+ num_composite_elements =
+ fuzzerutil::GetNumberOfStructMembers(*type_instruction);
+ } else if (type->AsVector()) {
+ num_composite_elements = type->AsVector()->element_count();
+ } else {
+ // The type is not a composite, so return.
+ return;
+ }
+
+ // If the fact has the form:
+ // obj_1[a_1, ..., a_m] == obj_2[b_1, ..., b_n]
+ // then for each composite index i, we add a fact of the form:
+ // obj_1[a_1, ..., a_m, i] == obj_2[b_1, ..., b_n, i]
+ for (uint32_t i = 0; i < num_composite_elements; i++) {
+ std::vector<uint32_t> extended_indices1 =
+ fuzzerutil::RepeatedFieldToVector(fact.data1().index());
+ extended_indices1.push_back(i);
+ std::vector<uint32_t> extended_indices2 =
+ fuzzerutil::RepeatedFieldToVector(fact.data2().index());
+ extended_indices2.push_back(i);
+ protobufs::FactDataSynonym extended_data_synonym_fact;
+ *extended_data_synonym_fact.mutable_data1() =
+ MakeDataDescriptor(fact.data1().object(), std::move(extended_indices1));
+ *extended_data_synonym_fact.mutable_data2() =
+ MakeDataDescriptor(fact.data2().object(), std::move(extended_indices2));
+ AddFactRecursive(extended_data_synonym_fact, context);
+ }
+}
+
+void FactManager::DataSynonymFacts::ComputeClosureOfFacts(
+ opt::IRContext* context) const {
+ // Suppose that obj_1[a_1, ..., a_m] and obj_2[b_1, ..., b_n] are distinct
+ // data descriptors that describe objects of the same composite type, and that
+ // the composite type is comprised of k components.
+ //
+ // For example, if m is a mat4x4 and v a vec4, we might consider:
+ // m[2]: describes the 2nd column of m, a vec4
+ // v[]: describes all of v, a vec4
+ //
+ // Suppose that we know, for every 0 <= i < k, that the fact:
+ // obj_1[a_1, ..., a_m, i] == obj_2[b_1, ..., b_n, i]
+ // holds - i.e. that the children of the two data descriptors are synonymous.
+ //
+ // Then we can conclude that:
+ // obj_1[a_1, ..., a_m] == obj_2[b_1, ..., b_n]
+ // holds.
+ //
+ // For instance, if we have the facts:
+ // m[2, 0] == v[0]
+ // m[2, 1] == v[1]
+ // m[2, 2] == v[2]
+ // m[2, 3] == v[3]
+ // then we can conclude that:
+ // m[2] == v.
+ //
+ // This method repeatedly searches the equivalence relation of data
+ // descriptors, deducing and adding such facts, until a pass over the
+ // relation leads to no further facts being deduced.
+
+ // The method relies on working with pairs of data descriptors, and in
+ // particular being able to hash and compare such pairs.
+
+ using DataDescriptorPair =
+ std::pair<protobufs::DataDescriptor, protobufs::DataDescriptor>;
+
+ struct DataDescriptorPairHash {
+ std::size_t operator()(const DataDescriptorPair& pair) const {
+ return DataDescriptorHash()(&pair.first) ^
+ DataDescriptorHash()(&pair.second);
+ }
+ };
+
+ struct DataDescriptorPairEquals {
+ bool operator()(const DataDescriptorPair& first,
+ const DataDescriptorPair& second) const {
+ return DataDescriptorEquals()(&first.first, &second.first) &&
+ DataDescriptorEquals()(&first.second, &second.second);
+ }
+ };
+
+ // This map records, for a given pair of composite data descriptors of the
+ // same type, all the indices at which the data descriptors are known to be
+ // synonymous. A pair is a key to this map only if we have observed that
+ // the pair are synonymous at *some* index, but not at *all* indices.
+ // Once we find that a pair of data descriptors are equivalent at all indices
+ // we record the fact that they are synonymous and remove them from the map.
+ //
+ // Using the m and v example from above, initially the pair (m[2], v) would
+ // not be a key to the map. If we find that m[2, 2] == v[2] holds, we would
+ // add an entry:
+ // (m[2], v) -> [false, false, true, false]
+ // to record that they are synonymous at index 2. If we then find that
+ // m[2, 0] == v[0] holds, we would update this entry to:
+ // (m[2], v) -> [true, false, true, false]
+ // If we then find that m[2, 3] == v[3] holds, we would update this entry to:
+ // (m[2], v) -> [true, false, true, true]
+ // Finally, if we then find that m[2, 1] == v[1] holds, which would make the
+ // boolean vector true at every index, we would add the fact:
+ // m[2] == v
+ // to the equivalence relation and remove (m[2], v) from the map.
+ std::unordered_map<DataDescriptorPair, std::vector<bool>,
+ DataDescriptorPairHash, DataDescriptorPairEquals>
+ candidate_composite_synonyms;
+
+ // We keep looking for new facts until we perform a complete pass over the
+ // equivalence relation without finding any new facts.
+ while (closure_computation_required) {
+ // We have not found any new facts yet during this pass; we set this to
+ // 'true' if we do find a new fact.
+ closure_computation_required = false;
+
+ // Consider each class in the equivalence relation.
+ for (auto representative :
+ synonymous_.GetEquivalenceClassRepresentatives()) {
+ auto equivalence_class = synonymous_.GetEquivalenceClass(*representative);
+
+ // Consider every data descriptor in the equivalence class.
+ for (auto dd1_it = equivalence_class.begin();
+ dd1_it != equivalence_class.end(); ++dd1_it) {
+ // If this data descriptor has no indices then it does not have the form
+ // obj_1[a_1, ..., a_m, i], so move on.
+ auto dd1 = *dd1_it;
+ if (dd1->index_size() == 0) {
+ continue;
+ }
+
+ // Consider every other data descriptor later in the equivalence class
+ // (due to symmetry, there is no need to compare with previous data
+ // descriptors).
+ auto dd2_it = dd1_it;
+ for (++dd2_it; dd2_it != equivalence_class.end(); ++dd2_it) {
+ auto dd2 = *dd2_it;
+ // If this data descriptor has no indices then it does not have the
+ // form obj_2[b_1, ..., b_n, i], so move on.
+ if (dd2->index_size() == 0) {
+ continue;
+ }
+
+ // At this point we know that:
+ // - |dd1| has the form obj_1[a_1, ..., a_m, i]
+ // - |dd2| has the form obj_2[b_1, ..., b_n, j]
+ assert(dd1->index_size() > 0 && dd2->index_size() > 0 &&
+ "Control should not reach here if either data descriptor has "
+ "no indices.");
+
+ // We are only interested if i == j.
+ if (dd1->index(dd1->index_size() - 1) !=
+ dd2->index(dd2->index_size() - 1)) {
+ continue;
+ }
+
+ const uint32_t common_final_index = dd1->index(dd1->index_size() - 1);
+
+ // Make data descriptors |dd1_prefix| and |dd2_prefix| for
+ // obj_1[a_1, ..., a_m]
+ // and
+ // obj_2[b_1, ..., b_n]
+ // These are the two data descriptors we might be getting closer to
+ // deducing as being synonymous, due to knowing that they are
+ // synonymous when extended by a particular index.
+ protobufs::DataDescriptor dd1_prefix;
+ dd1_prefix.set_object(dd1->object());
+ for (uint32_t i = 0; i < static_cast<uint32_t>(dd1->index_size() - 1);
+ i++) {
+ dd1_prefix.add_index(dd1->index(i));
+ }
+ protobufs::DataDescriptor dd2_prefix;
+ dd2_prefix.set_object(dd2->object());
+ for (uint32_t i = 0; i < static_cast<uint32_t>(dd2->index_size() - 1);
+ i++) {
+ dd2_prefix.add_index(dd2->index(i));
+ }
+ assert(!DataDescriptorEquals()(&dd1_prefix, &dd2_prefix) &&
+ "By construction these prefixes should be different.");
+
+ // If we already know that these prefixes are synonymous, move on.
+ if (synonymous_.Exists(dd1_prefix) &&
+ synonymous_.Exists(dd2_prefix) &&
+ synonymous_.IsEquivalent(dd1_prefix, dd2_prefix)) {
+ continue;
+ }
+
+ // Get the type of obj_1
+ auto dd1_root_type_id =
+ context->get_def_use_mgr()->GetDef(dd1->object())->type_id();
+ // Use this type, together with a_1, ..., a_m, to get the type of
+ // obj_1[a_1, ..., a_m].
+ auto dd1_prefix_type = fuzzerutil::WalkCompositeTypeIndices(
+ context, dd1_root_type_id, dd1_prefix.index());
+
+ // Similarly, get the type of obj_2 and use it to get the type of
+ // obj_2[b_1, ..., b_n].
+ auto dd2_root_type_id =
+ context->get_def_use_mgr()->GetDef(dd2->object())->type_id();
+ auto dd2_prefix_type = fuzzerutil::WalkCompositeTypeIndices(
+ context, dd2_root_type_id, dd2_prefix.index());
+
+ // If the types of dd1_prefix and dd2_prefix are not the same, they
+ // cannot be synonymous.
+ if (dd1_prefix_type != dd2_prefix_type) {
+ continue;
+ }
+
+ // At this point, we know we have synonymous data descriptors of the
+ // form:
+ // obj_1[a_1, ..., a_m, i]
+ // obj_2[b_1, ..., b_n, i]
+ // with the same last_index i, such that:
+ // obj_1[a_1, ..., a_m]
+ // and
+ // obj_2[b_1, ..., b_n]
+ // have the same type.
+
+ // Work out how many components there are in the (common) commposite
+ // type associated with obj_1[a_1, ..., a_m] and obj_2[b_1, ..., b_n].
+ // This depends on whether the composite type is array, matrix, struct
+ // or vector.
+ uint32_t num_components_in_composite;
+ auto composite_type =
+ context->get_type_mgr()->GetType(dd1_prefix_type);
+ auto composite_type_instruction =
+ context->get_def_use_mgr()->GetDef(dd1_prefix_type);
+ if (composite_type->AsArray()) {
+ num_components_in_composite =
+ fuzzerutil::GetArraySize(*composite_type_instruction, context);
+ if (num_components_in_composite == 0) {
+ // This indicates that the array has an unknown size, in which
+ // case we cannot be sure we have matched all of its elements with
+ // synonymous elements of another array.
+ continue;
+ }
+ } else if (composite_type->AsMatrix()) {
+ num_components_in_composite =
+ composite_type->AsMatrix()->element_count();
+ } else if (composite_type->AsStruct()) {
+ num_components_in_composite = fuzzerutil::GetNumberOfStructMembers(
+ *composite_type_instruction);
+ } else {
+ assert(composite_type->AsVector());
+ num_components_in_composite =
+ composite_type->AsVector()->element_count();
+ }
+
+ // We are one step closer to being able to say that |dd1_prefix| and
+ // |dd2_prefix| are synonymous.
+ DataDescriptorPair candidate_composite_synonym(dd1_prefix,
+ dd2_prefix);
+
+ // We look up what we already know about this pair.
+ auto existing_entry =
+ candidate_composite_synonyms.find(candidate_composite_synonym);
+
+ if (existing_entry == candidate_composite_synonyms.end()) {
+ // If this is the first time we have seen the pair, we make a vector
+ // of size |num_components_in_composite| that is 'true' at the
+ // common final index associated with |dd1| and |dd2|, and 'false'
+ // everywhere else, and register this vector as being associated
+ // with the pair.
+ std::vector<bool> entry;
+ for (uint32_t i = 0; i < num_components_in_composite; i++) {
+ entry.push_back(i == common_final_index);
+ }
+ candidate_composite_synonyms[candidate_composite_synonym] = entry;
+ existing_entry =
+ candidate_composite_synonyms.find(candidate_composite_synonym);
+ } else {
+ // We have seen this pair of data descriptors before, and we now
+ // know that they are synonymous at one further index, so we
+ // update the entry to record that.
+ existing_entry->second[common_final_index] = true;
+ }
+ assert(existing_entry != candidate_composite_synonyms.end());
+
+ // Check whether |dd1_prefix| and |dd2_prefix| are now known to match
+ // at every sub-component.
+ bool all_components_match = true;
+ for (uint32_t i = 0; i < num_components_in_composite; i++) {
+ if (!existing_entry->second[i]) {
+ all_components_match = false;
+ break;
+ }
+ }
+ if (all_components_match) {
+ // The two prefixes match on all sub-components, so we know that
+ // they are synonymous. We add this fact *non-recursively*, as we
+ // have deduced that |dd1_prefix| and |dd2_prefix| are synonymous
+ // by observing that all their sub-components are already
+ // synonymous.
+ assert(DataDescriptorsAreWellFormedAndComparable(
+ context, dd1_prefix, dd2_prefix));
+ synonymous_.MakeEquivalent(dd1_prefix, dd2_prefix);
+ // As we have added a new synonym fact, we might benefit from doing
+ // another pass over the equivalence relation.
+ closure_computation_required = true;
+ // Now that we know this pair of data descriptors are synonymous,
+ // there is no point recording how close they are to being
+ // synonymous.
+ candidate_composite_synonyms.erase(candidate_composite_synonym);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool FactManager::DataSynonymFacts::DataDescriptorsAreWellFormedAndComparable(
+ opt::IRContext* context, const protobufs::DataDescriptor& dd1,
+ const protobufs::DataDescriptor& dd2) const {
+ auto end_type_1 = fuzzerutil::WalkCompositeTypeIndices(
+ context, context->get_def_use_mgr()->GetDef(dd1.object())->type_id(),
+ dd1.index());
+ auto end_type_2 = fuzzerutil::WalkCompositeTypeIndices(
+ context, context->get_def_use_mgr()->GetDef(dd2.object())->type_id(),
+ dd2.index());
+ return end_type_1 && end_type_1 == end_type_2;
+}
+
+std::vector<const protobufs::DataDescriptor*>
+FactManager::DataSynonymFacts::GetSynonymsForDataDescriptor(
+ const protobufs::DataDescriptor& data_descriptor,
+ opt::IRContext* context) const {
+ ComputeClosureOfFacts(context);
+ if (synonymous_.Exists(data_descriptor)) {
+ return synonymous_.GetEquivalenceClass(data_descriptor);
+ }
+ return std::vector<const protobufs::DataDescriptor*>();
+}
+
+std::vector<uint32_t>
+FactManager::DataSynonymFacts ::GetIdsForWhichSynonymsAreKnown(
+ opt::IRContext* context) const {
+ ComputeClosureOfFacts(context);
+ std::vector<uint32_t> result;
+ for (auto& data_descriptor : synonymous_.GetAllKnownValues()) {
+ if (data_descriptor->index().empty()) {
+ result.push_back(data_descriptor->object());
+ }
+ }
+ return result;
+}
+
+bool FactManager::DataSynonymFacts::IsSynonymous(
+ const protobufs::DataDescriptor& data_descriptor1,
+ const protobufs::DataDescriptor& data_descriptor2,
+ opt::IRContext* context) const {
+ const_cast<FactManager::DataSynonymFacts*>(this)->ComputeClosureOfFacts(
+ context);
+ return synonymous_.Exists(data_descriptor1) &&
+ synonymous_.Exists(data_descriptor2) &&
+ synonymous_.IsEquivalent(data_descriptor1, data_descriptor2);
+}
+
+// End of data synonym facts
//==============================
FactManager::FactManager()
: uniform_constant_facts_(MakeUnique<ConstantUniformFacts>()),
- id_synonym_facts_(MakeUnique<IdSynonymFacts>()) {}
+ data_synonym_facts_(MakeUnique<DataSynonymFacts>()) {}
FactManager::~FactManager() = default;
@@ -385,14 +818,14 @@
}
}
-bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact& fact,
- spvtools::opt::IRContext* context) {
+bool FactManager::AddFact(const fuzz::protobufs::Fact& fact,
+ opt::IRContext* context) {
switch (fact.fact_case()) {
case protobufs::Fact::kConstantUniformFact:
return uniform_constant_facts_->AddFact(fact.constant_uniform_fact(),
context);
- case protobufs::Fact::kIdSynonymFact:
- id_synonym_facts_->AddFact(fact.id_synonym_fact());
+ case protobufs::Fact::kDataSynonymFact:
+ data_synonym_facts_->AddFact(fact.data_synonym_fact(), context);
return true;
default:
assert(false && "Unknown fact type.");
@@ -400,6 +833,15 @@
}
}
+void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1,
+ const protobufs::DataDescriptor& data2,
+ opt::IRContext* context) {
+ protobufs::FactDataSynonym fact;
+ *fact.mutable_data1() = data1;
+ *fact.mutable_data2() = data2;
+ data_synonym_facts_->AddFact(fact, context);
+}
+
std::vector<uint32_t> FactManager::GetConstantsAvailableFromUniformsForType(
opt::IRContext* ir_context, uint32_t type_id) const {
return uniform_constant_facts_->GetConstantsAvailableFromUniformsForType(
@@ -427,16 +869,33 @@
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
FactManager::GetConstantUniformFactsAndTypes() const {
- return uniform_constant_facts_->facts_and_type_ids;
+ return uniform_constant_facts_->GetConstantUniformFactsAndTypes();
}
-const std::set<uint32_t>& FactManager::GetIdsForWhichSynonymsAreKnown() const {
- return id_synonym_facts_->ids_with_synonyms;
+std::vector<uint32_t> FactManager::GetIdsForWhichSynonymsAreKnown(
+ opt::IRContext* context) const {
+ return data_synonym_facts_->GetIdsForWhichSynonymsAreKnown(context);
}
-const std::vector<protobufs::DataDescriptor>& FactManager::GetSynonymsForId(
- uint32_t id) const {
- return id_synonym_facts_->synonyms.at(id);
+std::vector<const protobufs::DataDescriptor*>
+FactManager::GetSynonymsForDataDescriptor(
+ const protobufs::DataDescriptor& data_descriptor,
+ opt::IRContext* context) const {
+ return data_synonym_facts_->GetSynonymsForDataDescriptor(data_descriptor,
+ context);
+}
+
+std::vector<const protobufs::DataDescriptor*> FactManager::GetSynonymsForId(
+ uint32_t id, opt::IRContext* context) const {
+ return GetSynonymsForDataDescriptor(MakeDataDescriptor(id, {}), context);
+}
+
+bool FactManager::IsSynonymous(
+ const protobufs::DataDescriptor& data_descriptor1,
+ const protobufs::DataDescriptor& data_descriptor2,
+ opt::IRContext* context) const {
+ return data_synonym_facts_->IsSynonymous(data_descriptor1, data_descriptor2,
+ context);
}
} // namespace fuzz
diff --git a/source/fuzz/fact_manager.h b/source/fuzz/fact_manager.h
index f6ea247..62d9dac 100644
--- a/source/fuzz/fact_manager.h
+++ b/source/fuzz/fact_manager.h
@@ -20,6 +20,7 @@
#include <utility>
#include <vector>
+#include "source/fuzz/data_descriptor.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/opt/constants.h"
@@ -52,6 +53,11 @@
// fact manager.
bool AddFact(const protobufs::Fact& fact, opt::IRContext* context);
+ // Record the fact that |data1| and |data2| are synonymous.
+ void AddFactDataSynonym(const protobufs::DataDescriptor& data1,
+ const protobufs::DataDescriptor& data2,
+ opt::IRContext* context);
+
// The fact manager is responsible for managing a few distinct categories of
// facts. In principle there could be different fact managers for each kind
// of fact, but in practice providing one 'go to' place for facts is
@@ -99,33 +105,46 @@
//==============================
// Querying facts about id synonyms
- // Returns every id for which a fact of the form "this id is synonymous
- // with this piece of data" is known.
- const std::set<uint32_t>& GetIdsForWhichSynonymsAreKnown() const;
+ // Returns every id for which a fact of the form "this id is synonymous with
+ // this piece of data" is known.
+ std::vector<uint32_t> GetIdsForWhichSynonymsAreKnown(
+ opt::IRContext* context) const;
- // Requires that at least one synonym for |id| is known, and returns the
- // sequence of all known synonyms.
- const std::vector<protobufs::DataDescriptor>& GetSynonymsForId(
- uint32_t id) const;
+ // Returns the equivalence class of all known synonyms of |id|, or an empty
+ // set if no synonyms are known.
+ std::vector<const protobufs::DataDescriptor*> GetSynonymsForId(
+ uint32_t id, opt::IRContext* context) const;
+
+ // Returns the equivalence class of all known synonyms of |data_descriptor|,
+ // or empty if no synonyms are known.
+ std::vector<const protobufs::DataDescriptor*> GetSynonymsForDataDescriptor(
+ const protobufs::DataDescriptor& data_descriptor,
+ opt::IRContext* context) const;
+
+ // Returns true if and ony if |data_descriptor1| and |data_descriptor2| are
+ // known to be synonymous.
+ bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1,
+ const protobufs::DataDescriptor& data_descriptor2,
+ opt::IRContext* context) const;
// End of id synonym facts
//==============================
private:
// For each distinct kind of fact to be managed, we use a separate opaque
- // struct type.
+ // class type.
- struct ConstantUniformFacts; // Opaque struct for holding data about uniform
- // buffer elements.
+ class ConstantUniformFacts; // Opaque class for management of
+ // constant uniform facts.
std::unique_ptr<ConstantUniformFacts>
uniform_constant_facts_; // Unique pointer to internal data.
- struct IdSynonymFacts; // Opaque struct for holding data about id synonyms.
- std::unique_ptr<IdSynonymFacts>
- id_synonym_facts_; // Unique pointer to internal data.
+ class DataSynonymFacts; // Opaque class for management of data synonym facts.
+ std::unique_ptr<DataSynonymFacts>
+ data_synonym_facts_; // Unique pointer to internal data.
};
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_FACT_MANAGER_H_
+#endif // SOURCE_FUZZ_FACT_MANAGER_H_
diff --git a/source/fuzz/force_render_red.cpp b/source/fuzz/force_render_red.cpp
new file mode 100644
index 0000000..46e23e8
--- /dev/null
+++ b/source/fuzz/force_render_red.cpp
@@ -0,0 +1,370 @@
+// 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/fuzz/force_render_red.h"
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation_replace_constant_with_uniform.h"
+#include "source/fuzz/uniform_buffer_element_descriptor.h"
+#include "source/opt/build_module.h"
+#include "source/opt/ir_context.h"
+#include "source/opt/types.h"
+#include "source/util/make_unique.h"
+#include "tools/util/cli_consumer.h"
+
+#include <algorithm>
+#include <utility>
+
+namespace spvtools {
+namespace fuzz {
+
+namespace {
+
+// Helper method to find the fragment shader entry point, complaining if there
+// is no shader or if there is no fragment entry point.
+opt::Function* FindFragmentShaderEntryPoint(opt::IRContext* ir_context,
+ MessageConsumer message_consumer) {
+ // Check that this is a fragment shader
+ bool found_capability_shader = false;
+ for (auto& capability : ir_context->capabilities()) {
+ assert(capability.opcode() == SpvOpCapability);
+ if (capability.GetSingleWordInOperand(0) == SpvCapabilityShader) {
+ found_capability_shader = true;
+ break;
+ }
+ }
+ if (!found_capability_shader) {
+ message_consumer(
+ SPV_MSG_ERROR, nullptr, {},
+ "Forcing of red rendering requires the Shader capability.");
+ return nullptr;
+ }
+
+ opt::Instruction* fragment_entry_point = nullptr;
+ for (auto& entry_point : ir_context->module()->entry_points()) {
+ if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelFragment) {
+ fragment_entry_point = &entry_point;
+ break;
+ }
+ }
+ if (fragment_entry_point == nullptr) {
+ message_consumer(SPV_MSG_ERROR, nullptr, {},
+ "Forcing of red rendering requires an entry point with "
+ "the Fragment execution model.");
+ return nullptr;
+ }
+
+ for (auto& function : *ir_context->module()) {
+ if (function.result_id() ==
+ fragment_entry_point->GetSingleWordInOperand(1)) {
+ return &function;
+ }
+ }
+ assert(
+ false &&
+ "A valid module must have a function associate with each entry point.");
+ return nullptr;
+}
+
+// Helper method to check that there is a single vec4 output variable and get a
+// pointer to it.
+opt::Instruction* FindVec4OutputVariable(opt::IRContext* ir_context,
+ MessageConsumer message_consumer) {
+ opt::Instruction* output_variable = nullptr;
+ for (auto& inst : ir_context->types_values()) {
+ if (inst.opcode() == SpvOpVariable &&
+ inst.GetSingleWordInOperand(0) == SpvStorageClassOutput) {
+ if (output_variable != nullptr) {
+ message_consumer(SPV_MSG_ERROR, nullptr, {},
+ "Only one output variable can be handled at present; "
+ "found multiple.");
+ return nullptr;
+ }
+ output_variable = &inst;
+ // Do not break, as we want to check for multiple output variables.
+ }
+ }
+ if (output_variable == nullptr) {
+ message_consumer(SPV_MSG_ERROR, nullptr, {},
+ "No output variable to which to write red was found.");
+ return nullptr;
+ }
+
+ auto output_variable_base_type = ir_context->get_type_mgr()
+ ->GetType(output_variable->type_id())
+ ->AsPointer()
+ ->pointee_type()
+ ->AsVector();
+ if (!output_variable_base_type ||
+ output_variable_base_type->element_count() != 4 ||
+ !output_variable_base_type->element_type()->AsFloat()) {
+ message_consumer(SPV_MSG_ERROR, nullptr, {},
+ "The output variable must have type vec4.");
+ return nullptr;
+ }
+
+ return output_variable;
+}
+
+// Helper to get the ids of float constants 0.0 and 1.0, creating them if
+// necessary.
+std::pair<uint32_t, uint32_t> FindOrCreateFloatZeroAndOne(
+ opt::IRContext* ir_context, opt::analysis::Float* float_type) {
+ float one = 1.0;
+ uint32_t one_as_uint;
+ memcpy(&one_as_uint, &one, sizeof(float));
+ std::vector<uint32_t> zero_bytes = {0};
+ std::vector<uint32_t> one_bytes = {one_as_uint};
+ auto constant_zero = ir_context->get_constant_mgr()->RegisterConstant(
+ MakeUnique<opt::analysis::FloatConstant>(float_type, zero_bytes));
+ auto constant_one = ir_context->get_constant_mgr()->RegisterConstant(
+ MakeUnique<opt::analysis::FloatConstant>(float_type, one_bytes));
+ auto constant_zero_id = ir_context->get_constant_mgr()
+ ->GetDefiningInstruction(constant_zero)
+ ->result_id();
+ auto constant_one_id = ir_context->get_constant_mgr()
+ ->GetDefiningInstruction(constant_one)
+ ->result_id();
+ return std::pair<uint32_t, uint32_t>(constant_zero_id, constant_one_id);
+}
+
+std::unique_ptr<TransformationReplaceConstantWithUniform>
+MakeConstantUniformReplacement(opt::IRContext* ir_context,
+ const FactManager& fact_manager,
+ uint32_t constant_id,
+ uint32_t greater_than_instruction,
+ uint32_t in_operand_index) {
+ return MakeUnique<TransformationReplaceConstantWithUniform>(
+ MakeIdUseDescriptor(constant_id,
+ MakeInstructionDescriptor(greater_than_instruction,
+ SpvOpFOrdGreaterThan, 0),
+ in_operand_index),
+ fact_manager.GetUniformDescriptorsForConstant(ir_context, constant_id)[0],
+ ir_context->TakeNextId(), ir_context->TakeNextId());
+}
+
+} // namespace
+
+bool ForceRenderRed(
+ const spv_target_env& target_env, const std::vector<uint32_t>& binary_in,
+ const spvtools::fuzz::protobufs::FactSequence& initial_facts,
+ std::vector<uint32_t>* binary_out) {
+ auto message_consumer = spvtools::utils::CLIMessageConsumer;
+ spvtools::SpirvTools tools(target_env);
+ if (!tools.IsValid()) {
+ message_consumer(SPV_MSG_ERROR, nullptr, {},
+ "Failed to create SPIRV-Tools interface; stopping.");
+ return false;
+ }
+
+ // Initial binary should be valid.
+ if (!tools.Validate(&binary_in[0], binary_in.size())) {
+ message_consumer(SPV_MSG_ERROR, nullptr, {},
+ "Initial binary is invalid; stopping.");
+ return false;
+ }
+
+ // Build the module from the input binary.
+ std::unique_ptr<opt::IRContext> ir_context = BuildModule(
+ target_env, message_consumer, binary_in.data(), binary_in.size());
+ assert(ir_context);
+
+ // Set up a fact manager with any given initial facts.
+ FactManager fact_manager;
+ for (auto& fact : initial_facts.fact()) {
+ fact_manager.AddFact(fact, ir_context.get());
+ }
+
+ auto entry_point_function =
+ FindFragmentShaderEntryPoint(ir_context.get(), message_consumer);
+ auto output_variable =
+ FindVec4OutputVariable(ir_context.get(), message_consumer);
+ if (entry_point_function == nullptr || output_variable == nullptr) {
+ return false;
+ }
+
+ opt::analysis::Float temp_float_type(32);
+ opt::analysis::Float* float_type = ir_context->get_type_mgr()
+ ->GetRegisteredType(&temp_float_type)
+ ->AsFloat();
+ std::pair<uint32_t, uint32_t> zero_one_float_ids =
+ FindOrCreateFloatZeroAndOne(ir_context.get(), float_type);
+
+ // Make the new exit block
+ auto new_exit_block_id = ir_context->TakeNextId();
+ {
+ auto label = MakeUnique<opt::Instruction>(ir_context.get(), SpvOpLabel, 0,
+ new_exit_block_id,
+ opt::Instruction::OperandList());
+ auto new_exit_block = MakeUnique<opt::BasicBlock>(std::move(label));
+ new_exit_block->AddInstruction(MakeUnique<opt::Instruction>(
+ ir_context.get(), SpvOpReturn, 0, 0, opt::Instruction::OperandList()));
+ entry_point_function->AddBasicBlock(std::move(new_exit_block));
+ }
+
+ // Make the new entry block
+ {
+ auto label = MakeUnique<opt::Instruction>(ir_context.get(), SpvOpLabel, 0,
+ ir_context->TakeNextId(),
+ opt::Instruction::OperandList());
+ auto new_entry_block = MakeUnique<opt::BasicBlock>(std::move(label));
+
+ // Make an instruction to construct vec4(1.0, 0.0, 0.0, 1.0), representing
+ // the colour red.
+ opt::Operand zero_float = {SPV_OPERAND_TYPE_ID, {zero_one_float_ids.first}};
+ opt::Operand one_float = {SPV_OPERAND_TYPE_ID, {zero_one_float_ids.second}};
+ opt::Instruction::OperandList op_composite_construct_operands = {
+ one_float, zero_float, zero_float, one_float};
+ auto temp_vec4 = opt::analysis::Vector(float_type, 4);
+ auto vec4_id = ir_context->get_type_mgr()->GetId(&temp_vec4);
+ auto red = MakeUnique<opt::Instruction>(
+ ir_context.get(), SpvOpCompositeConstruct, vec4_id,
+ ir_context->TakeNextId(), op_composite_construct_operands);
+ auto red_id = red->result_id();
+ new_entry_block->AddInstruction(std::move(red));
+
+ // Make an instruction to store red into the output color.
+ opt::Operand variable_to_store_into = {SPV_OPERAND_TYPE_ID,
+ {output_variable->result_id()}};
+ opt::Operand value_to_be_stored = {SPV_OPERAND_TYPE_ID, {red_id}};
+ opt::Instruction::OperandList op_store_operands = {variable_to_store_into,
+ value_to_be_stored};
+ new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
+ ir_context.get(), SpvOpStore, 0, 0, op_store_operands));
+
+ // We are going to attempt to construct 'false' as an expression of the form
+ // 'literal1 > literal2'. If we succeed, we will later replace each literal
+ // with a uniform of the same value - we can only do that replacement once
+ // we have added the entry block to the module.
+ std::unique_ptr<TransformationReplaceConstantWithUniform>
+ first_greater_then_operand_replacement = nullptr;
+ std::unique_ptr<TransformationReplaceConstantWithUniform>
+ second_greater_then_operand_replacement = nullptr;
+ uint32_t id_guaranteed_to_be_false = 0;
+
+ opt::analysis::Bool temp_bool_type;
+ opt::analysis::Bool* registered_bool_type =
+ ir_context->get_type_mgr()
+ ->GetRegisteredType(&temp_bool_type)
+ ->AsBool();
+
+ auto float_type_id = ir_context->get_type_mgr()->GetId(float_type);
+ auto types_for_which_uniforms_are_known =
+ fact_manager.GetTypesForWhichUniformValuesAreKnown();
+
+ // Check whether we have any float uniforms.
+ if (std::find(types_for_which_uniforms_are_known.begin(),
+ types_for_which_uniforms_are_known.end(),
+ float_type_id) != types_for_which_uniforms_are_known.end()) {
+ // We have at least one float uniform; let's see whether we have at least
+ // two.
+ auto available_constants =
+ fact_manager.GetConstantsAvailableFromUniformsForType(
+ ir_context.get(), float_type_id);
+ if (available_constants.size() > 1) {
+ // Grab the float constants associated with the first two known float
+ // uniforms.
+ auto first_constant =
+ ir_context->get_constant_mgr()
+ ->GetConstantFromInst(ir_context->get_def_use_mgr()->GetDef(
+ available_constants[0]))
+ ->AsFloatConstant();
+ auto second_constant =
+ ir_context->get_constant_mgr()
+ ->GetConstantFromInst(ir_context->get_def_use_mgr()->GetDef(
+ available_constants[1]))
+ ->AsFloatConstant();
+
+ // Now work out which of the two constants is larger than the other.
+ uint32_t larger_constant_index = 0;
+ uint32_t smaller_constant_index = 0;
+ if (first_constant->GetFloat() > second_constant->GetFloat()) {
+ larger_constant_index = 0;
+ smaller_constant_index = 1;
+ } else if (first_constant->GetFloat() < second_constant->GetFloat()) {
+ larger_constant_index = 1;
+ smaller_constant_index = 0;
+ }
+
+ // Only proceed with these constants if they have turned out to be
+ // distinct.
+ if (larger_constant_index != smaller_constant_index) {
+ // We are in a position to create 'false' as 'literal1 > literal2', so
+ // reserve an id for this computation; this id will end up being
+ // guaranteed to be 'false'.
+ id_guaranteed_to_be_false = ir_context->TakeNextId();
+
+ auto smaller_constant = available_constants[smaller_constant_index];
+ auto larger_constant = available_constants[larger_constant_index];
+
+ opt::Instruction::OperandList greater_than_operands = {
+ {SPV_OPERAND_TYPE_ID, {smaller_constant}},
+ {SPV_OPERAND_TYPE_ID, {larger_constant}}};
+ new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
+ ir_context.get(), SpvOpFOrdGreaterThan,
+ ir_context->get_type_mgr()->GetId(registered_bool_type),
+ id_guaranteed_to_be_false, greater_than_operands));
+
+ first_greater_then_operand_replacement =
+ MakeConstantUniformReplacement(ir_context.get(), fact_manager,
+ smaller_constant,
+ id_guaranteed_to_be_false, 0);
+ second_greater_then_operand_replacement =
+ MakeConstantUniformReplacement(ir_context.get(), fact_manager,
+ larger_constant,
+ id_guaranteed_to_be_false, 1);
+ }
+ }
+ }
+
+ if (id_guaranteed_to_be_false == 0) {
+ auto constant_false = ir_context->get_constant_mgr()->RegisterConstant(
+ MakeUnique<opt::analysis::BoolConstant>(registered_bool_type, false));
+ id_guaranteed_to_be_false = ir_context->get_constant_mgr()
+ ->GetDefiningInstruction(constant_false)
+ ->result_id();
+ }
+
+ opt::Operand false_condition = {SPV_OPERAND_TYPE_ID,
+ {id_guaranteed_to_be_false}};
+ opt::Operand then_block = {SPV_OPERAND_TYPE_ID,
+ {entry_point_function->entry()->id()}};
+ opt::Operand else_block = {SPV_OPERAND_TYPE_ID, {new_exit_block_id}};
+ opt::Instruction::OperandList op_branch_conditional_operands = {
+ false_condition, then_block, else_block};
+ new_entry_block->AddInstruction(
+ MakeUnique<opt::Instruction>(ir_context.get(), SpvOpBranchConditional,
+ 0, 0, op_branch_conditional_operands));
+
+ entry_point_function->InsertBasicBlockBefore(
+ std::move(new_entry_block), entry_point_function->entry().get());
+
+ for (auto& replacement : {first_greater_then_operand_replacement.get(),
+ second_greater_then_operand_replacement.get()}) {
+ if (replacement) {
+ assert(replacement->IsApplicable(ir_context.get(), fact_manager));
+ replacement->Apply(ir_context.get(), &fact_manager);
+ }
+ }
+ }
+
+ // Write out the module as a binary.
+ ir_context->module()->ToBinary(binary_out, false);
+ return true;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/force_render_red.h b/source/fuzz/force_render_red.h
new file mode 100644
index 0000000..2484d27
--- /dev/null
+++ b/source/fuzz/force_render_red.h
@@ -0,0 +1,48 @@
+// 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_FORCE_RENDER_RED_H_
+#define SOURCE_FORCE_RENDER_RED_H_
+
+#include <vector>
+
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "spirv-tools/libspirv.hpp"
+
+namespace spvtools {
+namespace fuzz {
+
+// Requires |binary_in| to be a valid SPIR-V module with Shader capability,
+// containing an entry point with the Fragment execution model, and a single
+// output variable of type vec4.
+//
+// Turns the body of this entry point into effectively:
+//
+// output_variable = vec4(1.0, 0.0, 0.0, 1.0);
+// if (false) {
+// original_body
+// }
+//
+// If suitable facts about values of uniforms are available, the 'false' will
+// instead become: 'u > v', where 'u' and 'v' are pieces of uniform data for
+// which it is known that 'u < v' holds.
+bool ForceRenderRed(
+ const spv_target_env& target_env, const std::vector<uint32_t>& binary_in,
+ const spvtools::fuzz::protobufs::FactSequence& initial_facts,
+ std::vector<uint32_t>* binary_out);
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FORCE_RENDER_RED_H_
diff --git a/source/fuzz/fuzzer.cpp b/source/fuzz/fuzzer.cpp
index 89250a0..01b4258 100644
--- a/source/fuzz/fuzzer.cpp
+++ b/source/fuzz/fuzzer.cpp
@@ -15,13 +15,22 @@
#include "source/fuzz/fuzzer.h"
#include <cassert>
+#include <memory>
#include <sstream>
+#include "fuzzer_pass_adjust_memory_operands_masks.h"
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/fuzzer_context.h"
#include "source/fuzz/fuzzer_pass_add_dead_breaks.h"
#include "source/fuzz/fuzzer_pass_add_dead_continues.h"
+#include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
+#include "source/fuzz/fuzzer_pass_adjust_function_controls.h"
+#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
+#include "source/fuzz/fuzzer_pass_adjust_selection_controls.h"
+#include "source/fuzz/fuzzer_pass_apply_id_synonyms.h"
+#include "source/fuzz/fuzzer_pass_construct_composites.h"
+#include "source/fuzz/fuzzer_pass_copy_objects.h"
#include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
#include "source/fuzz/fuzzer_pass_permute_blocks.h"
#include "source/fuzz/fuzzer_pass_split_blocks.h"
@@ -36,8 +45,25 @@
namespace {
const uint32_t kIdBoundGap = 100;
+
+const uint32_t kTransformationLimit = 500;
+
+const uint32_t kChanceOfApplyingAnotherPass = 85;
+
+template <typename T>
+void MaybeAddPass(
+ std::vector<std::unique_ptr<FuzzerPass>>* passes,
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformation_sequence_out) {
+ if (fuzzer_context->ChooseEven()) {
+ passes->push_back(MakeUnique<T>(ir_context, fact_manager, fuzzer_context,
+ transformation_sequence_out));
+ }
}
+} // namespace
+
struct Fuzzer::Impl {
explicit Impl(spv_target_env env) : target_env(env) {}
@@ -107,23 +133,69 @@
.Apply();
// Apply some semantics-preserving passes.
- FuzzerPassSplitBlocks(ir_context.get(), &fact_manager, &fuzzer_context,
- transformation_sequence_out)
- .Apply();
- FuzzerPassAddDeadBreaks(ir_context.get(), &fact_manager, &fuzzer_context,
- transformation_sequence_out)
- .Apply();
- FuzzerPassAddDeadContinues(ir_context.get(), &fact_manager, &fuzzer_context,
- transformation_sequence_out)
- .Apply();
- FuzzerPassObfuscateConstants(ir_context.get(), &fact_manager, &fuzzer_context,
- transformation_sequence_out)
- .Apply();
+ std::vector<std::unique_ptr<FuzzerPass>> passes;
+ while (passes.empty()) {
+ MaybeAddPass<FuzzerPassAddDeadBreaks>(&passes, ir_context.get(),
+ &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassAddDeadContinues>(&passes, ir_context.get(),
+ &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassApplyIdSynonyms>(&passes, ir_context.get(),
+ &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassConstructComposites>(&passes, ir_context.get(),
+ &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassCopyObjects>(&passes, ir_context.get(),
+ &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassObfuscateConstants>(&passes, ir_context.get(),
+ &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassPermuteBlocks>(&passes, ir_context.get(),
+ &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassSplitBlocks>(&passes, ir_context.get(),
+ &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ }
- // Finally, give the blocks in the module a good shake-up.
- FuzzerPassPermuteBlocks(ir_context.get(), &fact_manager, &fuzzer_context,
- transformation_sequence_out)
- .Apply();
+ bool is_first = true;
+ while (static_cast<uint32_t>(
+ transformation_sequence_out->transformation_size()) <
+ kTransformationLimit &&
+ (is_first ||
+ fuzzer_context.ChoosePercentage(kChanceOfApplyingAnotherPass))) {
+ is_first = false;
+ passes[fuzzer_context.RandomIndex(passes)]->Apply();
+ }
+
+ // Now apply some passes that it does not make sense to apply repeatedly,
+ // as they do not unlock other passes.
+ std::vector<std::unique_ptr<FuzzerPass>> final_passes;
+ MaybeAddPass<FuzzerPassAdjustFunctionControls>(
+ &final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassAdjustLoopControls>(&final_passes, ir_context.get(),
+ &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassAdjustMemoryOperandsMasks>(
+ &final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ MaybeAddPass<FuzzerPassAdjustSelectionControls>(
+ &final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
+ for (auto& pass : final_passes) {
+ pass->Apply();
+ }
+
+ if (fuzzer_context.ChooseEven()) {
+ FuzzerPassAddNoContractionDecorations(ir_context.get(), &fact_manager,
+ &fuzzer_context,
+ transformation_sequence_out)
+ .Apply();
+ }
// Encode the module as a binary.
ir_context->module()->ToBinary(binary_out, false);
diff --git a/source/fuzz/fuzzer_context.cpp b/source/fuzz/fuzzer_context.cpp
index c8e7719..356cb35 100644
--- a/source/fuzz/fuzzer_context.cpp
+++ b/source/fuzz/fuzzer_context.cpp
@@ -20,15 +20,31 @@
namespace fuzz {
namespace {
-// Default probabilities for applying various transformations.
-// All values are percentages.
-// Keep them in alphabetical order.
+// Default <minimum, maximum> pairs of probabilities for applying various
+// transformations. All values are percentages. Keep them in alphabetical order.
-const uint32_t kDefaultChanceOfAddingDeadBreak = 20;
-const uint32_t kDefaultChanceOfAddingDeadContinue = 20;
-const uint32_t kDefaultChanceOfMovingBlockDown = 25;
-const uint32_t kDefaultChanceOfObfuscatingConstant = 20;
-const uint32_t kDefaultChanceOfSplittingBlock = 20;
+const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadBreak = {5, 80};
+const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadContinue = {5, 80};
+const std::pair<uint32_t, uint32_t> kChanceOfAddingNoContractionDecoration = {
+ 5, 70};
+const std::pair<uint32_t, uint32_t> kChanceOfAdjustingFunctionControl = {20,
+ 70};
+const std::pair<uint32_t, uint32_t> kChanceOfAdjustingLoopControl = {20, 90};
+const std::pair<uint32_t, uint32_t> kChanceOfAdjustingMemoryOperandsMask = {20,
+ 90};
+const std::pair<uint32_t, uint32_t> kChanceOfAdjustingSelectionControl = {20,
+ 90};
+const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
+const std::pair<uint32_t, uint32_t> kChanceOfConstructingComposite = {20, 50};
+const std::pair<uint32_t, uint32_t> kChanceOfMovingBlockDown = {20, 50};
+const std::pair<uint32_t, uint32_t> kChanceOfObfuscatingConstant = {10, 90};
+const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdWithSynonym = {10, 90};
+const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
+
+// Default limits for various quantities that are chosen during fuzzing.
+// Keep them in alphabetical order.
+const uint32_t kDefaultMaxLoopControlPartialCount = 100;
+const uint32_t kDefaultMaxLoopControlPeelCount = 100;
// Default functions for controlling how deep to go during recursive
// generation/transformation. Keep them in alphabetical order.
@@ -46,20 +62,52 @@
uint32_t min_fresh_id)
: random_generator_(random_generator),
next_fresh_id_(min_fresh_id),
- chance_of_adding_dead_break_(kDefaultChanceOfAddingDeadBreak),
- chance_of_adding_dead_continue_(kDefaultChanceOfAddingDeadContinue),
- chance_of_moving_block_down_(kDefaultChanceOfMovingBlockDown),
- chance_of_obfuscating_constant_(kDefaultChanceOfObfuscatingConstant),
- chance_of_splitting_block_(kDefaultChanceOfSplittingBlock),
go_deeper_in_constant_obfuscation_(
- kDefaultGoDeeperInConstantObfuscation) {}
+ kDefaultGoDeeperInConstantObfuscation) {
+ chance_of_adding_dead_break_ =
+ ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak);
+ chance_of_adding_dead_continue_ =
+ ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue);
+ chance_of_adding_no_contraction_decoration_ =
+ ChooseBetweenMinAndMax(kChanceOfAddingNoContractionDecoration);
+ chance_of_adjusting_function_control_ =
+ ChooseBetweenMinAndMax(kChanceOfAdjustingFunctionControl);
+ chance_of_adjusting_loop_control_ =
+ ChooseBetweenMinAndMax(kChanceOfAdjustingLoopControl);
+ chance_of_adjusting_memory_operands_mask_ =
+ ChooseBetweenMinAndMax(kChanceOfAdjustingMemoryOperandsMask);
+ chance_of_adjusting_selection_control_ =
+ ChooseBetweenMinAndMax(kChanceOfAdjustingSelectionControl);
+ chance_of_constructing_composite_ =
+ ChooseBetweenMinAndMax(kChanceOfConstructingComposite);
+ chance_of_copying_object_ = ChooseBetweenMinAndMax(kChanceOfCopyingObject);
+ chance_of_moving_block_down_ =
+ ChooseBetweenMinAndMax(kChanceOfMovingBlockDown);
+ chance_of_obfuscating_constant_ =
+ ChooseBetweenMinAndMax(kChanceOfObfuscatingConstant);
+ chance_of_replacing_id_with_synonym_ =
+ ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym);
+ chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock);
+ max_loop_control_partial_count_ = kDefaultMaxLoopControlPartialCount;
+ max_loop_control_peel_count_ = kDefaultMaxLoopControlPeelCount;
+}
FuzzerContext::~FuzzerContext() = default;
uint32_t FuzzerContext::GetFreshId() { return next_fresh_id_++; }
-RandomGenerator* FuzzerContext::GetRandomGenerator() {
- return random_generator_;
+bool FuzzerContext::ChooseEven() { return random_generator_->RandomBool(); }
+
+bool FuzzerContext::ChoosePercentage(uint32_t percentage_chance) {
+ assert(percentage_chance <= 100);
+ return random_generator_->RandomPercentage() < percentage_chance;
+}
+
+uint32_t FuzzerContext::ChooseBetweenMinAndMax(
+ const std::pair<uint32_t, uint32_t>& min_max) {
+ assert(min_max.first <= min_max.second);
+ return min_max.first +
+ random_generator_->RandomUint32(min_max.second - min_max.first + 1);
}
} // namespace fuzz
diff --git a/source/fuzz/fuzzer_context.h b/source/fuzz/fuzzer_context.h
index 3eaefc7..c8242e6 100644
--- a/source/fuzz/fuzzer_context.h
+++ b/source/fuzz/fuzzer_context.h
@@ -16,6 +16,7 @@
#define SOURCE_FUZZ_FUZZER_CONTEXT_H_
#include <functional>
+#include <utility>
#include "source/fuzz/random_generator.h"
#include "source/opt/function.h"
@@ -34,8 +35,22 @@
~FuzzerContext();
- // Provides the random generator used to control fuzzing.
- RandomGenerator* GetRandomGenerator();
+ // Returns a random boolean.
+ bool ChooseEven();
+
+ // Returns true if and only if a randomly-chosen integer in the range [0, 100]
+ // is less than |percentage_chance|.
+ bool ChoosePercentage(uint32_t percentage_chance);
+
+ // Returns a random index into |sequence|, which is expected to have a 'size'
+ // method, and which must be non-empty. Typically 'HasSizeMethod' will be an
+ // std::vector.
+ template <typename HasSizeMethod>
+ uint32_t RandomIndex(const HasSizeMethod& sequence) {
+ assert(sequence.size() > 0);
+ return random_generator_->RandomUint32(
+ static_cast<uint32_t>(sequence.size()));
+ }
// Yields an id that is guaranteed not to be used in the module being fuzzed,
// or to have been issued before.
@@ -47,17 +62,44 @@
uint32_t GetChanceOfAddingDeadContinue() {
return chance_of_adding_dead_continue_;
}
+ uint32_t GetChanceOfAddingNoContractionDecoration() {
+ return chance_of_adding_no_contraction_decoration_;
+ }
+ uint32_t GetChanceOfAdjustingFunctionControl() {
+ return chance_of_adjusting_function_control_;
+ }
+ uint32_t GetChanceOfAdjustingLoopControl() {
+ return chance_of_adjusting_loop_control_;
+ }
+ uint32_t GetChanceOfAdjustingMemoryOperandsMask() {
+ return chance_of_adjusting_memory_operands_mask_;
+ }
+ uint32_t GetChanceOfAdjustingSelectionControl() {
+ return chance_of_adjusting_selection_control_;
+ }
+ uint32_t GetChanceOfConstructingComposite() {
+ return chance_of_constructing_composite_;
+ }
+ uint32_t GetChanceOfCopyingObject() { return chance_of_copying_object_; }
uint32_t GetChanceOfMovingBlockDown() { return chance_of_moving_block_down_; }
uint32_t GetChanceOfObfuscatingConstant() {
return chance_of_obfuscating_constant_;
}
+ uint32_t GetChanceOfReplacingIdWithSynonym() {
+ return chance_of_replacing_id_with_synonym_;
+ }
uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; }
+ uint32_t GetRandomLoopControlPeelCount() {
+ return random_generator_->RandomUint32(max_loop_control_peel_count_);
+ }
+ uint32_t GetRandomLoopControlPartialCount() {
+ return random_generator_->RandomUint32(max_loop_control_partial_count_);
+ }
- // Probability distributions to control how deeply to recurse.
+ // Functions to control how deeply to recurse.
// Keep them in alphabetical order.
- const std::function<bool(uint32_t, RandomGenerator*)>&
- GoDeeperInConstantObfuscation() {
- return go_deeper_in_constant_obfuscation_;
+ bool GoDeeperInConstantObfuscation(uint32_t depth) {
+ return go_deeper_in_constant_obfuscation_(depth, random_generator_);
}
private:
@@ -70,14 +112,32 @@
// Keep them in alphabetical order.
uint32_t chance_of_adding_dead_break_;
uint32_t chance_of_adding_dead_continue_;
+ uint32_t chance_of_adding_no_contraction_decoration_;
+ uint32_t chance_of_adjusting_function_control_;
+ uint32_t chance_of_adjusting_loop_control_;
+ uint32_t chance_of_adjusting_memory_operands_mask_;
+ uint32_t chance_of_adjusting_selection_control_;
+ uint32_t chance_of_constructing_composite_;
+ uint32_t chance_of_copying_object_;
uint32_t chance_of_moving_block_down_;
uint32_t chance_of_obfuscating_constant_;
+ uint32_t chance_of_replacing_id_with_synonym_;
uint32_t chance_of_splitting_block_;
+ // Limits associated with various quantities for which random values are
+ // chosen during fuzzing.
+ // Keep them in alphabetical order.
+ uint32_t max_loop_control_partial_count_;
+ uint32_t max_loop_control_peel_count_;
+
// Functions to determine with what probability to go deeper when generating
// or mutating constructs recursively.
const std::function<bool(uint32_t, RandomGenerator*)>&
go_deeper_in_constant_obfuscation_;
+
+ // Requires |min_max.first| <= |min_max.second|, and returns a value in the
+ // range [ |min_max.first|, |min_max.second| ]
+ uint32_t ChooseBetweenMinAndMax(const std::pair<uint32_t, uint32_t>& min_max);
};
} // namespace fuzz
diff --git a/source/fuzz/fuzzer_pass.cpp b/source/fuzz/fuzzer_pass.cpp
index 823f2e0..1da53f4 100644
--- a/source/fuzz/fuzzer_pass.cpp
+++ b/source/fuzz/fuzzer_pass.cpp
@@ -14,6 +14,8 @@
#include "source/fuzz/fuzzer_pass.h"
+#include "source/fuzz/instruction_descriptor.h"
+
namespace spvtools {
namespace fuzz {
@@ -27,5 +29,104 @@
FuzzerPass::~FuzzerPass() = default;
+std::vector<opt::Instruction*> FuzzerPass::FindAvailableInstructions(
+ const opt::Function& function, opt::BasicBlock* block,
+ opt::BasicBlock::iterator inst_it,
+ std::function<bool(opt::IRContext*, opt::Instruction*)>
+ instruction_is_relevant) {
+ // TODO(afd) The following is (relatively) simple, but may end up being
+ // prohibitively inefficient, as it walks the whole dominator tree for
+ // every instruction that is considered.
+
+ std::vector<opt::Instruction*> result;
+ // Consider all global declarations
+ for (auto& global : GetIRContext()->module()->types_values()) {
+ if (instruction_is_relevant(GetIRContext(), &global)) {
+ result.push_back(&global);
+ }
+ }
+
+ // Consider all previous instructions in this block
+ for (auto prev_inst_it = block->begin(); prev_inst_it != inst_it;
+ ++prev_inst_it) {
+ if (instruction_is_relevant(GetIRContext(), &*prev_inst_it)) {
+ result.push_back(&*prev_inst_it);
+ }
+ }
+
+ // Walk the dominator tree to consider all instructions from dominating
+ // blocks
+ auto dominator_analysis = GetIRContext()->GetDominatorAnalysis(&function);
+ for (auto next_dominator = dominator_analysis->ImmediateDominator(block);
+ next_dominator != nullptr;
+ next_dominator =
+ dominator_analysis->ImmediateDominator(next_dominator)) {
+ for (auto& dominating_inst : *next_dominator) {
+ if (instruction_is_relevant(GetIRContext(), &dominating_inst)) {
+ result.push_back(&dominating_inst);
+ }
+ }
+ }
+ return result;
+}
+
+void FuzzerPass::MaybeAddTransformationBeforeEachInstruction(
+ std::function<
+ void(const opt::Function& function, opt::BasicBlock* block,
+ opt::BasicBlock::iterator inst_it,
+ const protobufs::InstructionDescriptor& instruction_descriptor)>
+ maybe_apply_transformation) {
+ // Consider every block in every function.
+ for (auto& function : *GetIRContext()->module()) {
+ for (auto& block : function) {
+ // We now consider every instruction in the block, randomly deciding
+ // whether to apply a transformation before it.
+
+ // In order for transformations to insert new instructions, they need to
+ // be able to identify the instruction to insert before. We describe an
+ // instruction via its opcode, 'opc', a base instruction 'base' that has a
+ // result id, and the number of instructions with opcode 'opc' that we
+ // should skip when searching from 'base' for the desired instruction.
+ // (An instruction that has a result id is represented by its own opcode,
+ // itself as 'base', and a skip-count of 0.)
+ std::vector<std::tuple<uint32_t, SpvOp, uint32_t>>
+ base_opcode_skip_triples;
+
+ // The initial base instruction is the block label.
+ uint32_t base = block.id();
+
+ // Counts the number of times we have seen each opcode since we reset the
+ // base instruction.
+ std::map<SpvOp, uint32_t> skip_count;
+
+ // Consider every instruction in the block. The label is excluded: it is
+ // only necessary to consider it as a base in case the first instruction
+ // in the block does not have a result id.
+ for (auto inst_it = block.begin(); inst_it != block.end(); ++inst_it) {
+ if (inst_it->HasResultId()) {
+ // In the case that the instruction has a result id, we use the
+ // instruction as its own base, and clear the skip counts we have
+ // collected.
+ base = inst_it->result_id();
+ skip_count.clear();
+ }
+ const SpvOp opcode = inst_it->opcode();
+
+ // Invoke the provided function, which might apply a transformation.
+ maybe_apply_transformation(
+ function, &block, inst_it,
+ MakeInstructionDescriptor(
+ base, opcode,
+ skip_count.count(opcode) ? skip_count.at(opcode) : 0));
+
+ if (!inst_it->HasResultId()) {
+ skip_count[opcode] =
+ skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1;
+ }
+ }
+ }
+ }
+}
+
} // namespace fuzz
} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass.h b/source/fuzz/fuzzer_pass.h
index 4d0861e..cf56e24 100644
--- a/source/fuzz/fuzzer_pass.h
+++ b/source/fuzz/fuzzer_pass.h
@@ -15,9 +15,13 @@
#ifndef SOURCE_FUZZ_FUZZER_PASS_H_
#define SOURCE_FUZZ_FUZZER_PASS_H_
+#include <functional>
+#include <vector>
+
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/fuzzer_context.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/opt/ir_context.h"
namespace spvtools {
namespace fuzz {
@@ -48,6 +52,43 @@
return transformations_;
}
+ // Returns all instructions that are *available* at |inst_it|, which is
+ // required to be inside block |block| of function |function| - that is, all
+ // instructions at global scope and all instructions that strictly dominate
+ // |inst_it|.
+ //
+ // Filters said instructions to return only those that satisfy the
+ // |instruction_is_relevant| predicate. This, for instance, could ignore all
+ // instructions that have a particular decoration.
+ std::vector<opt::Instruction*> FindAvailableInstructions(
+ const opt::Function& function, opt::BasicBlock* block,
+ opt::BasicBlock::iterator inst_it,
+ std::function<bool(opt::IRContext*, opt::Instruction*)>
+ instruction_is_relevant);
+
+ // A helper method that iterates through each instruction in each block, at
+ // all times tracking an instruction descriptor that allows the latest
+ // instruction to be located even if it has no result id.
+ //
+ // The code to manipulate the instruction descriptor is a bit fiddly, and the
+ // point of this method is to avoiding having to duplicate it in multiple
+ // transformation passes.
+ //
+ // The function |maybe_apply_transformation| is invoked for each instruction
+ // |inst_it| in block |block| of function |function| that is encountered. The
+ // |instruction_descriptor| parameter to the function object allows |inst_it|
+ // to be identified.
+ //
+ // The job of |maybe_apply_transformation| is to randomly decide whether to
+ // try to apply some transformation, and then - if selected - to attempt to
+ // apply it.
+ void MaybeAddTransformationBeforeEachInstruction(
+ std::function<
+ void(const opt::Function& function, opt::BasicBlock* block,
+ opt::BasicBlock::iterator inst_it,
+ const protobufs::InstructionDescriptor& instruction_descriptor)>
+ maybe_apply_transformation);
+
private:
opt::IRContext* ir_context_;
FactManager* fact_manager_;
@@ -58,4 +99,4 @@
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_FUZZER_PASS_H_
+#endif // SOURCE_FUZZ_FUZZER_PASS_H_
diff --git a/source/fuzz/fuzzer_pass_add_dead_breaks.cpp b/source/fuzz/fuzzer_pass_add_dead_breaks.cpp
index 72cd17b..fa6b098 100644
--- a/source/fuzz/fuzzer_pass_add_dead_breaks.cpp
+++ b/source/fuzz/fuzzer_pass_add_dead_breaks.cpp
@@ -47,12 +47,11 @@
// ones that turn out to be no good.
for (auto& block : function) {
for (auto merge_block_id : merge_block_ids) {
- // TODO(afd): right now we completely ignore OpPhi instructions at
- // merge blocks. This will lead to interesting opportunities being
- // missed.
+ // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2856): right
+ // now we completely ignore OpPhi instructions at merge blocks. This
+ // will lead to interesting opportunities being missed.
auto candidate_transformation = TransformationAddDeadBreak(
- block.id(), merge_block_id,
- GetFuzzerContext()->GetRandomGenerator()->RandomBool(), {});
+ block.id(), merge_block_id, GetFuzzerContext()->ChooseEven(), {});
if (candidate_transformation.IsApplicable(GetIRContext(),
*GetFactManager())) {
// Only consider a transformation as a candidate if it is applicable.
@@ -77,16 +76,15 @@
while (!candidate_transformations.empty()) {
// Choose a random index into the sequence of remaining candidate
// transformations.
- auto index = GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
- static_cast<uint32_t>(candidate_transformations.size()));
+ auto index = GetFuzzerContext()->RandomIndex(candidate_transformations);
// Remove the transformation at the chosen index from the sequence.
auto transformation = std::move(candidate_transformations[index]);
candidate_transformations.erase(candidate_transformations.begin() + index);
// Probabilistically decide whether to try to apply it vs. ignore it, in the
// case that it is applicable.
if (transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
- GetFuzzerContext()->GetRandomGenerator()->RandomPercentage() >
- GetFuzzerContext()->GetChanceOfAddingDeadBreak()) {
+ GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfAddingDeadBreak())) {
transformation.Apply(GetIRContext(), GetFactManager());
*GetTransformations()->add_transformation() = transformation.ToMessage();
}
diff --git a/source/fuzz/fuzzer_pass_add_dead_breaks.h b/source/fuzz/fuzzer_pass_add_dead_breaks.h
index ad19856..12a5095 100644
--- a/source/fuzz/fuzzer_pass_add_dead_breaks.h
+++ b/source/fuzz/fuzzer_pass_add_dead_breaks.h
@@ -35,4 +35,4 @@
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_
+#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_
diff --git a/source/fuzz/fuzzer_pass_add_dead_continues.cpp b/source/fuzz/fuzzer_pass_add_dead_continues.cpp
index 2156d36..51bcb91 100644
--- a/source/fuzz/fuzzer_pass_add_dead_continues.cpp
+++ b/source/fuzz/fuzzer_pass_add_dead_continues.cpp
@@ -36,18 +36,17 @@
// node turns out to be inappropriate (e.g. by not being in a loop) the
// precondition for the transformation will fail and it will be ignored.
//
- // TODO(afd): right now we completely ignore OpPhi instructions at
- // merge blocks. This will lead to interesting opportunities being
- // missed.
+ // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2856): right
+ // now we completely ignore OpPhi instructions at continue targets.
+ // This will lead to interesting opportunities being missed.
auto candidate_transformation = TransformationAddDeadContinue(
- block.id(), GetFuzzerContext()->GetRandomGenerator()->RandomBool(),
- {});
+ block.id(), GetFuzzerContext()->ChooseEven(), {});
// Probabilistically decide whether to apply the transformation in the
// case that it is applicable.
if (candidate_transformation.IsApplicable(GetIRContext(),
*GetFactManager()) &&
- GetFuzzerContext()->GetRandomGenerator()->RandomPercentage() >
- GetFuzzerContext()->GetChanceOfAddingDeadContinue()) {
+ GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfAddingDeadContinue())) {
candidate_transformation.Apply(GetIRContext(), GetFactManager());
*GetTransformations()->add_transformation() =
candidate_transformation.ToMessage();
diff --git a/source/fuzz/fuzzer_pass_add_dead_continues.h b/source/fuzz/fuzzer_pass_add_dead_continues.h
index 6cadc97..d067f1c 100644
--- a/source/fuzz/fuzzer_pass_add_dead_continues.h
+++ b/source/fuzz/fuzzer_pass_add_dead_continues.h
@@ -36,4 +36,4 @@
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_CONTINUES_H_
+#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_CONTINUES_H_
diff --git a/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp b/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp
new file mode 100644
index 0000000..ead8c5c
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp
@@ -0,0 +1,61 @@
+// 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/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
+
+#include "source/fuzz/transformation_add_no_contraction_decoration.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassAddNoContractionDecorations::FuzzerPassAddNoContractionDecorations(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassAddNoContractionDecorations::
+ ~FuzzerPassAddNoContractionDecorations() = default;
+
+void FuzzerPassAddNoContractionDecorations::Apply() {
+ // Consider every instruction in every block in every function.
+ for (auto& function : *GetIRContext()->module()) {
+ for (auto& block : function) {
+ for (auto& inst : block) {
+ // Restrict attention to arithmetic instructions (as defined in the
+ // SPIR-V specification).
+ if (TransformationAddNoContractionDecoration::IsArithmetic(
+ inst.opcode())) {
+ // Randomly choose whether to apply the NoContraction decoration to
+ // this arithmetic instruction.
+ if (GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()
+ ->GetChanceOfAddingNoContractionDecoration())) {
+ TransformationAddNoContractionDecoration transformation(
+ inst.result_id());
+ assert(transformation.IsApplicable(GetIRContext(),
+ *GetFactManager()) &&
+ "Transformation should be applicable by construction.");
+ transformation.Apply(GetIRContext(), GetFactManager());
+ *GetTransformations()->add_transformation() =
+ transformation.ToMessage();
+ }
+ }
+ }
+ }
+ }
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h b/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h
new file mode 100644
index 0000000..abe5bd7
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h
@@ -0,0 +1,39 @@
+// 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_FUZZ_FUZZER_PASS_ADD_NO_CONTRACTION_DECORATIONS_
+#define SOURCE_FUZZ_FUZZER_PASS_ADD_NO_CONTRACTION_DECORATIONS_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A pass that applies the NoContraction decoration to arithmetic instructions.
+class FuzzerPassAddNoContractionDecorations : public FuzzerPass {
+ public:
+ FuzzerPassAddNoContractionDecorations(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ ~FuzzerPassAddNoContractionDecorations() override;
+
+ void Apply() override;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_NO_CONTRACTION_DECORATIONS_
diff --git a/source/fuzz/fuzzer_pass_add_useful_constructs.cpp b/source/fuzz/fuzzer_pass_add_useful_constructs.cpp
index 6ac4ae9..8552dfd 100644
--- a/source/fuzz/fuzzer_pass_add_useful_constructs.cpp
+++ b/source/fuzz/fuzzer_pass_add_useful_constructs.cpp
@@ -24,13 +24,11 @@
namespace spvtools {
namespace fuzz {
-using opt::IRContext;
-
FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs(
opt::IRContext* ir_context, FactManager* fact_manager,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations)
- : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations){};
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default;
diff --git a/source/fuzz/fuzzer_pass_add_useful_constructs.h b/source/fuzz/fuzzer_pass_add_useful_constructs.h
index a8ac9a3..7dc00f1 100644
--- a/source/fuzz/fuzzer_pass_add_useful_constructs.h
+++ b/source/fuzz/fuzzer_pass_add_useful_constructs.h
@@ -43,4 +43,4 @@
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_
+#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_
diff --git a/source/fuzz/fuzzer_pass_adjust_function_controls.cpp b/source/fuzz/fuzzer_pass_adjust_function_controls.cpp
new file mode 100644
index 0000000..2a11988
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_adjust_function_controls.cpp
@@ -0,0 +1,73 @@
+// 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/fuzz/fuzzer_pass_adjust_function_controls.h"
+
+#include "source/fuzz/transformation_set_function_control.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassAdjustFunctionControls::FuzzerPassAdjustFunctionControls(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassAdjustFunctionControls::~FuzzerPassAdjustFunctionControls() = default;
+
+void FuzzerPassAdjustFunctionControls::Apply() {
+ // Consider every function in the module.
+ for (auto& function : *GetIRContext()->module()) {
+ // Randomly decide whether to adjust this function's controls.
+ if (GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfAdjustingFunctionControl())) {
+ // Grab the function control mask for the function in its present form.
+ uint32_t existing_function_control_mask =
+ function.DefInst().GetSingleWordInOperand(0);
+
+ // For the new mask, we first randomly select one of three basic masks:
+ // None, Inline or DontInline. These are always valid (and are mutually
+ // exclusive).
+ std::vector<uint32_t> basic_function_control_masks = {
+ SpvFunctionControlMaskNone, SpvFunctionControlInlineMask,
+ SpvFunctionControlDontInlineMask};
+ uint32_t new_function_control_mask =
+ basic_function_control_masks[GetFuzzerContext()->RandomIndex(
+ basic_function_control_masks)];
+
+ // We now consider the Pure and Const mask bits. If these are already
+ // set on the function then it's OK to keep them, but also interesting
+ // to consider dropping them, so we decide randomly in each case.
+ for (auto mask_bit :
+ {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) {
+ if ((existing_function_control_mask & mask_bit) &&
+ GetFuzzerContext()->ChooseEven()) {
+ new_function_control_mask |= mask_bit;
+ }
+ }
+
+ // Create and add a transformation.
+ TransformationSetFunctionControl transformation(
+ function.DefInst().result_id(), new_function_control_mask);
+ assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
+ "Transformation should be applicable by construction.");
+ transformation.Apply(GetIRContext(), GetFactManager());
+ *GetTransformations()->add_transformation() = transformation.ToMessage();
+ }
+ }
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_adjust_function_controls.h b/source/fuzz/fuzzer_pass_adjust_function_controls.h
new file mode 100644
index 0000000..02d3600
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_adjust_function_controls.h
@@ -0,0 +1,39 @@
+// 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_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_
+#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A pass that adjusts the function controls on OpFunction instructions.
+class FuzzerPassAdjustFunctionControls : public FuzzerPass {
+ public:
+ FuzzerPassAdjustFunctionControls(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ ~FuzzerPassAdjustFunctionControls() override;
+
+ void Apply() override;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_
diff --git a/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp b/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp
new file mode 100644
index 0000000..ac2408a
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp
@@ -0,0 +1,121 @@
+// 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/fuzz/fuzzer_pass_adjust_loop_controls.h"
+
+#include "source/fuzz/transformation_set_loop_control.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassAdjustLoopControls::FuzzerPassAdjustLoopControls(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassAdjustLoopControls::~FuzzerPassAdjustLoopControls() = default;
+
+void FuzzerPassAdjustLoopControls::Apply() {
+ // Consider every merge instruction in the module (via looking through all
+ // functions and blocks).
+ for (auto& function : *GetIRContext()->module()) {
+ for (auto& block : function) {
+ if (auto merge_inst = block.GetMergeInst()) {
+ // Ignore the instruction if it is not a loop merge.
+ if (merge_inst->opcode() != SpvOpLoopMerge) {
+ continue;
+ }
+
+ // Decide randomly whether to adjust this loop merge.
+ if (!GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfAdjustingLoopControl())) {
+ continue;
+ }
+
+ uint32_t existing_mask = merge_inst->GetSingleWordOperand(
+ TransformationSetLoopControl::kLoopControlMaskInOperandIndex);
+
+ // First, set the new mask to one of None, Unroll or DontUnroll.
+ std::vector<uint32_t> basic_masks = {SpvLoopControlMaskNone,
+ SpvLoopControlUnrollMask,
+ SpvLoopControlDontUnrollMask};
+ uint32_t new_mask =
+ basic_masks[GetFuzzerContext()->RandomIndex(basic_masks)];
+
+ // For the loop controls that depend on guarantees about what the loop
+ // does, check which of these were present in the existing mask and
+ // randomly decide whether to keep them. They are just hints, so
+ // removing them should not change the semantics of the module.
+ for (auto mask_bit :
+ {SpvLoopControlDependencyInfiniteMask,
+ SpvLoopControlDependencyLengthMask,
+ SpvLoopControlMinIterationsMask, SpvLoopControlMaxIterationsMask,
+ SpvLoopControlIterationMultipleMask}) {
+ if ((existing_mask & mask_bit) && GetFuzzerContext()->ChooseEven()) {
+ // The mask bits we are considering are not available in all SPIR-V
+ // versions. However, we only include a mask bit if it was present
+ // in the original loop control mask, and we work under the
+ // assumption that we are transforming a valid module, thus we don't
+ // need to actually check whether the SPIR-V version being used
+ // supports these loop control mask bits.
+ new_mask |= mask_bit;
+ }
+ }
+
+ // We use 0 for peel count and partial count in the case that we choose
+ // not to set these controls.
+ uint32_t peel_count = 0;
+ uint32_t partial_count = 0;
+
+ // PeelCount and PartialCount are not compatible with DontUnroll, so
+ // we check whether DontUnroll is set.
+ if (!(new_mask & SpvLoopControlDontUnrollMask)) {
+ // If PeelCount is supported by this SPIR-V version, randomly choose
+ // whether to set it. If it was set in the original mask and is not
+ // selected for setting here, that amounts to dropping it.
+ if (TransformationSetLoopControl::PeelCountIsSupported(
+ GetIRContext()) &&
+ GetFuzzerContext()->ChooseEven()) {
+ new_mask |= SpvLoopControlPeelCountMask;
+ // The peel count is chosen randomly - if PeelCount was already set
+ // this will overwrite whatever peel count was previously used.
+ peel_count = GetFuzzerContext()->GetRandomLoopControlPeelCount();
+ }
+ // Similar, but for PartialCount.
+ if (TransformationSetLoopControl::PartialCountIsSupported(
+ GetIRContext()) &&
+ GetFuzzerContext()->ChooseEven()) {
+ new_mask |= SpvLoopControlPartialCountMask;
+ partial_count =
+ GetFuzzerContext()->GetRandomLoopControlPartialCount();
+ }
+ }
+
+ // Apply the transformation and add it to the output transformation
+ // sequence.
+ TransformationSetLoopControl transformation(block.id(), new_mask,
+ peel_count, partial_count);
+ assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
+ "Transformation should be applicable by construction.");
+ transformation.Apply(GetIRContext(), GetFactManager());
+ *GetTransformations()->add_transformation() =
+ transformation.ToMessage();
+ }
+ }
+ }
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_adjust_loop_controls.h b/source/fuzz/fuzzer_pass_adjust_loop_controls.h
new file mode 100644
index 0000000..e945606
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_adjust_loop_controls.h
@@ -0,0 +1,39 @@
+// 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_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_
+#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A pass that adjusts the loop controls on OpLoopMerge instructions.
+class FuzzerPassAdjustLoopControls : public FuzzerPass {
+ public:
+ FuzzerPassAdjustLoopControls(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ ~FuzzerPassAdjustLoopControls() override;
+
+ void Apply() override;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_
diff --git a/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp
new file mode 100644
index 0000000..a9d4b32
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp
@@ -0,0 +1,113 @@
+// 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/fuzz/fuzzer_pass_adjust_memory_operands_masks.h"
+
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/transformation_set_memory_operands_mask.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassAdjustMemoryOperandsMasks::FuzzerPassAdjustMemoryOperandsMasks(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassAdjustMemoryOperandsMasks::~FuzzerPassAdjustMemoryOperandsMasks() =
+ default;
+
+void FuzzerPassAdjustMemoryOperandsMasks::Apply() {
+ // Consider every block in every function.
+ for (auto& function : *GetIRContext()->module()) {
+ for (auto& block : function) {
+ // Consider every instruction in this block, using an explicit iterator so
+ // that when we find an instruction of interest we can search backwards to
+ // create an id descriptor for it.
+ for (auto inst_it = block.cbegin(); inst_it != block.cend(); ++inst_it) {
+ if (!TransformationSetMemoryOperandsMask::IsMemoryAccess(*inst_it)) {
+ // We are only interested in memory access instructions.
+ continue;
+ }
+
+ std::vector<uint32_t> indices_of_available_masks_to_adjust;
+ // All memory instructions have at least one memory operands mask.
+ indices_of_available_masks_to_adjust.push_back(0);
+ // From SPIR-V 1.4 onwards, OpCopyMemory and OpCopyMemorySized have a
+ // second mask.
+ switch (inst_it->opcode()) {
+ case SpvOpCopyMemory:
+ case SpvOpCopyMemorySized:
+ if (TransformationSetMemoryOperandsMask::
+ MultipleMemoryOperandMasksAreSupported(GetIRContext())) {
+ indices_of_available_masks_to_adjust.push_back(1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Consider the available masks
+ for (auto mask_index : indices_of_available_masks_to_adjust) {
+ // Randomly decide whether to adjust this mask.
+ if (!GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()
+ ->GetChanceOfAdjustingMemoryOperandsMask())) {
+ continue;
+ }
+ // Get the existing mask, using None if there was no mask present at
+ // all.
+ auto existing_mask_in_operand_index =
+ TransformationSetMemoryOperandsMask::GetInOperandIndexForMask(
+ *inst_it, mask_index);
+ auto existing_mask =
+ existing_mask_in_operand_index < inst_it->NumInOperands()
+ ? inst_it->GetSingleWordOperand(
+ existing_mask_in_operand_index)
+ : static_cast<uint32_t>(SpvMemoryAccessMaskNone);
+
+ // There are two things we can do to a mask:
+ // - add Volatile if not already present
+ // - toggle Nontemporal
+ // The following ensures that we do at least one of these
+ bool add_volatile = !(existing_mask & SpvMemoryAccessVolatileMask) &&
+ GetFuzzerContext()->ChooseEven();
+ bool toggle_nontemporal =
+ !add_volatile || GetFuzzerContext()->ChooseEven();
+
+ // These bitwise operations use '|' to add Volatile if desired, and
+ // '^' to toggle Nontemporal if desired.
+ uint32_t new_mask =
+ (existing_mask | (add_volatile ? SpvMemoryAccessVolatileMask
+ : SpvMemoryAccessMaskNone)) ^
+ (toggle_nontemporal ? SpvMemoryAccessNontemporalMask
+ : SpvMemoryAccessMaskNone);
+
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(block, inst_it), new_mask, mask_index);
+ assert(
+ transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
+ "Transformation should be applicable by construction.");
+ transformation.Apply(GetIRContext(), GetFactManager());
+ *GetTransformations()->add_transformation() =
+ transformation.ToMessage();
+ }
+ }
+ }
+ }
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h
new file mode 100644
index 0000000..c3d7118
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h
@@ -0,0 +1,40 @@
+// 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_FUZZ_FUZZER_PASS_ADJUST_MEMORY_OPERANDS_MASKS_H_
+#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_MEMORY_OPERANDS_MASKS_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A fuzzer pass to adjust the memory operand masks in memory access
+// instructions.
+class FuzzerPassAdjustMemoryOperandsMasks : public FuzzerPass {
+ public:
+ FuzzerPassAdjustMemoryOperandsMasks(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ ~FuzzerPassAdjustMemoryOperandsMasks();
+
+ void Apply() override;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_MEMORY_OPERANDS_MASKS_H_
diff --git a/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp b/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp
new file mode 100644
index 0000000..22654f2
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp
@@ -0,0 +1,76 @@
+// 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/fuzz/fuzzer_pass_adjust_selection_controls.h"
+
+#include "source/fuzz/transformation_set_selection_control.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassAdjustSelectionControls::FuzzerPassAdjustSelectionControls(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassAdjustSelectionControls::~FuzzerPassAdjustSelectionControls() =
+ default;
+
+void FuzzerPassAdjustSelectionControls::Apply() {
+ // Consider every merge instruction in the module (via looking through all
+ // functions and blocks).
+ for (auto& function : *GetIRContext()->module()) {
+ for (auto& block : function) {
+ if (auto merge_inst = block.GetMergeInst()) {
+ // Ignore the instruction if it is not a selection merge.
+ if (merge_inst->opcode() != SpvOpSelectionMerge) {
+ continue;
+ }
+
+ // Choose randomly whether to change the selection control for this
+ // instruction.
+ if (!GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfAdjustingSelectionControl())) {
+ continue;
+ }
+
+ // The choices to change the selection control to are the set of valid
+ // controls, minus the current control.
+ std::vector<uint32_t> choices;
+ for (auto control :
+ {SpvSelectionControlMaskNone, SpvSelectionControlFlattenMask,
+ SpvSelectionControlDontFlattenMask}) {
+ if (control == merge_inst->GetSingleWordOperand(1)) {
+ continue;
+ }
+ choices.push_back(control);
+ }
+
+ // Apply the transformation and add it to the output transformation
+ // sequence.
+ TransformationSetSelectionControl transformation(
+ block.id(), choices[GetFuzzerContext()->RandomIndex(choices)]);
+ assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
+ "Transformation should be applicable by construction.");
+ transformation.Apply(GetIRContext(), GetFactManager());
+ *GetTransformations()->add_transformation() =
+ transformation.ToMessage();
+ }
+ }
+ }
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_adjust_selection_controls.h b/source/fuzz/fuzzer_pass_adjust_selection_controls.h
new file mode 100644
index 0000000..b5b255c
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_adjust_selection_controls.h
@@ -0,0 +1,39 @@
+// 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_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_
+#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A pass that adjusts the selection controls on OpSelectionMerge instructions.
+class FuzzerPassAdjustSelectionControls : public FuzzerPass {
+ public:
+ FuzzerPassAdjustSelectionControls(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ ~FuzzerPassAdjustSelectionControls() override;
+
+ void Apply() override;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_
diff --git a/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
new file mode 100644
index 0000000..6ff42ca
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
@@ -0,0 +1,147 @@
+// 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/fuzz/fuzzer_pass_apply_id_synonyms.h"
+
+#include "source/fuzz/data_descriptor.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/id_use_descriptor.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/transformation_composite_extract.h"
+#include "source/fuzz/transformation_replace_id_with_synonym.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassApplyIdSynonyms::FuzzerPassApplyIdSynonyms(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassApplyIdSynonyms::~FuzzerPassApplyIdSynonyms() = default;
+
+void FuzzerPassApplyIdSynonyms::Apply() {
+ for (auto id_with_known_synonyms :
+ GetFactManager()->GetIdsForWhichSynonymsAreKnown(GetIRContext())) {
+ // Gather up all uses of |id_with_known_synonym|, and then subsequently
+ // iterate over these uses. We use this separation because, when
+ // considering a given use, we might apply a transformation that will
+ // invalidate the def-use manager.
+ std::vector<std::pair<opt::Instruction*, uint32_t>> uses;
+ GetIRContext()->get_def_use_mgr()->ForEachUse(
+ id_with_known_synonyms,
+ [&uses](opt::Instruction* use_inst, uint32_t use_index) -> void {
+ uses.emplace_back(
+ std::pair<opt::Instruction*, uint32_t>(use_inst, use_index));
+ });
+
+ for (auto& use : uses) {
+ auto use_inst = use.first;
+ auto use_index = use.second;
+ auto block_containing_use = GetIRContext()->get_instr_block(use_inst);
+ // The use might not be in a block; e.g. it could be a decoration.
+ if (!block_containing_use) {
+ continue;
+ }
+ if (!GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfReplacingIdWithSynonym())) {
+ continue;
+ }
+ // |use_index| is the absolute index of the operand. We require
+ // the index of the operand restricted to input operands only, so
+ // we subtract the number of non-input operands from |use_index|.
+ uint32_t use_in_operand_index =
+ use_index - use_inst->NumOperands() + use_inst->NumInOperands();
+ if (!TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym(
+ GetIRContext(), use_inst, use_in_operand_index)) {
+ continue;
+ }
+
+ std::vector<const protobufs::DataDescriptor*> synonyms_to_try;
+ for (auto& data_descriptor : GetFactManager()->GetSynonymsForId(
+ id_with_known_synonyms, GetIRContext())) {
+ protobufs::DataDescriptor descriptor_for_this_id =
+ MakeDataDescriptor(id_with_known_synonyms, {});
+ if (DataDescriptorEquals()(data_descriptor, &descriptor_for_this_id)) {
+ // Exclude the fact that the id is synonymous with itself.
+ continue;
+ }
+ synonyms_to_try.push_back(data_descriptor);
+ }
+ while (!synonyms_to_try.empty()) {
+ auto synonym_index = GetFuzzerContext()->RandomIndex(synonyms_to_try);
+ auto synonym_to_try = synonyms_to_try[synonym_index];
+ synonyms_to_try.erase(synonyms_to_try.begin() + synonym_index);
+
+ if (synonym_to_try->index_size() > 0 &&
+ use_inst->opcode() == SpvOpPhi) {
+ // We are trying to replace an operand to an OpPhi. This means
+ // we cannot use a composite synonym, because that requires
+ // extracting a component from a composite and we cannot insert
+ // an extract instruction before an OpPhi.
+ //
+ // TODO(afd): We could consider inserting the extract instruction
+ // into the relevant parent block of the OpPhi.
+ continue;
+ }
+
+ if (!TransformationReplaceIdWithSynonym::IdsIsAvailableAtUse(
+ GetIRContext(), use_inst, use_in_operand_index,
+ synonym_to_try->object())) {
+ continue;
+ }
+
+ // We either replace the use with an id known to be synonymous, or
+ // an id that will hold the result of extracting a synonym from a
+ // composite.
+ uint32_t id_with_which_to_replace_use;
+ if (synonym_to_try->index_size() == 0) {
+ id_with_which_to_replace_use = synonym_to_try->object();
+ } else {
+ id_with_which_to_replace_use = GetFuzzerContext()->GetFreshId();
+ protobufs::InstructionDescriptor instruction_to_insert_before =
+ MakeInstructionDescriptor(GetIRContext(), use_inst);
+ TransformationCompositeExtract composite_extract_transformation(
+ instruction_to_insert_before, id_with_which_to_replace_use,
+ synonym_to_try->object(),
+ fuzzerutil::RepeatedFieldToVector(synonym_to_try->index()));
+ assert(composite_extract_transformation.IsApplicable(
+ GetIRContext(), *GetFactManager()) &&
+ "Transformation should be applicable by construction.");
+ composite_extract_transformation.Apply(GetIRContext(),
+ GetFactManager());
+ *GetTransformations()->add_transformation() =
+ composite_extract_transformation.ToMessage();
+ }
+
+ TransformationReplaceIdWithSynonym replace_id_transformation(
+ MakeIdUseDescriptorFromUse(GetIRContext(), use_inst,
+ use_in_operand_index),
+ id_with_which_to_replace_use);
+
+ // The transformation should be applicable by construction.
+ assert(replace_id_transformation.IsApplicable(GetIRContext(),
+ *GetFactManager()));
+ replace_id_transformation.Apply(GetIRContext(), GetFactManager());
+ *GetTransformations()->add_transformation() =
+ replace_id_transformation.ToMessage();
+ break;
+ }
+ }
+ }
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_apply_id_synonyms.h b/source/fuzz/fuzzer_pass_apply_id_synonyms.h
new file mode 100644
index 0000000..1a0748e
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_apply_id_synonyms.h
@@ -0,0 +1,42 @@
+// 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_FUZZ_FUZZER_PASS_APPLY_ID_SYNONYMS_
+#define SOURCE_FUZZ_FUZZER_PASS_APPLY_ID_SYNONYMS_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A pass that replaces ids with other ids, or accesses into structures, that
+// are known to hold the same values.
+class FuzzerPassApplyIdSynonyms : public FuzzerPass {
+ public:
+ FuzzerPassApplyIdSynonyms(opt::IRContext* ir_context,
+ FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ ~FuzzerPassApplyIdSynonyms() override;
+
+ void Apply() override;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_PASS_APPLY_ID_SYNONYMS_
diff --git a/source/fuzz/fuzzer_pass_construct_composites.cpp b/source/fuzz/fuzzer_pass_construct_composites.cpp
new file mode 100644
index 0000000..9eb5631
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_construct_composites.cpp
@@ -0,0 +1,363 @@
+// 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/fuzz/fuzzer_pass_construct_composites.h"
+
+#include <cmath>
+#include <memory>
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/transformation_composite_construct.h"
+#include "source/util/make_unique.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassConstructComposites::FuzzerPassConstructComposites(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassConstructComposites::~FuzzerPassConstructComposites() = default;
+
+void FuzzerPassConstructComposites::Apply() {
+ // Gather up the ids of all composite types.
+ std::vector<uint32_t> composite_type_ids;
+ for (auto& inst : GetIRContext()->types_values()) {
+ if (fuzzerutil::IsCompositeType(
+ GetIRContext()->get_type_mgr()->GetType(inst.result_id()))) {
+ composite_type_ids.push_back(inst.result_id());
+ }
+ }
+
+ MaybeAddTransformationBeforeEachInstruction(
+ [this, &composite_type_ids](
+ const opt::Function& function, opt::BasicBlock* block,
+ opt::BasicBlock::iterator inst_it,
+ const protobufs::InstructionDescriptor& instruction_descriptor)
+ -> void {
+ // Check whether it is legitimate to insert a composite construction
+ // before the instruction.
+ if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
+ SpvOpCompositeConstruct, inst_it)) {
+ return;
+ }
+
+ // Randomly decide whether to try inserting an object copy here.
+ if (!GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfConstructingComposite())) {
+ return;
+ }
+
+ // For each instruction that is available at this program point (i.e. an
+ // instruction that is global or whose definition strictly dominates the
+ // program point) and suitable for making a synonym of, associate it
+ // with the id of its result type.
+ TypeIdToInstructions type_id_to_available_instructions;
+ for (auto instruction : FindAvailableInstructions(
+ function, block, inst_it, fuzzerutil::CanMakeSynonymOf)) {
+ RecordAvailableInstruction(instruction,
+ &type_id_to_available_instructions);
+ }
+
+ // At this point, |composite_type_ids| captures all the composite types
+ // we could try to create, while |type_id_to_available_instructions|
+ // captures all the available result ids we might use, organized by
+ // type.
+
+ // Now we try to find a composite that we can construct. We might not
+ // manage, if there is a paucity of available ingredients in the module
+ // (e.g. if our only available composite was a boolean vector and we had
+ // no instructions generating boolean result types available).
+ //
+ // If we succeed, |chosen_composite_type| will end up being non-zero,
+ // and |constructor_arguments| will end up giving us result ids suitable
+ // for constructing a composite of that type. Otherwise these variables
+ // will remain 0 and null respectively.
+ uint32_t chosen_composite_type = 0;
+ std::unique_ptr<std::vector<uint32_t>> constructor_arguments = nullptr;
+
+ // Initially, all composite type ids are available for us to try. Keep
+ // trying until we run out of options.
+ auto composites_to_try_constructing = composite_type_ids;
+ while (!composites_to_try_constructing.empty()) {
+ // Remove a composite type from the composite types left for us to
+ // try.
+ auto index =
+ GetFuzzerContext()->RandomIndex(composites_to_try_constructing);
+ auto next_composite_to_try_constructing =
+ composites_to_try_constructing[index];
+ composites_to_try_constructing.erase(
+ composites_to_try_constructing.begin() + index);
+
+ // Now try to construct a composite of this type, using an appropriate
+ // helper method depending on the kind of composite type.
+ auto composite_type = GetIRContext()->get_type_mgr()->GetType(
+ next_composite_to_try_constructing);
+ if (auto array_type = composite_type->AsArray()) {
+ constructor_arguments = TryConstructingArrayComposite(
+ *array_type, type_id_to_available_instructions);
+ } else if (auto matrix_type = composite_type->AsMatrix()) {
+ constructor_arguments = TryConstructingMatrixComposite(
+ *matrix_type, type_id_to_available_instructions);
+ } else if (auto struct_type = composite_type->AsStruct()) {
+ constructor_arguments = TryConstructingStructComposite(
+ *struct_type, type_id_to_available_instructions);
+ } else {
+ auto vector_type = composite_type->AsVector();
+ assert(vector_type &&
+ "The space of possible composite types should be covered by "
+ "the above cases.");
+ constructor_arguments = TryConstructingVectorComposite(
+ *vector_type, type_id_to_available_instructions);
+ }
+ if (constructor_arguments != nullptr) {
+ // We succeeded! Note the composite type we finally settled on, and
+ // exit from the loop.
+ chosen_composite_type = next_composite_to_try_constructing;
+ break;
+ }
+ }
+
+ if (!chosen_composite_type) {
+ // We did not manage to make a composite; return 0 to indicate that no
+ // instructions were added.
+ assert(constructor_arguments == nullptr);
+ return;
+ }
+ assert(constructor_arguments != nullptr);
+
+ // Make and apply a transformation.
+ TransformationCompositeConstruct transformation(
+ chosen_composite_type, *constructor_arguments,
+ instruction_descriptor, GetFuzzerContext()->GetFreshId());
+ assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
+ "This transformation should be applicable by construction.");
+ transformation.Apply(GetIRContext(), GetFactManager());
+ *GetTransformations()->add_transformation() =
+ transformation.ToMessage();
+ // Indicate that one instruction was added.
+ });
+}
+
+void FuzzerPassConstructComposites::RecordAvailableInstruction(
+ opt::Instruction* inst,
+ TypeIdToInstructions* type_id_to_available_instructions) {
+ if (type_id_to_available_instructions->count(inst->type_id()) == 0) {
+ (*type_id_to_available_instructions)[inst->type_id()] = {};
+ }
+ type_id_to_available_instructions->at(inst->type_id()).push_back(inst);
+}
+
+std::unique_ptr<std::vector<uint32_t>>
+FuzzerPassConstructComposites::TryConstructingArrayComposite(
+ const opt::analysis::Array& array_type,
+ const TypeIdToInstructions& type_id_to_available_instructions) {
+ // At present we assume arrays have a constant size.
+ assert(array_type.length_info().words.size() == 2);
+ assert(array_type.length_info().words[0] ==
+ opt::analysis::Array::LengthInfo::kConstant);
+
+ auto result = MakeUnique<std::vector<uint32_t>>();
+
+ // Get the element type for the array.
+ auto element_type_id =
+ GetIRContext()->get_type_mgr()->GetId(array_type.element_type());
+
+ // Get all instructions at our disposal that compute something of this element
+ // type.
+ auto available_instructions =
+ type_id_to_available_instructions.find(element_type_id);
+
+ if (available_instructions == type_id_to_available_instructions.cend()) {
+ // If there are not any instructions available that compute the element type
+ // of the array then we are not in a position to construct a composite with
+ // this array type.
+ return nullptr;
+ }
+ for (uint32_t index = 0; index < array_type.length_info().words[1]; index++) {
+ result->push_back(available_instructions
+ ->second[GetFuzzerContext()->RandomIndex(
+ available_instructions->second)]
+ ->result_id());
+ }
+ return result;
+}
+
+std::unique_ptr<std::vector<uint32_t>>
+FuzzerPassConstructComposites::TryConstructingMatrixComposite(
+ const opt::analysis::Matrix& matrix_type,
+ const TypeIdToInstructions& type_id_to_available_instructions) {
+ auto result = MakeUnique<std::vector<uint32_t>>();
+
+ // Get the element type for the matrix.
+ auto element_type_id =
+ GetIRContext()->get_type_mgr()->GetId(matrix_type.element_type());
+
+ // Get all instructions at our disposal that compute something of this element
+ // type.
+ auto available_instructions =
+ type_id_to_available_instructions.find(element_type_id);
+
+ if (available_instructions == type_id_to_available_instructions.cend()) {
+ // If there are not any instructions available that compute the element type
+ // of the matrix then we are not in a position to construct a composite with
+ // this matrix type.
+ return nullptr;
+ }
+ for (uint32_t index = 0; index < matrix_type.element_count(); index++) {
+ result->push_back(available_instructions
+ ->second[GetFuzzerContext()->RandomIndex(
+ available_instructions->second)]
+ ->result_id());
+ }
+ return result;
+}
+
+std::unique_ptr<std::vector<uint32_t>>
+FuzzerPassConstructComposites::TryConstructingStructComposite(
+ const opt::analysis::Struct& struct_type,
+ const TypeIdToInstructions& type_id_to_available_instructions) {
+ auto result = MakeUnique<std::vector<uint32_t>>();
+ // Consider the type of each field of the struct.
+ for (auto element_type : struct_type.element_types()) {
+ auto element_type_id = GetIRContext()->get_type_mgr()->GetId(element_type);
+ // Find the instructions at our disposal that compute something of the field
+ // type.
+ auto available_instructions =
+ type_id_to_available_instructions.find(element_type_id);
+ if (available_instructions == type_id_to_available_instructions.cend()) {
+ // If there are no such instructions, we cannot construct a composite of
+ // this struct type.
+ return nullptr;
+ }
+ result->push_back(available_instructions
+ ->second[GetFuzzerContext()->RandomIndex(
+ available_instructions->second)]
+ ->result_id());
+ }
+ return result;
+}
+
+std::unique_ptr<std::vector<uint32_t>>
+FuzzerPassConstructComposites::TryConstructingVectorComposite(
+ const opt::analysis::Vector& vector_type,
+ const TypeIdToInstructions& type_id_to_available_instructions) {
+ // Get details of the type underlying the vector, and the width of the vector,
+ // for convenience.
+ auto element_type = vector_type.element_type();
+ auto element_count = vector_type.element_count();
+
+ // Collect a mapping, from type id to width, for scalar/vector types that are
+ // smaller in width than |vector_type|, but that have the same underlying
+ // type. For example, if |vector_type| is vec4, the mapping will be:
+ // { float -> 1, vec2 -> 2, vec3 -> 3 }
+ // The mapping will have missing entries if some of these types do not exist.
+
+ std::map<uint32_t, uint32_t> smaller_vector_type_id_to_width;
+ // Add the underlying type. This id must exist, in order for |vector_type| to
+ // exist.
+ auto scalar_type_id = GetIRContext()->get_type_mgr()->GetId(element_type);
+ smaller_vector_type_id_to_width[scalar_type_id] = 1;
+
+ // Now add every vector type with width at least 2, and less than the width of
+ // |vector_type|.
+ for (uint32_t width = 2; width < element_count; width++) {
+ opt::analysis::Vector smaller_vector_type(vector_type.element_type(),
+ width);
+ auto smaller_vector_type_id =
+ GetIRContext()->get_type_mgr()->GetId(&smaller_vector_type);
+ // We might find that there is no declared type of this smaller width.
+ // For example, a module can declare vec4 without having declared vec2 or
+ // vec3.
+ if (smaller_vector_type_id) {
+ smaller_vector_type_id_to_width[smaller_vector_type_id] = width;
+ }
+ }
+
+ // Now we know the types that are available to us, we set about populating a
+ // vector of the right length. We do this by deciding, with no order in mind,
+ // which instructions we will use to populate the vector, and subsequently
+ // randomly choosing an order. This is to avoid biasing construction of
+ // vectors with smaller vectors to the left and scalars to the right. That is
+ // a concern because, e.g. in the case of populating a vec4, if we populate
+ // the constructor instructions left-to-right, we can always choose a vec3 to
+ // construct the first three elements, but can only choose a vec3 to construct
+ // the last three elements if we chose a float to construct the first element
+ // (otherwise there will not be space left for a vec3).
+
+ uint32_t vector_slots_used = 0;
+ // The instructions we will use to construct the vector, in no particular
+ // order at this stage.
+ std::vector<opt::Instruction*> instructions_to_use;
+
+ while (vector_slots_used < vector_type.element_count()) {
+ std::vector<opt::Instruction*> instructions_to_choose_from;
+ for (auto& entry : smaller_vector_type_id_to_width) {
+ if (entry.second >
+ std::min(vector_type.element_count() - 1,
+ vector_type.element_count() - vector_slots_used)) {
+ continue;
+ }
+ auto available_instructions =
+ type_id_to_available_instructions.find(entry.first);
+ if (available_instructions == type_id_to_available_instructions.cend()) {
+ continue;
+ }
+ instructions_to_choose_from.insert(instructions_to_choose_from.end(),
+ available_instructions->second.begin(),
+ available_instructions->second.end());
+ }
+ if (instructions_to_choose_from.empty()) {
+ // We may get unlucky and find that there are not any instructions to
+ // choose from. In this case we give up constructing a composite of this
+ // vector type. It might be that we could construct the composite in
+ // another manner, so we could opt to retry a few times here, but it is
+ // simpler to just give up on the basis that this will not happen
+ // frequently.
+ return nullptr;
+ }
+ auto instruction_to_use =
+ instructions_to_choose_from[GetFuzzerContext()->RandomIndex(
+ instructions_to_choose_from)];
+ instructions_to_use.push_back(instruction_to_use);
+ auto chosen_type =
+ GetIRContext()->get_type_mgr()->GetType(instruction_to_use->type_id());
+ if (chosen_type->AsVector()) {
+ assert(chosen_type->AsVector()->element_type() == element_type);
+ assert(chosen_type->AsVector()->element_count() < element_count);
+ assert(chosen_type->AsVector()->element_count() <=
+ element_count - vector_slots_used);
+ vector_slots_used += chosen_type->AsVector()->element_count();
+ } else {
+ assert(chosen_type == element_type);
+ vector_slots_used += 1;
+ }
+ }
+ assert(vector_slots_used == vector_type.element_count());
+
+ auto result = MakeUnique<std::vector<uint32_t>>();
+ std::vector<uint32_t> operands;
+ while (!instructions_to_use.empty()) {
+ auto index = GetFuzzerContext()->RandomIndex(instructions_to_use);
+ result->push_back(instructions_to_use[index]->result_id());
+ instructions_to_use.erase(instructions_to_use.begin() + index);
+ }
+ assert(result->size() > 1);
+ return result;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_construct_composites.h b/source/fuzz/fuzzer_pass_construct_composites.h
new file mode 100644
index 0000000..99ef31f
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_construct_composites.h
@@ -0,0 +1,79 @@
+// 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_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_
+#define SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+#include <map>
+#include <vector>
+
+namespace spvtools {
+namespace fuzz {
+
+// A fuzzer pass for constructing composite objects from smaller objects.
+class FuzzerPassConstructComposites : public FuzzerPass {
+ public:
+ FuzzerPassConstructComposites(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ ~FuzzerPassConstructComposites();
+
+ void Apply() override;
+
+ private:
+ // Used to map a type id to relevant instructions whose result type matches
+ // the type id.
+ typedef std::map<uint32_t, std::vector<opt::Instruction*>>
+ TypeIdToInstructions;
+
+ // Considers all instructions that are available at |inst| - instructions
+ // whose results could be packed into a composite - and updates
+ // |type_id_to_available_instructions| so that each such instruction is
+ // associated with its the id of its result type.
+ void RecordAvailableInstruction(
+ opt::Instruction* inst,
+ TypeIdToInstructions* type_id_to_available_instructions);
+
+ // Attempts to find suitable instruction result ids from the values of
+ // |type_id_to_available_instructions| that would allow a composite of type
+ // |array_type| to be constructed. Returns said ids if they can be found.
+ // Returns |nullptr| otherwise.
+ std::unique_ptr<std::vector<uint32_t>> TryConstructingArrayComposite(
+ const opt::analysis::Array& array_type,
+ const TypeIdToInstructions& type_id_to_available_instructions);
+
+ // Similar to TryConstructingArrayComposite, but for matrices.
+ std::unique_ptr<std::vector<uint32_t>> TryConstructingMatrixComposite(
+ const opt::analysis::Matrix& matrix_type,
+ const TypeIdToInstructions& type_id_to_available_instructions);
+
+ // Similar to TryConstructingArrayComposite, but for structs.
+ std::unique_ptr<std::vector<uint32_t>> TryConstructingStructComposite(
+ const opt::analysis::Struct& struct_type,
+ const TypeIdToInstructions& type_id_to_available_instructions);
+
+ // Similar to TryConstructingArrayComposite, but for vectors.
+ std::unique_ptr<std::vector<uint32_t>> TryConstructingVectorComposite(
+ const opt::analysis::Vector& vector_type,
+ const TypeIdToInstructions& type_id_to_available_instructions);
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_
diff --git a/source/fuzz/fuzzer_pass_copy_objects.cpp b/source/fuzz/fuzzer_pass_copy_objects.cpp
new file mode 100644
index 0000000..35b15a3
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_copy_objects.cpp
@@ -0,0 +1,80 @@
+// 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/fuzz/fuzzer_pass_copy_objects.h"
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/transformation_copy_object.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassCopyObjects::FuzzerPassCopyObjects(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassCopyObjects::~FuzzerPassCopyObjects() = default;
+
+void FuzzerPassCopyObjects::Apply() {
+ MaybeAddTransformationBeforeEachInstruction(
+ [this](const opt::Function& function, opt::BasicBlock* block,
+ opt::BasicBlock::iterator inst_it,
+ const protobufs::InstructionDescriptor& instruction_descriptor)
+ -> void {
+ assert(inst_it->opcode() ==
+ instruction_descriptor.target_instruction_opcode() &&
+ "The opcode of the instruction we might insert before must be "
+ "the same as the opcode in the descriptor for the instruction");
+
+ // Check whether it is legitimate to insert a copy before this
+ // instruction.
+ if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject,
+ inst_it)) {
+ return;
+ }
+
+ // Randomly decide whether to try inserting an object copy here.
+ if (!GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfCopyingObject())) {
+ return;
+ }
+
+ std::vector<opt::Instruction*> relevant_instructions =
+ FindAvailableInstructions(function, block, inst_it,
+ fuzzerutil::CanMakeSynonymOf);
+
+ // At this point, |relevant_instructions| contains all the instructions
+ // we might think of copying.
+ if (relevant_instructions.empty()) {
+ return;
+ }
+
+ // Choose a copyable instruction at random, and create and apply an
+ // object copying transformation based on it.
+ uint32_t index = GetFuzzerContext()->RandomIndex(relevant_instructions);
+ TransformationCopyObject transformation(
+ relevant_instructions[index]->result_id(), instruction_descriptor,
+ GetFuzzerContext()->GetFreshId());
+ assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
+ "This transformation should be applicable by construction.");
+ transformation.Apply(GetIRContext(), GetFactManager());
+ *GetTransformations()->add_transformation() =
+ transformation.ToMessage();
+ });
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_copy_objects.h b/source/fuzz/fuzzer_pass_copy_objects.h
new file mode 100644
index 0000000..5419459
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_copy_objects.h
@@ -0,0 +1,38 @@
+// 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_FUZZ_FUZZER_PASS_COPY_OBJECTS_H_
+#define SOURCE_FUZZ_FUZZER_PASS_COPY_OBJECTS_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A fuzzer pass for adding adding copies of objects to the module.
+class FuzzerPassCopyObjects : public FuzzerPass {
+ public:
+ FuzzerPassCopyObjects(opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ ~FuzzerPassCopyObjects();
+
+ void Apply() override;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_PASS_COPY_OBJECTS_H_
diff --git a/source/fuzz/fuzzer_pass_obfuscate_constants.cpp b/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
index ff52ea9..3df11ae 100644
--- a/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
+++ b/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
@@ -16,6 +16,7 @@
#include <cmath>
+#include "source/fuzz/instruction_descriptor.h"
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
#include "source/opt/ir_context.h"
@@ -48,14 +49,12 @@
// a 'greater than' or 'less than' kind of opcode, and then select a
// random opcode from the resulting subset.
SpvOp comparison_opcode;
- if (GetFuzzerContext()->GetRandomGenerator()->RandomBool()) {
- comparison_opcode = greater_than_opcodes
- [GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
- static_cast<uint32_t>(greater_than_opcodes.size()))];
+ if (GetFuzzerContext()->ChooseEven()) {
+ comparison_opcode = greater_than_opcodes[GetFuzzerContext()->RandomIndex(
+ greater_than_opcodes)];
} else {
- comparison_opcode = less_than_opcodes
- [GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
- static_cast<uint32_t>(less_than_opcodes.size()))];
+ comparison_opcode =
+ less_than_opcodes[GetFuzzerContext()->RandomIndex(less_than_opcodes)];
}
// We now need to decide how to order constant_id_1 and constant_id_2 such
@@ -103,12 +102,12 @@
for (uint32_t index : {0u, 1u}) {
// We randomly decide, based on the current depth of obfuscation, whether
// to further obfuscate this operand.
- if (GetFuzzerContext()->GoDeeperInConstantObfuscation()(
- depth, GetFuzzerContext()->GetRandomGenerator())) {
- auto in_operand_use = transformation::MakeIdUseDescriptor(
+ if (GetFuzzerContext()->GoDeeperInConstantObfuscation(depth)) {
+ auto in_operand_use = MakeIdUseDescriptor(
binary_operator_instruction->GetSingleWordInOperand(index),
- binary_operator_instruction->opcode(), index,
- binary_operator_instruction->result_id(), 0);
+ MakeInstructionDescriptor(binary_operator_instruction->result_id(),
+ binary_operator_instruction->opcode(), 0),
+ index);
ObfuscateConstant(depth + 1, in_operand_use);
}
}
@@ -252,9 +251,9 @@
// elements with known values.
return;
}
- auto chosen_type_id = available_types_with_uniforms
- [GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
- static_cast<uint32_t>(available_types_with_uniforms.size()))];
+ auto chosen_type_id =
+ available_types_with_uniforms[GetFuzzerContext()->RandomIndex(
+ available_types_with_uniforms)];
auto available_constants =
GetFactManager()->GetConstantsAvailableFromUniformsForType(
GetIRContext(), chosen_type_id);
@@ -269,15 +268,12 @@
// We know we have at least two known-to-be-constant uniforms of the chosen
// type. Pick one of them at random.
- auto constant_index_1 =
- GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
- static_cast<uint32_t>(available_constants.size()));
+ auto constant_index_1 = GetFuzzerContext()->RandomIndex(available_constants);
uint32_t constant_index_2;
// Now choose another one distinct from the first one.
do {
- constant_index_2 = GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
- static_cast<uint32_t>(available_constants.size()));
+ constant_index_2 = GetFuzzerContext()->RandomIndex(available_constants);
} while (constant_index_1 == constant_index_2);
auto constant_id_1 = available_constants[constant_index_1];
@@ -321,9 +317,7 @@
// Choose a random available uniform known to be equal to the constant.
protobufs::UniformBufferElementDescriptor uniform_descriptor =
- uniform_descriptors
- [GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
- static_cast<uint32_t>(uniform_descriptors.size()))];
+ uniform_descriptors[GetFuzzerContext()->RandomIndex(uniform_descriptors)];
// Create, apply and record a transformation to replace the constant use with
// the result of a load from the chosen uniform.
auto transformation = TransformationReplaceConstantWithUniform(
@@ -374,14 +368,17 @@
// it.
protobufs::IdUseDescriptor id_use_descriptor;
id_use_descriptor.set_id_of_interest(operand_id);
- id_use_descriptor.set_target_instruction_opcode(inst.opcode());
+ id_use_descriptor.mutable_enclosing_instruction()
+ ->set_target_instruction_opcode(inst.opcode());
+ id_use_descriptor.mutable_enclosing_instruction()
+ ->set_base_instruction_result_id(base_instruction_result_id);
+ id_use_descriptor.mutable_enclosing_instruction()
+ ->set_num_opcodes_to_ignore(
+ skipped_opcode_count.find(inst.opcode()) ==
+ skipped_opcode_count.end()
+ ? 0
+ : skipped_opcode_count.at(inst.opcode()));
id_use_descriptor.set_in_operand_index(in_operand_index);
- id_use_descriptor.set_base_instruction_result_id(
- base_instruction_result_id);
- id_use_descriptor.set_num_opcodes_to_ignore(
- skipped_opcode_count.find(inst.opcode()) == skipped_opcode_count.end()
- ? 0
- : skipped_opcode_count.at(inst.opcode()));
constant_uses->push_back(id_use_descriptor);
} break;
default:
@@ -445,13 +442,12 @@
// Go through the constant uses in a random order by repeatedly pulling out a
// constant use at a random index.
while (!constant_uses.empty()) {
- auto index = GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
- static_cast<uint32_t>(constant_uses.size()));
+ auto index = GetFuzzerContext()->RandomIndex(constant_uses);
auto constant_use = std::move(constant_uses[index]);
constant_uses.erase(constant_uses.begin() + index);
// Decide probabilistically whether to skip or obfuscate this constant use.
- if (GetFuzzerContext()->GetRandomGenerator()->RandomPercentage() >
- GetFuzzerContext()->GetChanceOfObfuscatingConstant()) {
+ if (!GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfObfuscatingConstant())) {
continue;
}
ObfuscateConstant(0, constant_use);
diff --git a/source/fuzz/fuzzer_pass_obfuscate_constants.h b/source/fuzz/fuzzer_pass_obfuscate_constants.h
index 03477a5..f34717b 100644
--- a/source/fuzz/fuzzer_pass_obfuscate_constants.h
+++ b/source/fuzz/fuzzer_pass_obfuscate_constants.h
@@ -104,4 +104,4 @@
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_
+#endif // SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_
diff --git a/source/fuzz/fuzzer_pass_permute_blocks.cpp b/source/fuzz/fuzzer_pass_permute_blocks.cpp
index 7ab2ee3..af6d2a5 100644
--- a/source/fuzz/fuzzer_pass_permute_blocks.cpp
+++ b/source/fuzz/fuzzer_pass_permute_blocks.cpp
@@ -57,8 +57,8 @@
// would provide more freedom for A to move.
for (auto id = block_ids.rbegin(); id != block_ids.rend(); ++id) {
// Randomly decide whether to ignore the block id.
- if (GetFuzzerContext()->GetRandomGenerator()->RandomPercentage() >
- GetFuzzerContext()->GetChanceOfMovingBlockDown()) {
+ if (!GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfMovingBlockDown())) {
continue;
}
// Keep pushing the block down, until pushing down fails.
diff --git a/source/fuzz/fuzzer_pass_permute_blocks.h b/source/fuzz/fuzzer_pass_permute_blocks.h
index d8aed72..6735e95 100644
--- a/source/fuzz/fuzzer_pass_permute_blocks.h
+++ b/source/fuzz/fuzzer_pass_permute_blocks.h
@@ -36,4 +36,4 @@
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_
+#endif // SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_
diff --git a/source/fuzz/fuzzer_pass_split_blocks.cpp b/source/fuzz/fuzzer_pass_split_blocks.cpp
index 39f84ec..6a2ea4d 100644
--- a/source/fuzz/fuzzer_pass_split_blocks.cpp
+++ b/source/fuzz/fuzzer_pass_split_blocks.cpp
@@ -14,9 +14,9 @@
#include "source/fuzz/fuzzer_pass_split_blocks.h"
-#include <utility>
#include <vector>
+#include "source/fuzz/instruction_descriptor.h"
#include "source/fuzz/transformation_split_block.h"
namespace spvtools {
@@ -44,45 +44,54 @@
// Now go through all the block pointers that were gathered.
for (auto& block : blocks) {
// Probabilistically decide whether to try to split this block.
- if (GetFuzzerContext()->GetRandomGenerator()->RandomPercentage() >
- GetFuzzerContext()->GetChanceOfSplittingBlock()) {
+ if (!GetFuzzerContext()->ChoosePercentage(
+ GetFuzzerContext()->GetChanceOfSplittingBlock())) {
+ // We are not going to try to split this block.
continue;
}
+
+ // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2964): consider
+ // taking a simpler approach to identifying the instruction before which
+ // to split a block.
+
// We are going to try to split this block. We now need to choose where
- // to split it. We do this by finding a base instruction that has a
- // result id, and an offset from that base instruction. We would like
- // offsets to be as small as possible and ideally 0 - we only need offsets
- // because not all instructions can be identified by a result id (e.g.
- // OpStore instructions cannot).
- std::vector<std::pair<uint32_t, uint32_t>> base_offset_pairs;
+ // to split it. We describe the instruction before which we would like to
+ // split a block via an InstructionDescriptor, details of which are
+ // commented in the protobufs definition file.
+ std::vector<protobufs::InstructionDescriptor> instruction_descriptors;
+
// The initial base instruction is the block label.
uint32_t base = block->id();
- uint32_t offset = 0;
+
+ // Counts the number of times we have seen each opcode since we reset the
+ // base instruction.
+ std::map<SpvOp, uint32_t> skip_count;
+
// Consider every instruction in the block. The label is excluded: it is
// only necessary to consider it as a base in case the first instruction
// in the block does not have a result id.
for (auto& inst : *block) {
if (inst.HasResultId()) {
// In the case that the instruction has a result id, we use the
- // instruction as its own base, with zero offset.
+ // instruction as its own base, and clear the skip counts we have
+ // collected.
base = inst.result_id();
- offset = 0;
- } else {
- // The instruction does not have a result id, so we need to identify
- // it via the latest instruction that did have a result id (base), and
- // an incremented offset.
- offset++;
+ skip_count.clear();
}
- base_offset_pairs.emplace_back(base, offset);
+ const SpvOp opcode = inst.opcode();
+ instruction_descriptors.emplace_back(MakeInstructionDescriptor(
+ base, opcode, skip_count.count(opcode) ? skip_count.at(opcode) : 0));
+ if (!inst.HasResultId()) {
+ skip_count[opcode] =
+ skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1;
+ }
}
// Having identified all the places we might be able to split the block,
// we choose one of them.
- auto base_offset = base_offset_pairs
- [GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
- static_cast<uint32_t>(base_offset_pairs.size()))];
- auto transformation =
- TransformationSplitBlock(base_offset.first, base_offset.second,
- GetFuzzerContext()->GetFreshId());
+ auto transformation = TransformationSplitBlock(
+ instruction_descriptors[GetFuzzerContext()->RandomIndex(
+ instruction_descriptors)],
+ GetFuzzerContext()->GetFreshId());
// If the position we have chosen turns out to be a valid place to split
// the block, we apply the split. Otherwise the block just doesn't get
// split.
diff --git a/source/fuzz/fuzzer_pass_split_blocks.h b/source/fuzz/fuzzer_pass_split_blocks.h
index 951022b..6e56dde 100644
--- a/source/fuzz/fuzzer_pass_split_blocks.h
+++ b/source/fuzz/fuzzer_pass_split_blocks.h
@@ -36,4 +36,4 @@
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_
+#endif // SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_
diff --git a/source/fuzz/fuzzer_util.cpp b/source/fuzz/fuzzer_util.cpp
index 9972e47..4654682 100644
--- a/source/fuzz/fuzzer_util.cpp
+++ b/source/fuzz/fuzzer_util.cpp
@@ -170,39 +170,233 @@
return false;
}
-opt::BasicBlock::iterator GetIteratorForBaseInstructionAndOffset(
- opt::BasicBlock* block, const opt::Instruction* base_inst,
- uint32_t offset) {
- // The cases where |base_inst| is the block's label, vs. inside the block,
- // are dealt with separately.
- if (base_inst == block->GetLabelInst()) {
- // |base_inst| is the block's label.
- if (offset == 0) {
- // We cannot return an iterator to the block's label.
- return block->end();
- }
- // Conceptually, the first instruction in the block is [label + 1].
- // We thus start from 1 when applying the offset.
- auto inst_it = block->begin();
- for (uint32_t i = 1; i < offset && inst_it != block->end(); i++) {
- ++inst_it;
- }
- // This is either the desired instruction, or the end of the block.
- return inst_it;
- }
- // |base_inst| is inside the block.
+opt::BasicBlock::iterator GetIteratorForInstruction(
+ opt::BasicBlock* block, const opt::Instruction* inst) {
for (auto inst_it = block->begin(); inst_it != block->end(); ++inst_it) {
- if (base_inst == &*inst_it) {
- // We have found the base instruction; we now apply the offset.
- for (uint32_t i = 0; i < offset && inst_it != block->end(); i++) {
- ++inst_it;
- }
- // This is either the desired instruction, or the end of the block.
+ if (inst == &*inst_it) {
return inst_it;
}
}
- assert(false && "The base instruction was not found.");
- return nullptr;
+ return block->end();
+}
+
+bool NewEdgeRespectsUseDefDominance(opt::IRContext* context,
+ opt::BasicBlock* bb_from,
+ opt::BasicBlock* bb_to) {
+ assert(bb_from->terminator()->opcode() == SpvOpBranch);
+
+ // If there is *already* an edge from |bb_from| to |bb_to|, then adding
+ // another edge is fine from a dominance point of view.
+ if (bb_from->terminator()->GetSingleWordInOperand(0) == bb_to->id()) {
+ return true;
+ }
+
+ // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2919): the
+ // solution below to determining whether a new edge respects dominance
+ // rules is incomplete. Test
+ // TransformationAddDeadContinueTest::DISABLED_Miscellaneous6 exposes the
+ // problem. In practice, this limitation does not bite too often, and the
+ // worst it does is leads to SPIR-V that spirv-val rejects.
+
+ // Let us assume that the module being manipulated is valid according to the
+ // rules of the SPIR-V language.
+ //
+ // Suppose that some block Y is dominated by |bb_to| (which includes the case
+ // where Y = |bb_to|).
+ //
+ // Suppose that Y uses an id i that is defined in some other block X.
+ //
+ // Because the module is valid, X must dominate Y. We are concerned about
+ // whether an edge from |bb_from| to |bb_to| could *stop* X from dominating
+ // Y.
+ //
+ // Because |bb_to| dominates Y, a new edge from |bb_from| to |bb_to| can
+ // only affect whether X dominates Y if X dominates |bb_to|.
+ //
+ // So let us assume that X does dominate |bb_to|, so that we have:
+ //
+ // (X defines i) dominates |bb_to| dominates (Y uses i)
+ //
+ // The new edge from |bb_from| to |bb_to| will stop the definition of i in X
+ // from dominating the use of i in Y exactly when the new edge will stop X
+ // from dominating |bb_to|.
+ //
+ // Now, the block X that we are worried about cannot dominate |bb_from|,
+ // because in that case X would still dominate |bb_to| after we add an edge
+ // from |bb_from| to |bb_to|.
+ //
+ // Also, it cannot be that X = |bb_to|, because nothing can stop a block
+ // from dominating itself.
+ //
+ // So we are looking for a block X such that:
+ //
+ // - X strictly dominates |bb_to|
+ // - X does not dominate |bb_from|
+ // - X defines an id i
+ // - i is used in some block Y
+ // - |bb_to| dominates Y
+
+ // Walk the dominator tree backwards, starting from the immediate dominator
+ // of |bb_to|. We can stop when we find a block that also dominates
+ // |bb_from|.
+ auto dominator_analysis = context->GetDominatorAnalysis(bb_from->GetParent());
+ for (auto dominator = dominator_analysis->ImmediateDominator(bb_to);
+ dominator != nullptr &&
+ !dominator_analysis->Dominates(dominator, bb_from);
+ dominator = dominator_analysis->ImmediateDominator(dominator)) {
+ // |dominator| is a candidate for block X in the above description.
+ // We now look through the instructions for a candidate instruction i.
+ for (auto& inst : *dominator) {
+ // Consider all the uses of this instruction.
+ if (!context->get_def_use_mgr()->WhileEachUse(
+ &inst,
+ [bb_to, context, dominator_analysis](
+ opt::Instruction* user, uint32_t operand_index) -> bool {
+ // If this use is in an OpPhi, we need to check that dominance
+ // of the relevant *parent* block is not spoiled. Otherwise we
+ // need to check that dominance of the block containing the use
+ // is not spoiled.
+ opt::BasicBlock* use_block_or_phi_parent =
+ user->opcode() == SpvOpPhi
+ ? context->cfg()->block(
+ user->GetSingleWordOperand(operand_index + 1))
+ : context->get_instr_block(user);
+
+ // There might not be any relevant block, e.g. if the use is in
+ // a decoration; in this case the new edge is unproblematic.
+ if (use_block_or_phi_parent == nullptr) {
+ return true;
+ }
+
+ // With reference to the above discussion,
+ // |use_block_or_phi_parent| is a candidate for the block Y.
+ // If |bb_to| dominates this block, the new edge would be
+ // problematic.
+ return !dominator_analysis->Dominates(bb_to,
+ use_block_or_phi_parent);
+ })) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool BlockIsReachableInItsFunction(opt::IRContext* context,
+ opt::BasicBlock* bb) {
+ auto enclosing_function = bb->GetParent();
+ return context->GetDominatorAnalysis(enclosing_function)
+ ->Dominates(enclosing_function->entry().get(), bb);
+}
+
+bool CanInsertOpcodeBeforeInstruction(
+ SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block) {
+ if (instruction_in_block->PreviousNode() &&
+ (instruction_in_block->PreviousNode()->opcode() == SpvOpLoopMerge ||
+ instruction_in_block->PreviousNode()->opcode() == SpvOpSelectionMerge)) {
+ // We cannot insert directly after a merge instruction.
+ return false;
+ }
+ if (opcode != SpvOpVariable &&
+ instruction_in_block->opcode() == SpvOpVariable) {
+ // We cannot insert a non-OpVariable instruction directly before a
+ // variable; variables in a function must be contiguous in the entry block.
+ return false;
+ }
+ // We cannot insert a non-OpPhi instruction directly before an OpPhi, because
+ // OpPhi instructions need to be contiguous at the start of a block.
+ return opcode == SpvOpPhi || instruction_in_block->opcode() != SpvOpPhi;
+}
+
+bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst) {
+ if (!inst->HasResultId()) {
+ // We can only make a synonym of an instruction that generates an id.
+ return false;
+ }
+ if (!inst->type_id()) {
+ // We can only make a synonym of an instruction that has a type.
+ return false;
+ }
+ // We do not make synonyms of objects that have decorations: if the synonym is
+ // not decorated analogously, using the original object vs. its synonymous
+ // form may not be equivalent.
+ return ir_context->get_decoration_mgr()
+ ->GetDecorationsFor(inst->result_id(), true)
+ .empty();
+}
+
+bool IsCompositeType(const opt::analysis::Type* type) {
+ return type && (type->AsArray() || type->AsMatrix() || type->AsStruct() ||
+ type->AsVector());
+}
+
+std::vector<uint32_t> RepeatedFieldToVector(
+ const google::protobuf::RepeatedField<uint32_t>& repeated_field) {
+ std::vector<uint32_t> result;
+ for (auto i : repeated_field) {
+ result.push_back(i);
+ }
+ return result;
+}
+
+uint32_t WalkCompositeTypeIndices(
+ opt::IRContext* context, uint32_t base_object_type_id,
+ const google::protobuf::RepeatedField<google::protobuf::uint32>& indices) {
+ uint32_t sub_object_type_id = base_object_type_id;
+ for (auto index : indices) {
+ auto should_be_composite_type =
+ context->get_def_use_mgr()->GetDef(sub_object_type_id);
+ assert(should_be_composite_type && "The type should exist.");
+ if (SpvOpTypeArray == should_be_composite_type->opcode()) {
+ auto array_length = GetArraySize(*should_be_composite_type, context);
+ if (array_length == 0 || index >= array_length) {
+ return 0;
+ }
+ sub_object_type_id = should_be_composite_type->GetSingleWordInOperand(0);
+ } else if (SpvOpTypeMatrix == should_be_composite_type->opcode()) {
+ auto matrix_column_count =
+ should_be_composite_type->GetSingleWordInOperand(1);
+ if (index >= matrix_column_count) {
+ return 0;
+ }
+ sub_object_type_id = should_be_composite_type->GetSingleWordInOperand(0);
+ } else if (SpvOpTypeStruct == should_be_composite_type->opcode()) {
+ if (index >= GetNumberOfStructMembers(*should_be_composite_type)) {
+ return 0;
+ }
+ sub_object_type_id =
+ should_be_composite_type->GetSingleWordInOperand(index);
+ } else if (SpvOpTypeVector == should_be_composite_type->opcode()) {
+ auto vector_length = should_be_composite_type->GetSingleWordInOperand(1);
+ if (index >= vector_length) {
+ return 0;
+ }
+ sub_object_type_id = should_be_composite_type->GetSingleWordInOperand(0);
+ } else {
+ return 0;
+ }
+ }
+ return sub_object_type_id;
+}
+
+uint32_t GetNumberOfStructMembers(
+ const opt::Instruction& struct_type_instruction) {
+ assert(struct_type_instruction.opcode() == SpvOpTypeStruct &&
+ "An OpTypeStruct instruction is required here.");
+ return struct_type_instruction.NumInOperands();
+}
+
+uint32_t GetArraySize(const opt::Instruction& array_type_instruction,
+ opt::IRContext* context) {
+ auto array_length_constant =
+ context->get_constant_mgr()
+ ->GetConstantFromInst(context->get_def_use_mgr()->GetDef(
+ array_type_instruction.GetSingleWordInOperand(1)))
+ ->AsIntConstant();
+ if (array_length_constant->words().size() != 1) {
+ return 0;
+ }
+ return array_length_constant->GetU32();
}
} // namespace fuzzerutil
diff --git a/source/fuzz/fuzzer_util.h b/source/fuzz/fuzzer_util.h
index 47588b0..1569df0 100644
--- a/source/fuzz/fuzzer_util.h
+++ b/source/fuzz/fuzzer_util.h
@@ -64,15 +64,58 @@
bool BlockIsInLoopContinueConstruct(opt::IRContext* context, uint32_t block_id,
uint32_t maybe_loop_header_id);
-// Requires that |base_inst| is either the label instruction of |block| or an
-// instruction inside |block|.
-//
-// If the block contains a (non-label, non-terminator) instruction |offset|
-// instructions after |base_inst|, an iterator to this instruction is returned.
-//
+// If |block| contains |inst|, an iterator for |inst| is returned.
// Otherwise |block|->end() is returned.
-opt::BasicBlock::iterator GetIteratorForBaseInstructionAndOffset(
- opt::BasicBlock* block, const opt::Instruction* base_inst, uint32_t offset);
+opt::BasicBlock::iterator GetIteratorForInstruction(
+ opt::BasicBlock* block, const opt::Instruction* inst);
+
+// The function determines whether adding an edge from |bb_from| to |bb_to| -
+// is legitimate with respect to the SPIR-V rule that a definition must
+// dominate all of its uses. This is because adding such an edge can change
+// dominance in the control flow graph, potentially making the module invalid.
+bool NewEdgeRespectsUseDefDominance(opt::IRContext* context,
+ opt::BasicBlock* bb_from,
+ opt::BasicBlock* bb_to);
+
+// Returns true if and only if there is a path to |bb| from the entry block of
+// the function that contains |bb|.
+bool BlockIsReachableInItsFunction(opt::IRContext* context,
+ opt::BasicBlock* bb);
+
+// Determines whether it is OK to insert an instruction with opcode |opcode|
+// before |instruction_in_block|.
+bool CanInsertOpcodeBeforeInstruction(
+ SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block);
+
+// Determines whether it is OK to make a synonym of |inst|.
+bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst);
+
+// Determines whether the given type is a composite; that is: an array, matrix,
+// struct or vector.
+bool IsCompositeType(const opt::analysis::Type* type);
+
+// Returns a vector containing the same elements as |repeated_field|.
+std::vector<uint32_t> RepeatedFieldToVector(
+ const google::protobuf::RepeatedField<uint32_t>& repeated_field);
+
+// Given a type id, |base_object_type_id|, checks that the given sequence of
+// |indices| is suitable for indexing into this type. Returns the id of the
+// type of the final sub-object reached via the indices if they are valid, and
+// 0 otherwise.
+uint32_t WalkCompositeTypeIndices(
+ opt::IRContext* context, uint32_t base_object_type_id,
+ const google::protobuf::RepeatedField<google::protobuf::uint32>& indices);
+
+// Returns the number of members associated with |struct_type_instruction|,
+// which must be an OpStructType instruction.
+uint32_t GetNumberOfStructMembers(
+ const opt::Instruction& struct_type_instruction);
+
+// Returns the constant size of the array associated with
+// |array_type_instruction|, which must be an OpArrayType instruction. Returns
+// 0 if there is not a static size.
+uint32_t GetArraySize(const opt::Instruction& array_type_instruction,
+ opt::IRContext* context);
} // namespace fuzzerutil
diff --git a/source/fuzz/id_use_descriptor.cpp b/source/fuzz/id_use_descriptor.cpp
index 33d2ca0..eb8589d 100644
--- a/source/fuzz/id_use_descriptor.cpp
+++ b/source/fuzz/id_use_descriptor.cpp
@@ -14,69 +14,49 @@
#include "source/fuzz/id_use_descriptor.h"
+#include "source/fuzz/instruction_descriptor.h"
+
namespace spvtools {
namespace fuzz {
-opt::Instruction* transformation::FindInstruction(
- const protobufs::IdUseDescriptor& descriptor,
- spvtools::opt::IRContext* context) {
- for (auto& function : *context->module()) {
- for (auto& block : function) {
- bool found_base = block.id() == descriptor.base_instruction_result_id();
- uint32_t num_ignored = 0;
- for (auto& instruction : block) {
- if (instruction.HasResultId() &&
- instruction.result_id() ==
- descriptor.base_instruction_result_id()) {
- assert(!found_base &&
- "It should not be possible to find the base instruction "
- "multiple times.");
- found_base = true;
- assert(num_ignored == 0 &&
- "The skipped instruction count should only be incremented "
- "after the instruction base has been found.");
- }
- if (found_base &&
- instruction.opcode() == descriptor.target_instruction_opcode()) {
- if (num_ignored == descriptor.num_opcodes_to_ignore()) {
- if (descriptor.in_operand_index() >= instruction.NumInOperands()) {
- return nullptr;
- }
- auto in_operand =
- instruction.GetInOperand(descriptor.in_operand_index());
- if (in_operand.type != SPV_OPERAND_TYPE_ID) {
- return nullptr;
- }
- if (in_operand.words[0] != descriptor.id_of_interest()) {
- return nullptr;
- }
- return &instruction;
- }
- num_ignored++;
- }
- }
- if (found_base) {
- // We found the base instruction, but did not find the target
- // instruction in the same block.
- return nullptr;
- }
- }
+opt::Instruction* FindInstructionContainingUse(
+ const protobufs::IdUseDescriptor& id_use_descriptor,
+ opt::IRContext* context) {
+ auto result =
+ FindInstruction(id_use_descriptor.enclosing_instruction(), context);
+ if (!result) {
+ return nullptr;
}
- return nullptr;
+ if (id_use_descriptor.in_operand_index() >= result->NumInOperands()) {
+ return nullptr;
+ }
+ if (result->GetSingleWordInOperand(id_use_descriptor.in_operand_index()) !=
+ id_use_descriptor.id_of_interest()) {
+ return nullptr;
+ }
+ return result;
}
-protobufs::IdUseDescriptor transformation::MakeIdUseDescriptor(
- uint32_t id_of_interest, SpvOp target_instruction_opcode,
- uint32_t in_operand_index, uint32_t base_instruction_result_id,
- uint32_t num_opcodes_to_ignore) {
+protobufs::IdUseDescriptor MakeIdUseDescriptor(
+ uint32_t id_of_interest,
+ const protobufs::InstructionDescriptor& enclosing_instruction,
+ uint32_t in_operand_index) {
protobufs::IdUseDescriptor result;
result.set_id_of_interest(id_of_interest);
- result.set_target_instruction_opcode(target_instruction_opcode);
+ *result.mutable_enclosing_instruction() = enclosing_instruction;
result.set_in_operand_index(in_operand_index);
- result.set_base_instruction_result_id(base_instruction_result_id);
- result.set_num_opcodes_to_ignore(num_opcodes_to_ignore);
return result;
}
+protobufs::IdUseDescriptor MakeIdUseDescriptorFromUse(
+ opt::IRContext* context, opt::Instruction* inst,
+ uint32_t in_operand_index) {
+ const auto& in_operand = inst->GetInOperand(in_operand_index);
+ assert(in_operand.type == SPV_OPERAND_TYPE_ID);
+ return MakeIdUseDescriptor(in_operand.words[0],
+ MakeInstructionDescriptor(context, inst),
+ in_operand_index);
+}
+
} // namespace fuzz
} // namespace spvtools
diff --git a/source/fuzz/id_use_descriptor.h b/source/fuzz/id_use_descriptor.h
index 63016c5..d18bb66 100644
--- a/source/fuzz/id_use_descriptor.h
+++ b/source/fuzz/id_use_descriptor.h
@@ -12,31 +12,36 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SOURCE_FUZZ_ID_USE_LOCATOR_H_
-#define SOURCE_FUZZ_ID_USE_LOCATOR_H_
+#ifndef SOURCE_FUZZ_ID_USE_DESCRIPTOR_H_
+#define SOURCE_FUZZ_ID_USE_DESCRIPTOR_H_
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace fuzz {
-namespace transformation {
-// Looks for an instruction in |context| such that the id use represented by
-// |descriptor| is one of the operands to said instruction. Returns |nullptr|
-// if no such instruction can be found.
-opt::Instruction* FindInstruction(const protobufs::IdUseDescriptor& descriptor,
- opt::IRContext* context);
+// Looks for an instruction in |context| that contains a use
+// identified by |id_use_descriptor|.
+// Returns |nullptr| if no such instruction can be found.
+opt::Instruction* FindInstructionContainingUse(
+ const protobufs::IdUseDescriptor& id_use_descriptor,
+ opt::IRContext* context);
// Creates an IdUseDescriptor protobuf message from the given components.
// See the protobuf definition for details of what these components mean.
protobufs::IdUseDescriptor MakeIdUseDescriptor(
- uint32_t id_of_interest, SpvOp target_instruction_opcode,
- uint32_t in_operand_index, uint32_t base_instruction_result_id,
- uint32_t num_opcodes_to_ignore);
+ uint32_t id_of_interest,
+ const protobufs::InstructionDescriptor& enclosing_instruction,
+ uint32_t in_operand_index);
-} // namespace transformation
+// Given an id use, represented by the instruction |inst| that uses the id, and
+// the input operand index |in_operand_index| associated with the usage, returns
+// an IdUseDescriptor that represents the use.
+protobufs::IdUseDescriptor MakeIdUseDescriptorFromUse(
+ opt::IRContext* context, opt::Instruction* inst, uint32_t in_operand_index);
+
} // namespace fuzz
} // namespace spvtools
-#endif // SOURCE_FUZZ_ID_USE_LOCATOR_H_
+#endif // SOURCE_FUZZ_ID_USE_DESCRIPTOR_H_
diff --git a/source/fuzz/instruction_descriptor.cpp b/source/fuzz/instruction_descriptor.cpp
new file mode 100644
index 0000000..c0cc5e5
--- /dev/null
+++ b/source/fuzz/instruction_descriptor.cpp
@@ -0,0 +1,127 @@
+// 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/fuzz/instruction_descriptor.h"
+
+namespace spvtools {
+namespace fuzz {
+
+opt::Instruction* FindInstruction(
+ const protobufs::InstructionDescriptor& instruction_descriptor,
+ spvtools::opt::IRContext* context) {
+ for (auto& function : *context->module()) {
+ for (auto& block : function) {
+ bool found_base =
+ block.id() == instruction_descriptor.base_instruction_result_id();
+ uint32_t num_ignored = 0;
+ for (auto& instruction : block) {
+ if (instruction.HasResultId() &&
+ instruction.result_id() ==
+ instruction_descriptor.base_instruction_result_id()) {
+ assert(!found_base &&
+ "It should not be possible to find the base instruction "
+ "multiple times.");
+ found_base = true;
+ assert(num_ignored == 0 &&
+ "The skipped instruction count should only be incremented "
+ "after the instruction base has been found.");
+ }
+ if (found_base &&
+ instruction.opcode() ==
+ instruction_descriptor.target_instruction_opcode()) {
+ if (num_ignored == instruction_descriptor.num_opcodes_to_ignore()) {
+ return &instruction;
+ }
+ num_ignored++;
+ }
+ }
+ if (found_base) {
+ // We found the base instruction, but did not find the target
+ // instruction in the same block.
+ return nullptr;
+ }
+ }
+ }
+ return nullptr;
+}
+
+protobufs::InstructionDescriptor MakeInstructionDescriptor(
+ uint32_t base_instruction_result_id, SpvOp target_instruction_opcode,
+ uint32_t num_opcodes_to_ignore) {
+ protobufs::InstructionDescriptor result;
+ result.set_base_instruction_result_id(base_instruction_result_id);
+ result.set_target_instruction_opcode(target_instruction_opcode);
+ result.set_num_opcodes_to_ignore(num_opcodes_to_ignore);
+ return result;
+}
+
+protobufs::InstructionDescriptor MakeInstructionDescriptor(
+ const opt::BasicBlock& block,
+ const opt::BasicBlock::const_iterator& inst_it) {
+ const SpvOp opcode =
+ inst_it->opcode(); // The opcode of the instruction being described.
+ uint32_t skip_count = 0; // The number of these opcodes we have skipped when
+ // searching backwards.
+
+ // Consider instructions in the block in reverse order, starting from
+ // |inst_it|.
+ for (opt::BasicBlock::const_iterator backwards_iterator = inst_it;;
+ --backwards_iterator) {
+ if (backwards_iterator->HasResultId()) {
+ // As soon as we find an instruction with a result id, we can return a
+ // descriptor for |inst_it|.
+ return MakeInstructionDescriptor(backwards_iterator->result_id(), opcode,
+ skip_count);
+ }
+ if (backwards_iterator != inst_it &&
+ backwards_iterator->opcode() == opcode) {
+ // We are skipping over an instruction with the same opcode as |inst_it|;
+ // we increase our skip count to reflect this.
+ skip_count++;
+ }
+ if (backwards_iterator == block.begin()) {
+ // We exit the loop when we reach the start of the block, but only after
+ // we have processed the first instruction in the block.
+ break;
+ }
+ }
+ // We did not find an instruction inside the block with a result id, so we use
+ // the block's label's id.
+ return MakeInstructionDescriptor(block.id(), opcode, skip_count);
+}
+
+protobufs::InstructionDescriptor MakeInstructionDescriptor(
+ opt::IRContext* context, opt::Instruction* inst) {
+ auto block = context->get_instr_block(inst);
+ uint32_t base_instruction_result_id = block->id();
+ uint32_t num_opcodes_to_ignore = 0;
+ for (auto& inst_in_block : *block) {
+ if (inst_in_block.HasResultId()) {
+ base_instruction_result_id = inst_in_block.result_id();
+ num_opcodes_to_ignore = 0;
+ }
+ if (&inst_in_block == inst) {
+ return MakeInstructionDescriptor(base_instruction_result_id,
+ inst->opcode(), num_opcodes_to_ignore);
+ }
+ if (inst_in_block.opcode() == inst->opcode()) {
+ num_opcodes_to_ignore++;
+ }
+ }
+ assert(false && "No matching instruction was found.");
+ return protobufs::InstructionDescriptor();
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/instruction_descriptor.h b/source/fuzz/instruction_descriptor.h
new file mode 100644
index 0000000..2ccd15a
--- /dev/null
+++ b/source/fuzz/instruction_descriptor.h
@@ -0,0 +1,53 @@
+// 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_FUZZ_INSTRUCTION_DESCRIPTOR_H_
+#define SOURCE_FUZZ_INSTRUCTION_DESCRIPTOR_H_
+
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/opt/basic_block.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Looks for an instruction in |context| corresponding to |descriptor|.
+// Returns |nullptr| if no such instruction can be found.
+opt::Instruction* FindInstruction(
+ const protobufs::InstructionDescriptor& instruction_descriptor,
+ opt::IRContext* context);
+
+// Creates an InstructionDescriptor protobuf message from the given
+// components. See the protobuf definition for details of what these
+// components mean.
+protobufs::InstructionDescriptor MakeInstructionDescriptor(
+ uint32_t base_instruction_result_id, SpvOp target_instruction_opcode,
+ uint32_t num_opcodes_to_ignore);
+
+// Returns an instruction descriptor that describing the instruction at
+// |inst_it|, which must be inside |block|. The descriptor will be with
+// respect to the first instruction at or before |inst_it| that has a result
+// id.
+protobufs::InstructionDescriptor MakeInstructionDescriptor(
+ const opt::BasicBlock& block,
+ const opt::BasicBlock::const_iterator& inst_it);
+
+// Returns an InstructionDescriptor that describes the given instruction |inst|.
+protobufs::InstructionDescriptor MakeInstructionDescriptor(
+ opt::IRContext* context, opt::Instruction* inst);
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_INSTRUCTION_DESCRIPTOR_H_
diff --git a/source/fuzz/protobufs/spvtoolsfuzz.proto b/source/fuzz/protobufs/spvtoolsfuzz.proto
index 4e8dcac..b33c2e5 100644
--- a/source/fuzz/protobufs/spvtoolsfuzz.proto
+++ b/source/fuzz/protobufs/spvtoolsfuzz.proto
@@ -21,17 +21,37 @@
package spvtools.fuzz.protobufs;
+message InstructionDescriptor {
+
+ // Describes an instruction in some block of a function with respect to a
+ // base instruction.
+
+ // The id of an instruction after which the instruction being described is
+ // believed to be located. It might be the using instruction itself.
+ uint32 base_instruction_result_id = 1;
+
+ // The opcode for the instruction being described.
+ uint32 target_instruction_opcode = 2;
+
+ // The number of matching opcodes to skip over when searching from the base
+ // instruction to the instruction being described.
+ uint32 num_opcodes_to_ignore = 3;
+
+}
+
message IdUseDescriptor {
- // Describes a use of an id as an input operand to an instruction in some block
- // of a function.
+ // Describes a use of an id as an input operand to an instruction in some
+ // block of a function.
// Example:
// - id_of_interest = 42
- // - target_instruction_opcode = OpStore
+ // - enclosing_instruction = (
+ // base_instruction_result_id = 50,
+ // target_instruction_opcode = OpStore
+ // num_opcodes_to_ignore = 7
+ // )
// - in_operand_index = 1
- // - base_instruction_result_id = 50
- // - num_opcodes_to_ignore = 7
// represents a use of id 42 as input operand 1 to an OpStore instruction,
// such that the OpStore instruction can be found in the same basic block as
// the instruction with result id 50, and in particular is the 8th OpStore
@@ -41,20 +61,11 @@
// An id that we would like to be able to find a use of.
uint32 id_of_interest = 1;
- // The opcode for the instruction that uses the id.
- uint32 target_instruction_opcode = 2;
-
// The input operand index at which the use is expected.
+ InstructionDescriptor enclosing_instruction = 2;
+
uint32 in_operand_index = 3;
- // The id of an instruction after which the instruction that contains the use
- // is believed to occur; it might be the using instruction itself.
- uint32 base_instruction_result_id = 4;
-
- // The number of matching opcodes to skip over when searching for the using
- // instruction from the base instruction.
- uint32 num_opcodes_to_ignore = 5;
-
}
message DataDescriptor {
@@ -113,7 +124,7 @@
oneof fact {
// Order the fact options by numeric id (rather than alphabetically).
FactConstantUniform constant_uniform_fact = 1;
- FactIdSynonym id_synonym_fact = 2;
+ FactDataSynonym data_synonym_fact = 2;
}
}
@@ -135,19 +146,16 @@
}
-message FactIdSynonym {
+message FactDataSynonym {
- // Records the fact that the data held in an id is guaranteed to be equal to
- // the data held in a data descriptor. spirv-fuzz can use this to replace
- // uses of the id with references to the data described by the data
- // descriptor.
+ // Records the fact that the data held in two data descriptors are guaranteed
+ // to be equal. spirv-fuzz can use this to replace uses of one piece of data
+ // with a known-to-be-equal piece of data.
- // An id
- uint32 id = 1;
+ // Data descriptors guaranteed to hold identical data.
+ DataDescriptor data1 = 1;
- // A data descriptor guaranteed to hold a value identical to that held by the
- // id
- DataDescriptor data_descriptor = 2;
+ DataDescriptor data2 = 2;
}
@@ -167,11 +175,21 @@
TransformationAddTypeFloat add_type_float = 6;
TransformationAddTypeInt add_type_int = 7;
TransformationAddDeadBreak add_dead_break = 8;
- TransformationReplaceBooleanConstantWithConstantBinary replace_boolean_constant_with_constant_binary = 9;
+ TransformationReplaceBooleanConstantWithConstantBinary
+ replace_boolean_constant_with_constant_binary = 9;
TransformationAddTypePointer add_type_pointer = 10;
TransformationReplaceConstantWithUniform replace_constant_with_uniform = 11;
TransformationAddDeadContinue add_dead_continue = 12;
TransformationCopyObject copy_object = 13;
+ TransformationReplaceIdWithSynonym replace_id_with_synonym = 14;
+ TransformationSetSelectionControl set_selection_control = 15;
+ TransformationCompositeConstruct composite_construct = 16;
+ TransformationSetLoopControl set_loop_control = 17;
+ TransformationSetFunctionControl set_function_control = 18;
+ TransformationAddNoContractionDecoration add_no_contraction_decoration = 19;
+ TransformationSetMemoryOperandsMask set_memory_operands_mask = 20;
+ TransformationCompositeExtract composite_extract = 21;
+ TransformationVectorShuffle vector_shuffle = 22;
// Add additional option using the next available number.
}
}
@@ -244,6 +262,15 @@
}
+message TransformationAddNoContractionDecoration {
+
+ // Applies OpDecorate NoContraction to the given result id
+
+ // Result id to be decorated
+ uint32 result_id = 1;
+
+}
+
message TransformationAddTypeBoolean {
// Adds OpTypeBool to the module
@@ -296,6 +323,46 @@
}
+message TransformationCompositeConstruct {
+
+ // A transformation that introduces an OpCompositeConstruct instruction to
+ // make a composite object.
+
+ // Id of the type of the composite that is to be constructed
+ uint32 composite_type_id = 1;
+
+ // Ids of the objects that will form the components of the composite
+ repeated uint32 component = 2;
+
+ // A descriptor for an instruction in a block before which the new
+ // OpCompositeConstruct instruction should be inserted
+ InstructionDescriptor instruction_to_insert_before = 3;
+
+ // A fresh id for the composite object
+ uint32 fresh_id = 4;
+
+}
+
+message TransformationCompositeExtract {
+
+ // A transformation that adds an instruction to extract an element from a
+ // composite.
+
+ // A descriptor for an instruction in a block before which the new
+ // OpCompositeExtract instruction should be inserted
+ InstructionDescriptor instruction_to_insert_before = 1;
+
+ // Result id for the extract operation.
+ uint32 fresh_id = 2;
+
+ // Id of the composite from which data is to be extracted.
+ uint32 composite_id = 3;
+
+ // Indices that indicate which part of the composite should be extracted.
+ repeated uint32 index = 4;
+
+}
+
message TransformationCopyObject {
// A transformation that introduces an OpCopyObject instruction to make a
@@ -304,15 +371,12 @@
// Id of the object to be copied
uint32 object = 1;
- // The id of an instruction in a block
- uint32 base_instruction_id = 2;
-
- // An offset, such that OpCopyObject instruction should be inserted right
- // before the instruction |offset| instructions after |base_instruction_id|
- uint32 offset = 3;
+ // A descriptor for an instruction in a block before which the new
+ // OpCopyObject instruction should be inserted
+ InstructionDescriptor instruction_to_insert_before = 2;
// A fresh id for the copied object
- uint32 fresh_id = 4;
+ uint32 fresh_id = 3;
}
@@ -325,25 +389,6 @@
uint32 block_id = 1;
}
-message TransformationReplaceConstantWithUniform {
-
- // Replaces a use of a constant id with the the result of a load from an
- // element of uniform buffer known to hold the same value as the constant
-
- // A descriptor for the id we would like to replace
- IdUseDescriptor id_use_descriptor = 1;
-
- // Uniform descriptor to identify which uniform value to choose
- UniformBufferElementDescriptor uniform_descriptor = 2;
-
- // Id that will store the result of an access chain
- uint32 fresh_id_for_access_chain = 3;
-
- // Id that will store the result of a load
- uint32 fresh_id_for_load = 4;
-
-}
-
message TransformationReplaceBooleanConstantWithConstantBinary {
// A transformation to capture replacing a use of a boolean constant with
@@ -366,17 +411,117 @@
}
+message TransformationReplaceConstantWithUniform {
+
+ // Replaces a use of a constant id with the result of a load from an
+ // element of uniform buffer known to hold the same value as the constant
+
+ // A descriptor for the id we would like to replace
+ IdUseDescriptor id_use_descriptor = 1;
+
+ // Uniform descriptor to identify which uniform value to choose
+ UniformBufferElementDescriptor uniform_descriptor = 2;
+
+ // Id that will store the result of an access chain
+ uint32 fresh_id_for_access_chain = 3;
+
+ // Id that will store the result of a load
+ uint32 fresh_id_for_load = 4;
+
+}
+
+message TransformationReplaceIdWithSynonym {
+
+ // Replaces a use of an id with an id that is known to be synonymous, e.g.
+ // because it was obtained via applying OpCopyObject
+
+ // The id use that is to be replaced
+ IdUseDescriptor id_use_descriptor = 1;
+
+ // The synonymous id
+ uint32 synonymous_id = 2;
+
+}
+
+message TransformationSetFunctionControl {
+
+ // A transformation that sets the function control operand of an OpFunction
+ // instruction.
+
+ // The result id of an OpFunction instruction
+ uint32 function_id = 1;
+
+ // The value to which the 'function control' operand should be set.
+ uint32 function_control = 2;
+
+}
+
+message TransformationSetLoopControl {
+
+ // A transformation that sets the loop control operand of an OpLoopMerge
+ // instruction.
+
+ // The id of a basic block that should contain OpLoopMerge
+ uint32 block_id = 1;
+
+ // The value to which the 'loop control' operand should be set.
+ // This must be a legal loop control mask.
+ uint32 loop_control = 2;
+
+ // Provides a peel count value for the loop. Used if and only if the
+ // PeelCount bit is set. Must be zero if the PeelCount bit is not set (can
+ // still be zero if this bit is set).
+ uint32 peel_count = 3;
+
+ // Provides a partial count value for the loop. Used if and only if the
+ // PartialCount bit is set. Must be zero if the PartialCount bit is not set
+ // (can still be zero if this bit is set).
+ uint32 partial_count = 4;
+
+}
+
+message TransformationSetMemoryOperandsMask {
+
+ // A transformation that sets the memory operands mask of a memory access
+ // instruction.
+
+ // A descriptor for a memory access instruction, e.g. an OpLoad
+ InstructionDescriptor memory_access_instruction = 1;
+
+ // A mask of memory operands to be applied to the instruction. It must be the
+ // same as the original mask, except that Volatile can be added, and
+ // Nontemporal can be added or removed.
+ uint32 memory_operands_mask = 2;
+
+ // Some memory access instructions allow more than one mask to be specified;
+ // this field indicates which mask should be set
+ uint32 memory_operands_mask_index = 3;
+
+}
+
+message TransformationSetSelectionControl {
+
+ // A transformation that sets the selection control operand of an
+ // OpSelectionMerge instruction.
+
+ // The id of a basic block that should contain OpSelectionMerge
+ uint32 block_id = 1;
+
+ // The value to which the 'selection control' operand should be set.
+ // Although technically 'selection control' is a literal mask that can be
+ // some combination of 'None', 'Flatten' and 'DontFlatten', the combination
+ // 'Flatten | DontFlatten' does not make sense and is not allowed here.
+ uint32 selection_control = 2;
+
+}
+
message TransformationSplitBlock {
// A transformation that splits a basic block into two basic blocks
- // The result id of an instruction
- uint32 base_instruction_id = 1;
-
- // An offset, such that the block containing |base_instruction_id| should be
- // split right before the instruction |offset| instructions after
- // |base_instruction_id|
- uint32 offset = 2;
+ // A descriptor for an instruction such that the block containing the
+ // described instruction should be split right before the instruction.
+ InstructionDescriptor instruction_to_split_before = 1;
// An id that must not yet be used by the module to which this transformation
// is applied. Rather than having the transformation choose a suitable id on
@@ -386,6 +531,28 @@
// transformation, and if we end up changing what that id is, due to removing
// earlier transformations, it may inhibit later transformations from
// applying.
- uint32 fresh_id = 3;
+ uint32 fresh_id = 2;
+
+}
+
+message TransformationVectorShuffle {
+
+ // A transformation that adds a vector shuffle instruction.
+
+ // A descriptor for an instruction in a block before which the new
+ // OpVectorShuffle instruction should be inserted
+ InstructionDescriptor instruction_to_insert_before = 1;
+
+ // Result id for the shuffle operation.
+ uint32 fresh_id = 2;
+
+ // Id of the first vector operand.
+ uint32 vector1 = 3;
+
+ // Id of the second vector operand.
+ uint32 vector2 = 4;
+
+ // Indices that indicate which components of the input vectors should be used.
+ repeated uint32 component = 5;
}
diff --git a/source/fuzz/replayer.cpp b/source/fuzz/replayer.cpp
index b0d4ee2..398ce59 100644
--- a/source/fuzz/replayer.cpp
+++ b/source/fuzz/replayer.cpp
@@ -37,13 +37,18 @@
namespace fuzz {
struct Replayer::Impl {
- explicit Impl(spv_target_env env) : target_env(env) {}
+ explicit Impl(spv_target_env env, bool validate)
+ : target_env(env), validate_during_replay(validate) {}
const spv_target_env target_env; // Target environment.
MessageConsumer consumer; // Message consumer.
+
+ const bool validate_during_replay; // Controls whether the validator should
+ // be run after every replay step.
};
-Replayer::Replayer(spv_target_env env) : impl_(MakeUnique<Impl>(env)) {}
+Replayer::Replayer(spv_target_env env, bool validate_during_replay)
+ : impl_(MakeUnique<Impl>(env, validate_during_replay)) {}
Replayer::~Replayer() = default;
@@ -80,6 +85,13 @@
impl_->target_env, impl_->consumer, binary_in.data(), binary_in.size());
assert(ir_context);
+ // For replay validation, we track the last valid SPIR-V binary that was
+ // observed. Initially this is the input binary.
+ std::vector<uint32_t> last_valid_binary;
+ if (impl_->validate_during_replay) {
+ last_valid_binary = binary_in;
+ }
+
FactManager fact_manager;
fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get());
@@ -93,6 +105,23 @@
// sequence of transformations that were applied.
transformation->Apply(ir_context.get(), &fact_manager);
*transformation_sequence_out->add_transformation() = message;
+
+ if (impl_->validate_during_replay) {
+ std::vector<uint32_t> binary_to_validate;
+ ir_context->module()->ToBinary(&binary_to_validate, false);
+
+ // Check whether the latest transformation led to a valid binary.
+ if (!tools.Validate(&binary_to_validate[0],
+ binary_to_validate.size())) {
+ impl_->consumer(SPV_MSG_INFO, nullptr, {},
+ "Binary became invalid during replay (set a "
+ "breakpoint to inspect); stopping.");
+ return Replayer::ReplayerResultStatus::kReplayValidationFailure;
+ }
+
+ // The binary was valid, so it becomes the latest valid binary.
+ last_valid_binary = std::move(binary_to_validate);
+ }
}
}
diff --git a/source/fuzz/replayer.h b/source/fuzz/replayer.h
index 13391d0..1d58bae 100644
--- a/source/fuzz/replayer.h
+++ b/source/fuzz/replayer.h
@@ -33,10 +33,11 @@
kComplete,
kFailedToCreateSpirvToolsInterface,
kInitialBinaryInvalid,
+ kReplayValidationFailure,
};
// Constructs a replayer from the given target environment.
- explicit Replayer(spv_target_env env);
+ explicit Replayer(spv_target_env env, bool validate_during_replay);
// Disables copy/move constructor/assignment operations.
Replayer(const Replayer&) = delete;
diff --git a/source/fuzz/shrinker.cpp b/source/fuzz/shrinker.cpp
index f8d8aa3..1bb92f1 100644
--- a/source/fuzz/shrinker.cpp
+++ b/source/fuzz/shrinker.cpp
@@ -60,16 +60,20 @@
} // namespace
struct Shrinker::Impl {
- explicit Impl(spv_target_env env, uint32_t limit)
- : target_env(env), step_limit(limit) {}
+ explicit Impl(spv_target_env env, uint32_t limit, bool validate)
+ : target_env(env), step_limit(limit), validate_during_replay(validate) {}
- const spv_target_env target_env; // Target environment.
- MessageConsumer consumer; // Message consumer.
- const uint32_t step_limit; // Step limit for reductions.
+ const spv_target_env target_env; // Target environment.
+ MessageConsumer consumer; // Message consumer.
+ const uint32_t step_limit; // Step limit for reductions.
+ const bool validate_during_replay; // Determines whether to check for
+ // validity during the replaying of
+ // transformations.
};
-Shrinker::Shrinker(spv_target_env env, uint32_t step_limit)
- : impl_(MakeUnique<Impl>(env, step_limit)) {}
+Shrinker::Shrinker(spv_target_env env, uint32_t step_limit,
+ bool validate_during_replay)
+ : impl_(MakeUnique<Impl>(env, step_limit, validate_during_replay)) {}
Shrinker::~Shrinker() = default;
@@ -109,7 +113,7 @@
// succeeds, (b) get the binary that results from running these
// transformations, and (c) get the subsequence of the initial transformations
// that actually apply (in principle this could be a strict subsequence).
- if (Replayer(impl_->target_env)
+ if (Replayer(impl_->target_env, impl_->validate_during_replay)
.Run(binary_in, initial_facts, transformation_sequence_in,
¤t_best_binary, ¤t_best_transformations) !=
Replayer::ReplayerResultStatus::kComplete) {
@@ -180,7 +184,7 @@
// transformations inapplicable.
std::vector<uint32_t> next_binary;
protobufs::TransformationSequence next_transformation_sequence;
- if (Replayer(impl_->target_env)
+ if (Replayer(impl_->target_env, false)
.Run(binary_in, initial_facts, transformations_with_chunk_removed,
&next_binary, &next_transformation_sequence) !=
Replayer::ReplayerResultStatus::kComplete) {
diff --git a/source/fuzz/shrinker.h b/source/fuzz/shrinker.h
index 72dd470..0163a53 100644
--- a/source/fuzz/shrinker.h
+++ b/source/fuzz/shrinker.h
@@ -50,7 +50,8 @@
const std::vector<uint32_t>& binary, uint32_t counter)>;
// Constructs a shrinker from the given target environment.
- Shrinker(spv_target_env env, uint32_t step_limit);
+ Shrinker(spv_target_env env, uint32_t step_limit,
+ bool validate_during_replay);
// Disables copy/move constructor/assignment operations.
Shrinker(const Shrinker&) = delete;
diff --git a/source/fuzz/transformation.cpp b/source/fuzz/transformation.cpp
index a252734..d8fc92f 100644
--- a/source/fuzz/transformation.cpp
+++ b/source/fuzz/transformation.cpp
@@ -16,19 +16,29 @@
#include <cassert>
+#include "source/fuzz/transformation_add_constant_boolean.h"
+#include "source/fuzz/transformation_add_constant_scalar.h"
+#include "source/fuzz/transformation_add_dead_break.h"
+#include "source/fuzz/transformation_add_dead_continue.h"
+#include "source/fuzz/transformation_add_no_contraction_decoration.h"
+#include "source/fuzz/transformation_add_type_boolean.h"
+#include "source/fuzz/transformation_add_type_float.h"
+#include "source/fuzz/transformation_add_type_int.h"
+#include "source/fuzz/transformation_add_type_pointer.h"
+#include "source/fuzz/transformation_composite_construct.h"
+#include "source/fuzz/transformation_composite_extract.h"
+#include "source/fuzz/transformation_copy_object.h"
+#include "source/fuzz/transformation_move_block_down.h"
+#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
+#include "source/fuzz/transformation_replace_constant_with_uniform.h"
+#include "source/fuzz/transformation_replace_id_with_synonym.h"
+#include "source/fuzz/transformation_set_function_control.h"
+#include "source/fuzz/transformation_set_loop_control.h"
+#include "source/fuzz/transformation_set_memory_operands_mask.h"
+#include "source/fuzz/transformation_set_selection_control.h"
+#include "source/fuzz/transformation_split_block.h"
+#include "source/fuzz/transformation_vector_shuffle.h"
#include "source/util/make_unique.h"
-#include "transformation_add_constant_boolean.h"
-#include "transformation_add_constant_scalar.h"
-#include "transformation_add_dead_break.h"
-#include "transformation_add_dead_continue.h"
-#include "transformation_add_type_boolean.h"
-#include "transformation_add_type_float.h"
-#include "transformation_add_type_int.h"
-#include "transformation_add_type_pointer.h"
-#include "transformation_move_block_down.h"
-#include "transformation_replace_boolean_constant_with_constant_binary.h"
-#include "transformation_replace_constant_with_uniform.h"
-#include "transformation_split_block.h"
namespace spvtools {
namespace fuzz {
@@ -49,6 +59,10 @@
case protobufs::Transformation::TransformationCase::kAddDeadContinue:
return MakeUnique<TransformationAddDeadContinue>(
message.add_dead_continue());
+ case protobufs::Transformation::TransformationCase::
+ kAddNoContractionDecoration:
+ return MakeUnique<TransformationAddNoContractionDecoration>(
+ message.add_no_contraction_decoration());
case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
return MakeUnique<TransformationAddTypeBoolean>(
message.add_type_boolean());
@@ -59,6 +73,14 @@
case protobufs::Transformation::TransformationCase::kAddTypePointer:
return MakeUnique<TransformationAddTypePointer>(
message.add_type_pointer());
+ case protobufs::Transformation::TransformationCase::kCompositeConstruct:
+ return MakeUnique<TransformationCompositeConstruct>(
+ message.composite_construct());
+ case protobufs::Transformation::TransformationCase::kCompositeExtract:
+ return MakeUnique<TransformationCompositeExtract>(
+ message.composite_extract());
+ case protobufs::Transformation::TransformationCase::kCopyObject:
+ return MakeUnique<TransformationCopyObject>(message.copy_object());
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
return MakeUnique<TransformationMoveBlockDown>(message.move_block_down());
case protobufs::Transformation::TransformationCase::
@@ -69,15 +91,31 @@
kReplaceConstantWithUniform:
return MakeUnique<TransformationReplaceConstantWithUniform>(
message.replace_constant_with_uniform());
+ case protobufs::Transformation::TransformationCase::kReplaceIdWithSynonym:
+ return MakeUnique<TransformationReplaceIdWithSynonym>(
+ message.replace_id_with_synonym());
+ case protobufs::Transformation::TransformationCase::kSetFunctionControl:
+ return MakeUnique<TransformationSetFunctionControl>(
+ message.set_function_control());
+ case protobufs::Transformation::TransformationCase::kSetLoopControl:
+ return MakeUnique<TransformationSetLoopControl>(
+ message.set_loop_control());
+ case protobufs::Transformation::TransformationCase::kSetMemoryOperandsMask:
+ return MakeUnique<TransformationSetMemoryOperandsMask>(
+ message.set_memory_operands_mask());
+ case protobufs::Transformation::TransformationCase::kSetSelectionControl:
+ return MakeUnique<TransformationSetSelectionControl>(
+ message.set_selection_control());
case protobufs::Transformation::TransformationCase::kSplitBlock:
return MakeUnique<TransformationSplitBlock>(message.split_block());
- default:
- assert(message.transformation_case() ==
- protobufs::Transformation::TRANSFORMATION_NOT_SET &&
- "Unhandled transformation type.");
+ case protobufs::Transformation::TransformationCase::kVectorShuffle:
+ return MakeUnique<TransformationVectorShuffle>(message.vector_shuffle());
+ case protobufs::Transformation::TRANSFORMATION_NOT_SET:
assert(false && "An unset transformation was encountered.");
return nullptr;
}
+ assert(false && "Should be unreachable as all cases must be handled above.");
+ return nullptr;
}
} // namespace fuzz
diff --git a/source/fuzz/transformation_add_dead_break.cpp b/source/fuzz/transformation_add_dead_break.cpp
index 229dc90..b244cf4 100644
--- a/source/fuzz/transformation_add_dead_break.cpp
+++ b/source/fuzz/transformation_add_dead_break.cpp
@@ -138,6 +138,13 @@
return false;
}
+ if (!fuzzerutil::BlockIsReachableInItsFunction(context, bb_to)) {
+ // If the target of the break is unreachable, we conservatively do not
+ // allow adding a dead break, to avoid the compilations that arise due to
+ // the lack of sensible dominance information for unreachable blocks.
+ return false;
+ }
+
// Check that |message_.from_block| ends with an unconditional branch.
if (bb_from->terminator()->opcode() != SpvOpBranch) {
// The block associated with the id does not end with an unconditional
@@ -162,9 +169,15 @@
return false;
}
- // Finally, check that adding the break would respect the rules of structured
+ // Check that adding the break would respect the rules of structured
// control flow.
- return AddingBreakRespectsStructuredControlFlow(context, bb_from);
+ if (!AddingBreakRespectsStructuredControlFlow(context, bb_from)) {
+ return false;
+ }
+
+ // Check that adding the break would not violate the property that a
+ // definition must dominate all of its uses.
+ return fuzzerutil::NewEdgeRespectsUseDefDominance(context, bb_from, bb_to);
}
void TransformationAddDeadBreak::Apply(opt::IRContext* context,
diff --git a/source/fuzz/transformation_add_dead_break.h b/source/fuzz/transformation_add_dead_break.h
index aeb4dbb..10d2cec 100644
--- a/source/fuzz/transformation_add_dead_break.h
+++ b/source/fuzz/transformation_add_dead_break.h
@@ -48,6 +48,8 @@
// the condition, and the ids in |message_.phi_ids| used to extend
// any OpPhi instructions at b as a result of the edge from a, must
// maintain validity of the module.
+ // In particular, the new branch must not lead to violations of the rule
+ // that a use must be dominated by its definition.
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
diff --git a/source/fuzz/transformation_add_dead_continue.cpp b/source/fuzz/transformation_add_dead_continue.cpp
index e3b3da2..e644b88 100644
--- a/source/fuzz/transformation_add_dead_continue.cpp
+++ b/source/fuzz/transformation_add_dead_continue.cpp
@@ -83,14 +83,22 @@
return false;
}
+ auto continue_block = context->cfg()->block(loop_header)->ContinueBlockId();
+
+ if (!fuzzerutil::BlockIsReachableInItsFunction(
+ context, context->cfg()->block(continue_block))) {
+ // If the loop's continue block is unreachable, we conservatively do not
+ // allow adding a dead continue, to avoid the compilations that arise due to
+ // the lack of sensible dominance information for unreachable blocks.
+ return false;
+ }
+
if (fuzzerutil::BlockIsInLoopContinueConstruct(context, message_.from_block(),
loop_header)) {
// We cannot jump to the continue target from the continue construct.
return false;
}
- auto continue_block = context->cfg()->block(loop_header)->ContinueBlockId();
-
if (context->GetStructuredCFGAnalysis()->IsMergeBlock(continue_block)) {
// A branch straight to the continue target that is also a merge block might
// break the property that a construct header must dominate its merge block
@@ -98,6 +106,13 @@
return false;
}
+ // Check that adding the continue would not violate the property that a
+ // definition must dominate all of its uses.
+ if (!fuzzerutil::NewEdgeRespectsUseDefDominance(
+ context, bb_from, context->cfg()->block(continue_block))) {
+ return false;
+ }
+
// The transformation is good if and only if the given phi ids are sufficient
// to extend relevant OpPhi instructions in the continue block.
return fuzzerutil::PhiIdsOkForNewEdge(context, bb_from,
diff --git a/source/fuzz/transformation_add_dead_continue.h b/source/fuzz/transformation_add_dead_continue.h
index e49e2a8..df6bb4c 100644
--- a/source/fuzz/transformation_add_dead_continue.h
+++ b/source/fuzz/transformation_add_dead_continue.h
@@ -36,6 +36,8 @@
// - |message_.from_block| must be the id of a block a in the given module.
// - a must be contained in a loop with continue target b
+ // - The continue target b must be dominated by the head of the loop in which
+ // it is contained
// - b must not be the merge block of a selection construct
// - if |message_.continue_condition_value| holds (does not hold) then
// OpConstantTrue (OpConstantFalse) must be present in the module
@@ -47,6 +49,9 @@
// as the condition, and the ids in |message_.phi_ids| used to extend any
// OpPhi instructions at b as a result of the edge from a, must maintain
// validity of the module.
+ // In particular, adding an edge from somewhere in the loop to the continue
+ // target must not prevent uses of ids in the continue target from being
+ // dominated by the definitions of those ids.
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
diff --git a/source/fuzz/transformation_add_no_contraction_decoration.cpp b/source/fuzz/transformation_add_no_contraction_decoration.cpp
new file mode 100644
index 0000000..7f22cc2
--- /dev/null
+++ b/source/fuzz/transformation_add_no_contraction_decoration.cpp
@@ -0,0 +1,110 @@
+// 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/fuzz/transformation_add_no_contraction_decoration.h"
+
+#include "source/fuzz/fuzzer_util.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationAddNoContractionDecoration::
+ TransformationAddNoContractionDecoration(
+ const spvtools::fuzz::protobufs::
+ TransformationAddNoContractionDecoration& message)
+ : message_(message) {}
+
+TransformationAddNoContractionDecoration::
+ TransformationAddNoContractionDecoration(uint32_t result_id) {
+ message_.set_result_id(result_id);
+}
+
+bool TransformationAddNoContractionDecoration::IsApplicable(
+ opt::IRContext* context,
+ const spvtools::fuzz::FactManager& /*unused*/) const {
+ // |message_.result_id| must be the id of an instruction.
+ auto instr = context->get_def_use_mgr()->GetDef(message_.result_id());
+ if (!instr) {
+ return false;
+ }
+ // The instruction must be arithmetic.
+ return IsArithmetic(instr->opcode());
+}
+
+void TransformationAddNoContractionDecoration::Apply(
+ opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
+ // Add a NoContraction decoration targeting |message_.result_id|.
+ context->get_decoration_mgr()->AddDecoration(message_.result_id(),
+ SpvDecorationNoContraction);
+}
+
+protobufs::Transformation TransformationAddNoContractionDecoration::ToMessage()
+ const {
+ protobufs::Transformation result;
+ *result.mutable_add_no_contraction_decoration() = message_;
+ return result;
+}
+
+bool TransformationAddNoContractionDecoration::IsArithmetic(uint32_t opcode) {
+ switch (opcode) {
+ case SpvOpSNegate:
+ case SpvOpFNegate:
+ case SpvOpIAdd:
+ case SpvOpFAdd:
+ case SpvOpISub:
+ case SpvOpFSub:
+ case SpvOpIMul:
+ case SpvOpFMul:
+ case SpvOpUDiv:
+ case SpvOpSDiv:
+ case SpvOpFDiv:
+ case SpvOpUMod:
+ case SpvOpSRem:
+ case SpvOpSMod:
+ case SpvOpFRem:
+ case SpvOpFMod:
+ case SpvOpVectorTimesScalar:
+ case SpvOpMatrixTimesScalar:
+ case SpvOpVectorTimesMatrix:
+ case SpvOpMatrixTimesVector:
+ case SpvOpMatrixTimesMatrix:
+ case SpvOpOuterProduct:
+ case SpvOpDot:
+ case SpvOpIAddCarry:
+ case SpvOpISubBorrow:
+ case SpvOpUMulExtended:
+ case SpvOpSMulExtended:
+ case SpvOpAny:
+ case SpvOpAll:
+ case SpvOpIsNan:
+ case SpvOpIsInf:
+ case SpvOpIsFinite:
+ case SpvOpIsNormal:
+ case SpvOpSignBitSet:
+ case SpvOpLessOrGreater:
+ case SpvOpOrdered:
+ case SpvOpUnordered:
+ case SpvOpLogicalEqual:
+ case SpvOpLogicalNotEqual:
+ case SpvOpLogicalOr:
+ case SpvOpLogicalAnd:
+ case SpvOpLogicalNot:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_add_no_contraction_decoration.h b/source/fuzz/transformation_add_no_contraction_decoration.h
new file mode 100644
index 0000000..cec1b2c
--- /dev/null
+++ b/source/fuzz/transformation_add_no_contraction_decoration.h
@@ -0,0 +1,58 @@
+// 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_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_
+#define SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationAddNoContractionDecoration : public Transformation {
+ public:
+ explicit TransformationAddNoContractionDecoration(
+ const protobufs::TransformationAddNoContractionDecoration& message);
+
+ explicit TransformationAddNoContractionDecoration(uint32_t fresh_id);
+
+ // - |message_.result_id| must be the result id of an arithmetic instruction,
+ // as defined by the SPIR-V specification.
+ // - It does not matter whether this instruction is already annotated with the
+ // NoContraction decoration.
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // Adds a decoration of the form:
+ // 'OpDecoration |message_.result_id| NoContraction'
+ // to the module.
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ // Returns true if and only if |opcode| is the opcode of an arithmetic
+ // instruction, as defined by the SPIR-V specification.
+ static bool IsArithmetic(uint32_t opcode);
+
+ private:
+ protobufs::TransformationAddNoContractionDecoration message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_
diff --git a/source/fuzz/transformation_composite_construct.cpp b/source/fuzz/transformation_composite_construct.cpp
new file mode 100644
index 0000000..7a3aff1
--- /dev/null
+++ b/source/fuzz/transformation_composite_construct.cpp
@@ -0,0 +1,305 @@
+// 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/fuzz/transformation_composite_construct.h"
+
+#include "source/fuzz/data_descriptor.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/opt/instruction.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationCompositeConstruct::TransformationCompositeConstruct(
+ const protobufs::TransformationCompositeConstruct& message)
+ : message_(message) {}
+
+TransformationCompositeConstruct::TransformationCompositeConstruct(
+ uint32_t composite_type_id, std::vector<uint32_t> component,
+ const protobufs::InstructionDescriptor& instruction_to_insert_before,
+ uint32_t fresh_id) {
+ message_.set_composite_type_id(composite_type_id);
+ for (auto a_component : component) {
+ message_.add_component(a_component);
+ }
+ *message_.mutable_instruction_to_insert_before() =
+ instruction_to_insert_before;
+ message_.set_fresh_id(fresh_id);
+}
+
+bool TransformationCompositeConstruct::IsApplicable(
+ opt::IRContext* context, const FactManager& /*fact_manager*/) const {
+ if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
+ // We require the id for the composite constructor to be unused.
+ return false;
+ }
+
+ auto insert_before =
+ FindInstruction(message_.instruction_to_insert_before(), context);
+ if (!insert_before) {
+ // The instruction before which the composite should be inserted was not
+ // found.
+ return false;
+ }
+
+ auto composite_type =
+ context->get_type_mgr()->GetType(message_.composite_type_id());
+
+ if (!fuzzerutil::IsCompositeType(composite_type)) {
+ // The type must actually be a composite.
+ return false;
+ }
+
+ // If the type is an array, matrix, struct or vector, the components need to
+ // be suitable for constructing something of that type.
+ if (composite_type->AsArray() && !ComponentsForArrayConstructionAreOK(
+ context, *composite_type->AsArray())) {
+ return false;
+ }
+ if (composite_type->AsMatrix() && !ComponentsForMatrixConstructionAreOK(
+ context, *composite_type->AsMatrix())) {
+ return false;
+ }
+ if (composite_type->AsStruct() && !ComponentsForStructConstructionAreOK(
+ context, *composite_type->AsStruct())) {
+ return false;
+ }
+ if (composite_type->AsVector() && !ComponentsForVectorConstructionAreOK(
+ context, *composite_type->AsVector())) {
+ return false;
+ }
+
+ // Now check whether every component being used to initialize the composite is
+ // available at the desired program point.
+ for (auto& component : message_.component()) {
+ auto component_inst = context->get_def_use_mgr()->GetDef(component);
+ if (!context->get_instr_block(component)) {
+ // The component does not have a block; that means it is in global scope,
+ // which is OK. (Whether the component actually corresponds to an
+ // instruction is checked above when determining whether types are
+ // suitable.)
+ continue;
+ }
+ // Check whether the component is available.
+ if (insert_before->HasResultId() &&
+ insert_before->result_id() == component) {
+ // This constitutes trying to use an id right before it is defined. The
+ // special case is needed due to an instruction always dominating itself.
+ return false;
+ }
+ if (!context
+ ->GetDominatorAnalysis(
+ context->get_instr_block(&*insert_before)->GetParent())
+ ->Dominates(component_inst, &*insert_before)) {
+ // The instruction defining the component must dominate the instruction we
+ // wish to insert the composite before.
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void TransformationCompositeConstruct::Apply(opt::IRContext* context,
+ FactManager* fact_manager) const {
+ // Use the base and offset information from the transformation to determine
+ // where in the module a new instruction should be inserted.
+ auto insert_before_inst =
+ FindInstruction(message_.instruction_to_insert_before(), context);
+ auto destination_block = context->get_instr_block(insert_before_inst);
+ auto insert_before = fuzzerutil::GetIteratorForInstruction(
+ destination_block, insert_before_inst);
+
+ // Prepare the input operands for an OpCompositeConstruct instruction.
+ opt::Instruction::OperandList in_operands;
+ for (auto& component_id : message_.component()) {
+ in_operands.push_back({SPV_OPERAND_TYPE_ID, {component_id}});
+ }
+
+ // Insert an OpCompositeConstruct instruction.
+ insert_before.InsertBefore(MakeUnique<opt::Instruction>(
+ context, SpvOpCompositeConstruct, message_.composite_type_id(),
+ message_.fresh_id(), in_operands));
+
+ fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
+ context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
+
+ // Inform the fact manager that we now have new synonyms: every component of
+ // the composite is synonymous with the id used to construct that component,
+ // except in the case of a vector where a single vector id can span multiple
+ // components.
+ auto composite_type =
+ context->get_type_mgr()->GetType(message_.composite_type_id());
+ uint32_t index = 0;
+ for (auto component : message_.component()) {
+ auto component_type = context->get_type_mgr()->GetType(
+ context->get_def_use_mgr()->GetDef(component)->type_id());
+ if (composite_type->AsVector() && component_type->AsVector()) {
+ // The case where the composite being constructed is a vector and the
+ // component provided for construction is also a vector is special. It
+ // requires adding a synonym fact relating each element of the sub-vector
+ // to the corresponding element of the composite being constructed.
+ assert(component_type->AsVector()->element_type() ==
+ composite_type->AsVector()->element_type());
+ assert(component_type->AsVector()->element_count() <
+ composite_type->AsVector()->element_count());
+ for (uint32_t subvector_index = 0;
+ subvector_index < component_type->AsVector()->element_count();
+ subvector_index++) {
+ fact_manager->AddFactDataSynonym(
+ MakeDataDescriptor(component, {subvector_index}),
+ MakeDataDescriptor(message_.fresh_id(), {index}), context);
+ index++;
+ }
+ } else {
+ // The other cases are simple: the component is made directly synonymous
+ // with the element of the composite being constructed.
+ fact_manager->AddFactDataSynonym(
+ MakeDataDescriptor(component, {}),
+ MakeDataDescriptor(message_.fresh_id(), {index}), context);
+ index++;
+ }
+ }
+}
+
+bool TransformationCompositeConstruct::ComponentsForArrayConstructionAreOK(
+ opt::IRContext* context, const opt::analysis::Array& array_type) const {
+ if (array_type.length_info().words[0] !=
+ opt::analysis::Array::LengthInfo::kConstant) {
+ // We only handle constant-sized arrays.
+ return false;
+ }
+ if (array_type.length_info().words.size() != 2) {
+ // We only handle the case where the array size can be captured in a single
+ // word.
+ return false;
+ }
+ // Get the array size.
+ auto array_size = array_type.length_info().words[1];
+ if (static_cast<uint32_t>(message_.component().size()) != array_size) {
+ // The number of components must match the array size.
+ return false;
+ }
+ // Check that each component is the result id of an instruction whose type is
+ // the array's element type.
+ for (auto component_id : message_.component()) {
+ auto inst = context->get_def_use_mgr()->GetDef(component_id);
+ if (inst == nullptr || !inst->type_id()) {
+ // The component does not correspond to an instruction with a result
+ // type.
+ return false;
+ }
+ auto component_type = context->get_type_mgr()->GetType(inst->type_id());
+ assert(component_type);
+ if (component_type != array_type.element_type()) {
+ // The component's type does not match the array's element type.
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TransformationCompositeConstruct::ComponentsForMatrixConstructionAreOK(
+ opt::IRContext* context, const opt::analysis::Matrix& matrix_type) const {
+ if (static_cast<uint32_t>(message_.component().size()) !=
+ matrix_type.element_count()) {
+ // The number of components must match the number of columns of the matrix.
+ return false;
+ }
+ // Check that each component is the result id of an instruction whose type is
+ // the matrix's column type.
+ for (auto component_id : message_.component()) {
+ auto inst = context->get_def_use_mgr()->GetDef(component_id);
+ if (inst == nullptr || !inst->type_id()) {
+ // The component does not correspond to an instruction with a result
+ // type.
+ return false;
+ }
+ auto component_type = context->get_type_mgr()->GetType(inst->type_id());
+ assert(component_type);
+ if (component_type != matrix_type.element_type()) {
+ // The component's type does not match the matrix's column type.
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TransformationCompositeConstruct::ComponentsForStructConstructionAreOK(
+ opt::IRContext* context, const opt::analysis::Struct& struct_type) const {
+ if (static_cast<uint32_t>(message_.component().size()) !=
+ struct_type.element_types().size()) {
+ // The number of components must match the number of fields of the struct.
+ return false;
+ }
+ // Check that each component is the result id of an instruction those type
+ // matches the associated field type.
+ for (uint32_t field_index = 0;
+ field_index < struct_type.element_types().size(); field_index++) {
+ auto inst =
+ context->get_def_use_mgr()->GetDef(message_.component()[field_index]);
+ if (inst == nullptr || !inst->type_id()) {
+ // The component does not correspond to an instruction with a result
+ // type.
+ return false;
+ }
+ auto component_type = context->get_type_mgr()->GetType(inst->type_id());
+ assert(component_type);
+ if (component_type != struct_type.element_types()[field_index]) {
+ // The component's type does not match the corresponding field type.
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TransformationCompositeConstruct::ComponentsForVectorConstructionAreOK(
+ opt::IRContext* context, const opt::analysis::Vector& vector_type) const {
+ uint32_t base_element_count = 0;
+ auto element_type = vector_type.element_type();
+ for (auto& component_id : message_.component()) {
+ auto inst = context->get_def_use_mgr()->GetDef(component_id);
+ if (inst == nullptr || !inst->type_id()) {
+ // The component does not correspond to an instruction with a result
+ // type.
+ return false;
+ }
+ auto component_type = context->get_type_mgr()->GetType(inst->type_id());
+ assert(component_type);
+ if (component_type == element_type) {
+ base_element_count++;
+ } else if (component_type->AsVector() &&
+ component_type->AsVector()->element_type() == element_type) {
+ base_element_count += component_type->AsVector()->element_count();
+ } else {
+ // The component was not appropriate; e.g. no type corresponding to the
+ // given id was found, or the type that was found was not compatible
+ // with the vector being constructed.
+ return false;
+ }
+ }
+ // The number of components provided (when vector components are flattened
+ // out) needs to match the length of the vector being constructed.
+ return base_element_count == vector_type.element_count();
+}
+
+protobufs::Transformation TransformationCompositeConstruct::ToMessage() const {
+ protobufs::Transformation result;
+ *result.mutable_composite_construct() = message_;
+ return result;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_composite_construct.h b/source/fuzz/transformation_composite_construct.h
new file mode 100644
index 0000000..5369c4c
--- /dev/null
+++ b/source/fuzz/transformation_composite_construct.h
@@ -0,0 +1,88 @@
+// 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_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_
+#define SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationCompositeConstruct : public Transformation {
+ public:
+ explicit TransformationCompositeConstruct(
+ const protobufs::TransformationCompositeConstruct& message);
+
+ TransformationCompositeConstruct(
+ uint32_t composite_type_id, std::vector<uint32_t> component,
+ const protobufs::InstructionDescriptor& instruction_to_insert_before,
+ uint32_t fresh_id);
+
+ // - |message_.fresh_id| must not be used by the module.
+ // - |message_.composite_type_id| must be the id of a composite type
+ // - The elements of |message_.component| must be result ids that are
+ // suitable for constructing an element of the given composite type, in
+ // order
+ // - The elements of |message_.component| must not be the target of any
+ // decorations.
+ // - |message_.base_instruction_id| must be the result id of an instruction
+ // 'base' in some block 'blk'.
+ // - 'blk' must contain an instruction 'inst' located |message_.offset|
+ // instructions after 'base' (if |message_.offset| = 0 then 'inst' =
+ // 'base').
+ // - It must be legal to insert an OpCompositeConstruct instruction directly
+ // before 'inst'.
+ // - Each element of |message_.component| must be available directly before
+ // 'inst'.
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // Inserts a new OpCompositeConstruct instruction, with id
+ // |message_.fresh_id|, directly before the instruction identified by
+ // |message_.base_instruction_id| and |message_.offset|. The instruction
+ // creates a composite of type |message_.composite_type_id| using the ids of
+ // |message_.component|.
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ private:
+ // Helper to decide whether the components of the transformation are suitable
+ // for constructing an array of the given type.
+ bool ComponentsForArrayConstructionAreOK(
+ opt::IRContext* context, const opt::analysis::Array& array_type) const;
+
+ // Similar, but for matrices.
+ bool ComponentsForMatrixConstructionAreOK(
+ opt::IRContext* context, const opt::analysis::Matrix& matrix_type) const;
+
+ // Similar, but for structs.
+ bool ComponentsForStructConstructionAreOK(
+ opt::IRContext* context, const opt::analysis::Struct& struct_type) const;
+
+ // Similar, but for vectors.
+ bool ComponentsForVectorConstructionAreOK(
+ opt::IRContext* context, const opt::analysis::Vector& vector_type) const;
+
+ protobufs::TransformationCompositeConstruct message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_
diff --git a/source/fuzz/transformation_composite_extract.cpp b/source/fuzz/transformation_composite_extract.cpp
new file mode 100644
index 0000000..5d3a386
--- /dev/null
+++ b/source/fuzz/transformation_composite_extract.cpp
@@ -0,0 +1,125 @@
+// 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/fuzz/transformation_composite_extract.h"
+
+#include <vector>
+
+#include "source/fuzz/data_descriptor.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationCompositeExtract::TransformationCompositeExtract(
+ const spvtools::fuzz::protobufs::TransformationCompositeExtract& message)
+ : message_(message) {}
+
+TransformationCompositeExtract::TransformationCompositeExtract(
+ const protobufs::InstructionDescriptor& instruction_to_insert_before,
+ uint32_t fresh_id, uint32_t composite_id, std::vector<uint32_t>&& index) {
+ *message_.mutable_instruction_to_insert_before() =
+ instruction_to_insert_before;
+ message_.set_fresh_id(fresh_id);
+ message_.set_composite_id(composite_id);
+ for (auto an_index : index) {
+ message_.add_index(an_index);
+ }
+}
+
+bool TransformationCompositeExtract::IsApplicable(
+ opt::IRContext* context,
+ const spvtools::fuzz::FactManager& /*unused*/) const {
+ if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
+ return false;
+ }
+ auto instruction_to_insert_before =
+ FindInstruction(message_.instruction_to_insert_before(), context);
+ if (!instruction_to_insert_before) {
+ return false;
+ }
+ auto composite_instruction =
+ context->get_def_use_mgr()->GetDef(message_.composite_id());
+ if (!composite_instruction) {
+ return false;
+ }
+ if (auto block = context->get_instr_block(composite_instruction)) {
+ if (composite_instruction == instruction_to_insert_before ||
+ !context->GetDominatorAnalysis(block->GetParent())
+ ->Dominates(composite_instruction, instruction_to_insert_before)) {
+ return false;
+ }
+ }
+ assert(composite_instruction->type_id() &&
+ "An instruction in a block cannot have a result id but no type id.");
+
+ auto composite_type =
+ context->get_type_mgr()->GetType(composite_instruction->type_id());
+ if (!composite_type) {
+ return false;
+ }
+
+ if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
+ SpvOpCompositeExtract, instruction_to_insert_before)) {
+ return false;
+ }
+
+ return fuzzerutil::WalkCompositeTypeIndices(
+ context, composite_instruction->type_id(), message_.index()) != 0;
+}
+
+void TransformationCompositeExtract::Apply(
+ opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const {
+ opt::Instruction::OperandList extract_operands;
+ extract_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.composite_id()}});
+ for (auto an_index : message_.index()) {
+ extract_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {an_index}});
+ }
+ auto composite_instruction =
+ context->get_def_use_mgr()->GetDef(message_.composite_id());
+ auto extracted_type = fuzzerutil::WalkCompositeTypeIndices(
+ context, composite_instruction->type_id(), message_.index());
+
+ FindInstruction(message_.instruction_to_insert_before(), context)
+ ->InsertBefore(MakeUnique<opt::Instruction>(
+ context, SpvOpCompositeExtract, extracted_type, message_.fresh_id(),
+ extract_operands));
+
+ fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
+
+ context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
+
+ // Add the fact that the id storing the extracted element is synonymous with
+ // the index into the structure.
+ std::vector<uint32_t> indices;
+ for (auto an_index : message_.index()) {
+ indices.push_back(an_index);
+ }
+ protobufs::DataDescriptor data_descriptor_for_extracted_element =
+ MakeDataDescriptor(message_.composite_id(), std::move(indices));
+ protobufs::DataDescriptor data_descriptor_for_result_id =
+ MakeDataDescriptor(message_.fresh_id(), {});
+ fact_manager->AddFactDataSynonym(data_descriptor_for_extracted_element,
+ data_descriptor_for_result_id, context);
+}
+
+protobufs::Transformation TransformationCompositeExtract::ToMessage() const {
+ protobufs::Transformation result;
+ *result.mutable_composite_extract() = message_;
+ return result;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_composite_extract.h b/source/fuzz/transformation_composite_extract.h
new file mode 100644
index 0000000..c4c9278
--- /dev/null
+++ b/source/fuzz/transformation_composite_extract.h
@@ -0,0 +1,63 @@
+// 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_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_
+#define SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationCompositeExtract : public Transformation {
+ public:
+ explicit TransformationCompositeExtract(
+ const protobufs::TransformationCompositeExtract& message);
+
+ TransformationCompositeExtract(
+ const protobufs::InstructionDescriptor& instruction_to_insert_before,
+ uint32_t fresh_id, uint32_t composite_id, std::vector<uint32_t>&& index);
+
+ // - |message_.fresh_id| must be available
+ // - |message_.instruction_to_insert_before| must identify an instruction
+ // before which it is valid to place an OpCompositeExtract
+ // - |message_.composite_id| must be the id of an instruction that defines
+ // a composite object, and this id must be available at the instruction
+ // identified by |message_.instruction_to_insert_before|
+ // - |message_.index| must be a suitable set of indices for
+ // |message_.composite_id|, i.e. it must be possible to follow this chain
+ // of indices to reach a sub-object of |message_.composite_id|
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // Adds an OpCompositeConstruct instruction before the instruction identified
+ // by |message_.instruction_to_insert_before|, that extracts from
+ // |message_.composite_id| via indices |message_.index| into
+ // |message_.fresh_id|. Generates a data synonym fact relating
+ // |message_.fresh_id| to the extracted element.
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ private:
+ protobufs::TransformationCompositeExtract message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_
diff --git a/source/fuzz/transformation_copy_object.cpp b/source/fuzz/transformation_copy_object.cpp
index f9ead43..af1e81c 100644
--- a/source/fuzz/transformation_copy_object.cpp
+++ b/source/fuzz/transformation_copy_object.cpp
@@ -14,7 +14,9 @@
#include "source/fuzz/transformation_copy_object.h"
+#include "source/fuzz/data_descriptor.h"
#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
#include "source/opt/instruction.h"
#include "source/util/make_unique.h"
@@ -25,13 +27,13 @@
const protobufs::TransformationCopyObject& message)
: message_(message) {}
-TransformationCopyObject::TransformationCopyObject(uint32_t object,
- uint32_t base_instruction_id,
- uint32_t offset,
- uint32_t fresh_id) {
+TransformationCopyObject::TransformationCopyObject(
+ uint32_t object,
+ const protobufs::InstructionDescriptor& instruction_to_insert_before,
+ uint32_t fresh_id) {
message_.set_object(object);
- message_.set_base_instruction_id(base_instruction_id);
- message_.set_offset(offset);
+ *message_.mutable_instruction_to_insert_before() =
+ instruction_to_insert_before;
message_.set_fresh_id(fresh_id);
}
@@ -46,57 +48,22 @@
if (!object_inst) {
return false;
}
- if (!object_inst->type_id()) {
- // We can only apply OpCopyObject to instructions that have types.
- return false;
- }
- if (!context->get_decoration_mgr()
- ->GetDecorationsFor(message_.object(), true)
- .empty()) {
- // We do not copy objects that have decorations: if the copy is not
- // decorated analogously, using the original object vs. its copy may not be
- // equivalent.
- // TODO(afd): it would be possible to make the copy but not add an id
- // synonym.
+ if (!fuzzerutil::CanMakeSynonymOf(context, object_inst)) {
return false;
}
- auto base_instruction =
- context->get_def_use_mgr()->GetDef(message_.base_instruction_id());
- if (!base_instruction) {
- // The given id to insert after is not defined.
+ auto insert_before =
+ FindInstruction(message_.instruction_to_insert_before(), context);
+ if (!insert_before) {
+ // The instruction before which the copy should be inserted was not found.
return false;
}
- auto destination_block = context->get_instr_block(base_instruction);
- if (!destination_block) {
- // The given id to insert after is not in a block.
+ if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject,
+ insert_before)) {
return false;
}
- auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset(
- destination_block, base_instruction, message_.offset());
-
- if (insert_before == destination_block->end()) {
- // The offset was inappropriate.
- return false;
- }
- if (insert_before->PreviousNode() &&
- (insert_before->PreviousNode()->opcode() == SpvOpLoopMerge ||
- insert_before->PreviousNode()->opcode() == SpvOpSelectionMerge)) {
- // We cannot insert a copy directly after a merge instruction.
- return false;
- }
- if (insert_before->opcode() == SpvOpVariable) {
- // We cannot insert a copy directly before a variable; variables in a
- // function must be contiguous in the entry block.
- return false;
- }
- // We cannot insert a copy directly before OpPhi, because OpPhi instructions
- // need to be contiguous at the start of a block.
- if (insert_before->opcode() == SpvOpPhi) {
- return false;
- }
// |message_object| must be available at the point where we want to add the
// copy. It is available if it is at global scope (in which case it has no
// block), or if it dominates the point of insertion but is different from the
@@ -107,28 +74,22 @@
// insert it before the object's defining instruction.
return !context->get_instr_block(object_inst) ||
(object_inst != &*insert_before &&
- context->GetDominatorAnalysis(destination_block->GetParent())
+ context
+ ->GetDominatorAnalysis(
+ context->get_instr_block(insert_before)->GetParent())
->Dominates(object_inst, &*insert_before));
}
void TransformationCopyObject::Apply(opt::IRContext* context,
FactManager* fact_manager) const {
- // - A new instruction,
- // %|message_.fresh_id| = OpCopyObject %ty %|message_.object|
- // is added directly before the instruction at |message_.insert_after_id| +
- // |message_|.offset, where %ty is the type of |message_.object|.
- // - The fact that |message_.fresh_id| and |message_.object| are synonyms
- // is added to the fact manager.
- // The id of the object to be copied must exist
auto object_inst = context->get_def_use_mgr()->GetDef(message_.object());
assert(object_inst && "The object to be copied must exist.");
- auto base_instruction =
- context->get_def_use_mgr()->GetDef(message_.base_instruction_id());
- assert(base_instruction && "The base instruction must exist.");
- auto destination_block = context->get_instr_block(base_instruction);
+ auto insert_before_inst =
+ FindInstruction(message_.instruction_to_insert_before(), context);
+ auto destination_block = context->get_instr_block(insert_before_inst);
assert(destination_block && "The base instruction must be in a block.");
- auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset(
- destination_block, base_instruction, message_.offset());
+ auto insert_before = fuzzerutil::GetIteratorForInstruction(
+ destination_block, insert_before_inst);
assert(insert_before != destination_block->end() &&
"There must be an instruction before which the copy can be inserted.");
@@ -141,11 +102,9 @@
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
- protobufs::Fact fact;
- fact.mutable_id_synonym_fact()->set_id(message_.object());
- fact.mutable_id_synonym_fact()->mutable_data_descriptor()->set_object(
- message_.fresh_id());
- fact_manager->AddFact(fact, context);
+ fact_manager->AddFactDataSynonym(MakeDataDescriptor(message_.object(), {}),
+ MakeDataDescriptor(message_.fresh_id(), {}),
+ context);
}
protobufs::Transformation TransformationCopyObject::ToMessage() const {
diff --git a/source/fuzz/transformation_copy_object.h b/source/fuzz/transformation_copy_object.h
index 6ce72df..3a75ac9 100644
--- a/source/fuzz/transformation_copy_object.h
+++ b/source/fuzz/transformation_copy_object.h
@@ -28,8 +28,10 @@
explicit TransformationCopyObject(
const protobufs::TransformationCopyObject& message);
- TransformationCopyObject(uint32_t fresh_id, uint32_t object,
- uint32_t insert_after_id, uint32_t offset);
+ TransformationCopyObject(
+ uint32_t object,
+ const protobufs::InstructionDescriptor& instruction_to_insert_before,
+ uint32_t fresh_id);
// - |message_.fresh_id| must not be used by the module.
// - |message_.object| must be a result id that is a legitimate operand for
@@ -37,14 +39,14 @@
// has a result type
// - |message_.object| must not be the target of any decoration.
// TODO(afd): consider copying decorations along with objects.
- // - |message_.insert_after_id| must be the result id of an instruction
+ // - |message_.base_instruction_id| must be the result id of an instruction
// 'base' in some block 'blk'.
// - 'blk' must contain an instruction 'inst' located |message_.offset|
// instructions after 'base' (if |message_.offset| = 0 then 'inst' =
// 'base').
// - It must be legal to insert an OpCopyObject instruction directly
// before 'inst'.
- // - |message_object| must be available directly before 'inst'.
+ // - |message_.object| must be available directly before 'inst'.
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
diff --git a/source/fuzz/transformation_move_block_down.cpp b/source/fuzz/transformation_move_block_down.cpp
index ebce185..f181855 100644
--- a/source/fuzz/transformation_move_block_down.cpp
+++ b/source/fuzz/transformation_move_block_down.cpp
@@ -84,12 +84,12 @@
"To be able to move a block down, it needs to have a "
"program-order successor.");
function.MoveBasicBlockToAfter(message_.block_id(), &*block_it);
- // It is prudent to invalidate analyses after changing block ordering in
- // case any of them depend on it, but the ones that definitely do not
- // depend on ordering can be preserved. These include the following,
- // which can likely be extended.
+ // For performance, it is vital to keep the dominator analysis valid
+ // (which due to https://github.com/KhronosGroup/SPIRV-Tools/issues/2889
+ // requires keeping the CFG analysis valid).
context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisDefUse |
+ opt::IRContext::Analysis::kAnalysisCFG |
opt::IRContext::Analysis::kAnalysisDominatorAnalysis);
return;
diff --git a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp
index 91b4007..b097767 100644
--- a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp
+++ b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp
@@ -178,7 +178,7 @@
context->get_constant_mgr()->FindDeclaredConstant(message_.rhs_id());
bool expected_result = (boolean_constant->opcode() == SpvOpConstantTrue);
- const SpvOp binary_opcode = static_cast<SpvOp>(message_.opcode());
+ const auto binary_opcode = static_cast<SpvOp>(message_.opcode());
// We consider the floating point, signed and unsigned integer cases
// separately. In each case the logic is very similar.
@@ -237,8 +237,17 @@
}
// The id use descriptor must identify some instruction
- return transformation::FindInstruction(message_.id_use_descriptor(),
- context) != nullptr;
+ auto instruction =
+ FindInstructionContainingUse(message_.id_use_descriptor(), context);
+ if (instruction == nullptr) {
+ return false;
+ }
+
+ // The instruction must not be an OpPhi, as we cannot insert a binary
+ // operator instruction before an OpPhi.
+ // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2902): there is
+ // scope for being less conservative.
+ return instruction->opcode() != SpvOpPhi;
}
void TransformationReplaceBooleanConstantWithConstantBinary::Apply(
@@ -259,7 +268,7 @@
message_.fresh_id_for_binary_operation(), operands);
opt::Instruction* result = binary_instruction.get();
auto instruction_containing_constant_use =
- transformation::FindInstruction(message_.id_use_descriptor(), context);
+ FindInstructionContainingUse(message_.id_use_descriptor(), context);
// We want to insert the new instruction before the instruction that contains
// the use of the boolean, but we need to go backwards one more instruction if
diff --git a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h
index c384093..f74cd8d 100644
--- a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h
+++ b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h
@@ -43,6 +43,12 @@
// - |message_.opcode| must be suitable for applying to |message.lhs_id| and
// |message_.rhs_id|, and the result must evaluate to the boolean constant
// c.
+ // - The boolean constant usage must not be an argument to OpPhi, because in
+ // this case it is not legal to insert a binary operator instruction right
+ // before the OpPhi.
+ // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2902): consider
+ // replacing a boolean in an OpPhi by adding a binary operator instruction
+ // to the parent block for the OpPhi.
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
diff --git a/source/fuzz/transformation_replace_constant_with_uniform.cpp b/source/fuzz/transformation_replace_constant_with_uniform.cpp
index 48334ba..405776e 100644
--- a/source/fuzz/transformation_replace_constant_with_uniform.cpp
+++ b/source/fuzz/transformation_replace_constant_with_uniform.cpp
@@ -149,7 +149,7 @@
// The id use descriptor must identify some instruction with respect to the
// module.
auto instruction_using_constant =
- transformation::FindInstruction(message_.id_use_descriptor(), context);
+ FindInstructionContainingUse(message_.id_use_descriptor(), context);
if (!instruction_using_constant) {
return false;
}
@@ -188,7 +188,7 @@
spvtools::fuzz::FactManager* /*unused*/) const {
// Get the instruction that contains the id use we wish to replace.
auto instruction_containing_constant_use =
- transformation::FindInstruction(message_.id_use_descriptor(), context);
+ FindInstructionContainingUse(message_.id_use_descriptor(), context);
assert(instruction_containing_constant_use &&
"Precondition requires that the id use can be found.");
assert(instruction_containing_constant_use->GetSingleWordInOperand(
diff --git a/source/fuzz/transformation_replace_id_with_synonym.cpp b/source/fuzz/transformation_replace_id_with_synonym.cpp
new file mode 100644
index 0000000..79ba012
--- /dev/null
+++ b/source/fuzz/transformation_replace_id_with_synonym.cpp
@@ -0,0 +1,195 @@
+// 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/fuzz/transformation_replace_id_with_synonym.h"
+
+#include <algorithm>
+
+#include "source/fuzz/data_descriptor.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/id_use_descriptor.h"
+#include "source/opt/types.h"
+#include "source/util/make_unique.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym(
+ const spvtools::fuzz::protobufs::TransformationReplaceIdWithSynonym&
+ message)
+ : message_(message) {}
+
+TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym(
+ protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id) {
+ *message_.mutable_id_use_descriptor() = std::move(id_use_descriptor);
+ message_.set_synonymous_id(synonymous_id);
+}
+
+bool TransformationReplaceIdWithSynonym::IsApplicable(
+ spvtools::opt::IRContext* context,
+ const spvtools::fuzz::FactManager& fact_manager) const {
+ auto id_of_interest = message_.id_use_descriptor().id_of_interest();
+
+ // Does the fact manager know about the synonym?
+ auto data_descriptor_for_synonymous_id =
+ MakeDataDescriptor(message_.synonymous_id(), {});
+ if (!fact_manager.IsSynonymous(MakeDataDescriptor(id_of_interest, {}),
+ data_descriptor_for_synonymous_id, context)) {
+ return false;
+ }
+
+ // Does the id use descriptor in the transformation identify an instruction?
+ auto use_instruction =
+ FindInstructionContainingUse(message_.id_use_descriptor(), context);
+ if (!use_instruction) {
+ return false;
+ }
+
+ // Is the use suitable for being replaced in principle?
+ if (!UseCanBeReplacedWithSynonym(
+ context, use_instruction,
+ message_.id_use_descriptor().in_operand_index())) {
+ return false;
+ }
+
+ // The transformation is applicable if the synonymous id is available at the
+ // use point.
+ return IdsIsAvailableAtUse(context, use_instruction,
+ message_.id_use_descriptor().in_operand_index(),
+ message_.synonymous_id());
+}
+
+void TransformationReplaceIdWithSynonym::Apply(
+ spvtools::opt::IRContext* context,
+ spvtools::fuzz::FactManager* /*unused*/) const {
+ auto instruction_to_change =
+ FindInstructionContainingUse(message_.id_use_descriptor(), context);
+ instruction_to_change->SetInOperand(
+ message_.id_use_descriptor().in_operand_index(),
+ {message_.synonymous_id()});
+ context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
+}
+
+protobufs::Transformation TransformationReplaceIdWithSynonym::ToMessage()
+ const {
+ protobufs::Transformation result;
+ *result.mutable_replace_id_with_synonym() = message_;
+ return result;
+}
+
+bool TransformationReplaceIdWithSynonym::IdsIsAvailableAtUse(
+ opt::IRContext* context, opt::Instruction* use_instruction,
+ uint32_t use_input_operand_index, uint32_t id) {
+ if (!context->get_instr_block(id)) {
+ return true;
+ }
+ auto defining_instruction = context->get_def_use_mgr()->GetDef(id);
+ if (defining_instruction == use_instruction) {
+ return false;
+ }
+ auto dominator_analysis = context->GetDominatorAnalysis(
+ context->get_instr_block(use_instruction)->GetParent());
+ if (use_instruction->opcode() == SpvOpPhi) {
+ // In the case where the use is an operand to OpPhi, it is actually the
+ // *parent* block associated with the operand that must be dominated by
+ // the synonym.
+ auto parent_block =
+ use_instruction->GetSingleWordInOperand(use_input_operand_index + 1);
+ return dominator_analysis->Dominates(
+ context->get_instr_block(defining_instruction)->id(), parent_block);
+ }
+ return dominator_analysis->Dominates(defining_instruction, use_instruction);
+}
+
+bool TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym(
+ opt::IRContext* context, opt::Instruction* use_instruction,
+ uint32_t use_in_operand_index) {
+ if (use_instruction->opcode() == SpvOpAccessChain &&
+ use_in_operand_index > 0) {
+ // This is an access chain index. If the (sub-)object being accessed by the
+ // given index has struct type then we cannot replace the use with a
+ // synonym, as the use needs to be an OpConstant.
+
+ // Get the top-level composite type that is being accessed.
+ auto object_being_accessed = context->get_def_use_mgr()->GetDef(
+ use_instruction->GetSingleWordInOperand(0));
+ auto pointer_type =
+ context->get_type_mgr()->GetType(object_being_accessed->type_id());
+ assert(pointer_type->AsPointer());
+ auto composite_type_being_accessed =
+ pointer_type->AsPointer()->pointee_type();
+
+ // Now walk the access chain, tracking the type of each sub-object of the
+ // composite that is traversed, until the index of interest is reached.
+ for (uint32_t index_in_operand = 1; index_in_operand < use_in_operand_index;
+ index_in_operand++) {
+ // For vectors, matrices and arrays, getting the type of the sub-object is
+ // trivial. For the struct case, the sub-object type is field-sensitive,
+ // and depends on the constant index that is used.
+ if (composite_type_being_accessed->AsVector()) {
+ composite_type_being_accessed =
+ composite_type_being_accessed->AsVector()->element_type();
+ } else if (composite_type_being_accessed->AsMatrix()) {
+ composite_type_being_accessed =
+ composite_type_being_accessed->AsMatrix()->element_type();
+ } else if (composite_type_being_accessed->AsArray()) {
+ composite_type_being_accessed =
+ composite_type_being_accessed->AsArray()->element_type();
+ } else {
+ assert(composite_type_being_accessed->AsStruct());
+ auto constant_index_instruction = context->get_def_use_mgr()->GetDef(
+ use_instruction->GetSingleWordInOperand(index_in_operand));
+ assert(constant_index_instruction->opcode() == SpvOpConstant);
+ uint32_t member_index =
+ constant_index_instruction->GetSingleWordInOperand(0);
+ composite_type_being_accessed =
+ composite_type_being_accessed->AsStruct()
+ ->element_types()[member_index];
+ }
+ }
+
+ // We have found the composite type being accessed by the index we are
+ // considering replacing. If it is a struct, then we cannot do the
+ // replacement as struct indices must be constants.
+ if (composite_type_being_accessed->AsStruct()) {
+ return false;
+ }
+ }
+
+ if (use_instruction->opcode() == SpvOpFunctionCall &&
+ use_in_operand_index > 0) {
+ // This is a function call argument. It is not allowed to have pointer
+ // type.
+
+ // Get the definition of the function being called.
+ auto function = context->get_def_use_mgr()->GetDef(
+ use_instruction->GetSingleWordInOperand(0));
+ // From the function definition, get the function type.
+ auto function_type =
+ context->get_def_use_mgr()->GetDef(function->GetSingleWordInOperand(1));
+ // OpTypeFunction's 0-th input operand is the function return type, and the
+ // function argument types follow. Because the arguments to OpFunctionCall
+ // start from input operand 1, we can use |use_in_operand_index| to get the
+ // type associated with this function argument.
+ auto parameter_type = context->get_type_mgr()->GetType(
+ function_type->GetSingleWordInOperand(use_in_operand_index));
+ if (parameter_type->AsPointer()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_replace_id_with_synonym.h b/source/fuzz/transformation_replace_id_with_synonym.h
new file mode 100644
index 0000000..c21673d
--- /dev/null
+++ b/source/fuzz/transformation_replace_id_with_synonym.h
@@ -0,0 +1,80 @@
+// 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_FUZZ_TRANSFORMATION_REPLACE_ID_WITH_SYNONYM_H_
+#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_ID_WITH_SYNONYM_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationReplaceIdWithSynonym : public Transformation {
+ public:
+ explicit TransformationReplaceIdWithSynonym(
+ const protobufs::TransformationReplaceIdWithSynonym& message);
+
+ TransformationReplaceIdWithSynonym(
+ protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id);
+
+ // - The fact manager must know that the id identified by
+ // |message_.id_use_descriptor| is synonomous with
+ // |message_.synonymous_id|.
+ // - Replacing the id in |message_.id_use_descriptor| by
+ // |message_.synonymous_id| must respect SPIR-V's rules about uses being
+ // dominated by their definitions.
+ // - The id must not be an index into an access chain whose base object has
+ // struct type, as such indices must be constants.
+ // - The id must not be a pointer argument to a function call (because the
+ // synonym might not be a memory object declaration).
+ // - |fresh_id_for_temporary| must be 0.
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // Replaces the use identified by |message_.id_use_descriptor| with the
+ // synonymous id identified by |message_.synonymous_id|.
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ // Checks whether the |id| is available (according to dominance rules) at the
+ // use point defined by input operand |use_input_operand_index| of
+ // |use_instruction|.
+ static bool IdsIsAvailableAtUse(opt::IRContext* context,
+ opt::Instruction* use_instruction,
+ uint32_t use_input_operand_index,
+ uint32_t id);
+
+ // Checks whether various conditions hold related to the acceptability of
+ // replacing the id use at |use_in_operand_index| of |use_instruction| with
+ // a synonym. In particular, this checks that:
+ // - the id use is not an index into a struct field in an OpAccessChain - such
+ // indices must be constants, so it is dangerous to replace them.
+ // - the id use is not a pointer function call argument, on which there are
+ // restrictions that make replacement problematic.
+ static bool UseCanBeReplacedWithSynonym(opt::IRContext* context,
+ opt::Instruction* use_instruction,
+ uint32_t use_in_operand_index);
+
+ private:
+ protobufs::TransformationReplaceIdWithSynonym message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_ID_WITH_SYNONYM_H_
diff --git a/source/fuzz/transformation_set_function_control.cpp b/source/fuzz/transformation_set_function_control.cpp
new file mode 100644
index 0000000..d2b61f1
--- /dev/null
+++ b/source/fuzz/transformation_set_function_control.cpp
@@ -0,0 +1,100 @@
+// 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/fuzz/transformation_set_function_control.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationSetFunctionControl::TransformationSetFunctionControl(
+ const spvtools::fuzz::protobufs::TransformationSetFunctionControl& message)
+ : message_(message) {}
+
+TransformationSetFunctionControl::TransformationSetFunctionControl(
+ uint32_t function_id, uint32_t function_control) {
+ message_.set_function_id(function_id);
+ message_.set_function_control(function_control);
+}
+
+bool TransformationSetFunctionControl::IsApplicable(
+ opt::IRContext* context, const FactManager& /*unused*/) const {
+ opt::Instruction* function_def_instruction =
+ FindFunctionDefInstruction(context);
+ if (!function_def_instruction) {
+ // The given function id does not correspond to any function.
+ return false;
+ }
+ uint32_t existing_function_control_mask =
+ function_def_instruction->GetSingleWordInOperand(0);
+
+ // Check (via an assertion) that function control mask doesn't have any bad
+ // bits set.
+ uint32_t acceptable_function_control_bits =
+ SpvFunctionControlInlineMask | SpvFunctionControlDontInlineMask |
+ SpvFunctionControlPureMask | SpvFunctionControlConstMask;
+ // The following is to keep release-mode compilers happy as this variable is
+ // only used in an assertion.
+ (void)(acceptable_function_control_bits);
+ assert(!(message_.function_control() & ~acceptable_function_control_bits) &&
+ "Nonsensical loop control bits were found.");
+
+ // Check (via an assertion) that function control mask does not have both
+ // Inline and DontInline bits set.
+ assert(!((message_.function_control() & SpvFunctionControlInlineMask) &&
+ (message_.function_control() & SpvFunctionControlDontInlineMask)) &&
+ "It is not OK to set both the 'Inline' and 'DontInline' bits of a "
+ "function control mask");
+
+ // Check that Const and Pure are only present if they were present on the
+ // original function
+ for (auto mask_bit :
+ {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) {
+ if ((message_.function_control() & mask_bit) &&
+ !(existing_function_control_mask & mask_bit)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void TransformationSetFunctionControl::Apply(opt::IRContext* context,
+ FactManager* /*unused*/) const {
+ opt::Instruction* function_def_instruction =
+ FindFunctionDefInstruction(context);
+ function_def_instruction->SetInOperand(0, {message_.function_control()});
+}
+
+protobufs::Transformation TransformationSetFunctionControl::ToMessage() const {
+ protobufs::Transformation result;
+ *result.mutable_set_function_control() = message_;
+ return result;
+}
+
+opt::Instruction* TransformationSetFunctionControl ::FindFunctionDefInstruction(
+ opt::IRContext* context) const {
+ // Look through all functions for a function whose defining instruction's
+ // result id matches |message_.function_id|, returning the defining
+ // instruction if found.
+ for (auto& function : *context->module()) {
+ if (function.DefInst().result_id() == message_.function_id()) {
+ return &function.DefInst();
+ }
+ }
+ // A nullptr result indicates that no match was found.
+ return nullptr;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_set_function_control.h b/source/fuzz/transformation_set_function_control.h
new file mode 100644
index 0000000..0526bb9
--- /dev/null
+++ b/source/fuzz/transformation_set_function_control.h
@@ -0,0 +1,58 @@
+// 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_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_H_
+#define SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationSetFunctionControl : public Transformation {
+ public:
+ explicit TransformationSetFunctionControl(
+ const protobufs::TransformationSetFunctionControl& message);
+
+ TransformationSetFunctionControl(uint32_t function_id,
+ uint32_t function_control);
+
+ // - |message_.function_id| must be the result id of an OpFunction
+ // instruction.
+ // - |message_.function_control| must be a function control mask that sets
+ // at most one of 'Inline' or 'DontInline', and that may not contain 'Pure'
+ // (respectively 'Const') unless the existing function control mask contains
+ // 'Pure' (respectively 'Const').
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // The function control operand of instruction |message_.function_id| is
+ // over-written with |message_.function_control|.
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ private:
+ opt::Instruction* FindFunctionDefInstruction(opt::IRContext* context) const;
+
+ protobufs::TransformationSetFunctionControl message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_H_
diff --git a/source/fuzz/transformation_set_loop_control.cpp b/source/fuzz/transformation_set_loop_control.cpp
new file mode 100644
index 0000000..9062f17
--- /dev/null
+++ b/source/fuzz/transformation_set_loop_control.cpp
@@ -0,0 +1,216 @@
+// 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/fuzz/transformation_set_loop_control.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationSetLoopControl::TransformationSetLoopControl(
+ const spvtools::fuzz::protobufs::TransformationSetLoopControl& message)
+ : message_(message) {}
+
+TransformationSetLoopControl::TransformationSetLoopControl(
+ uint32_t block_id, uint32_t loop_control, uint32_t peel_count,
+ uint32_t partial_count) {
+ message_.set_block_id(block_id);
+ message_.set_loop_control(loop_control);
+ message_.set_peel_count(peel_count);
+ message_.set_partial_count(partial_count);
+}
+
+bool TransformationSetLoopControl::IsApplicable(
+ opt::IRContext* context, const FactManager& /*unused*/) const {
+ // |message_.block_id| must identify a block that ends with OpLoopMerge.
+ auto block = context->get_instr_block(message_.block_id());
+ if (!block) {
+ return false;
+ }
+ auto merge_inst = block->GetMergeInst();
+ if (!merge_inst || merge_inst->opcode() != SpvOpLoopMerge) {
+ return false;
+ }
+
+ // We sanity-check that the transformation does not try to set any meaningless
+ // bits of the loop control mask.
+ uint32_t all_loop_control_mask_bits_set =
+ SpvLoopControlUnrollMask | SpvLoopControlDontUnrollMask |
+ SpvLoopControlDependencyInfiniteMask |
+ SpvLoopControlDependencyLengthMask | SpvLoopControlMinIterationsMask |
+ SpvLoopControlMaxIterationsMask | SpvLoopControlIterationMultipleMask |
+ SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask;
+
+ // The variable is only used in an assertion; the following keeps release-mode
+ // compilers happy.
+ (void)(all_loop_control_mask_bits_set);
+
+ // No additional bits should be set.
+ assert(!(message_.loop_control() & ~all_loop_control_mask_bits_set));
+
+ // Grab the loop control mask currently associated with the OpLoopMerge
+ // instruction.
+ auto existing_loop_control_mask =
+ merge_inst->GetSingleWordInOperand(kLoopControlMaskInOperandIndex);
+
+ // Check that there is no attempt to set one of the loop controls that
+ // requires guarantees to hold.
+ for (SpvLoopControlMask mask :
+ {SpvLoopControlDependencyInfiniteMask,
+ SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask,
+ SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) {
+ // We have a problem if this loop control bit was not set in the original
+ // loop control mask but is set by the transformation.
+ if (LoopControlBitIsAddedByTransformation(mask,
+ existing_loop_control_mask)) {
+ return false;
+ }
+ }
+
+ if ((message_.loop_control() &
+ (SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask)) &&
+ !(PeelCountIsSupported(context) && PartialCountIsSupported(context))) {
+ // At least one of PeelCount or PartialCount is used, but the SPIR-V version
+ // in question does not support these loop controls.
+ return false;
+ }
+
+ if (message_.peel_count() > 0 &&
+ !(message_.loop_control() & SpvLoopControlPeelCountMask)) {
+ // Peel count provided, but peel count mask bit not set.
+ return false;
+ }
+
+ if (message_.partial_count() > 0 &&
+ !(message_.loop_control() & SpvLoopControlPartialCountMask)) {
+ // Partial count provided, but partial count mask bit not set.
+ return false;
+ }
+
+ // We must not set both 'don't unroll' and one of 'peel count' or 'partial
+ // count'.
+ return !((message_.loop_control() & SpvLoopControlDontUnrollMask) &&
+ (message_.loop_control() &
+ (SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask)));
+}
+
+void TransformationSetLoopControl::Apply(opt::IRContext* context,
+ FactManager* /*unused*/) const {
+ // Grab the loop merge instruction and its associated loop control mask.
+ auto merge_inst =
+ context->get_instr_block(message_.block_id())->GetMergeInst();
+ auto existing_loop_control_mask =
+ merge_inst->GetSingleWordInOperand(kLoopControlMaskInOperandIndex);
+
+ // We are going to replace the OpLoopMerge's operands with this list.
+ opt::Instruction::OperandList new_operands;
+ // We add the existing merge block and continue target ids.
+ new_operands.push_back(merge_inst->GetInOperand(0));
+ new_operands.push_back(merge_inst->GetInOperand(1));
+ // We use the loop control mask from the transformation.
+ new_operands.push_back(
+ {SPV_OPERAND_TYPE_LOOP_CONTROL, {message_.loop_control()}});
+
+ // It remains to determine what literals to provide, in association with
+ // the new loop control mask.
+ //
+ // For the loop controls that require guarantees to hold about the number
+ // of loop iterations, we need to keep, from the original OpLoopMerge, any
+ // literals associated with loop control bits that are still set.
+
+ uint32_t literal_index = 0; // Indexes into the literals from the original
+ // instruction.
+ for (SpvLoopControlMask mask :
+ {SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask,
+ SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) {
+ // Check whether the bit was set in the original loop control mask.
+ if (existing_loop_control_mask & mask) {
+ // Check whether the bit is set in the new loop control mask.
+ if (message_.loop_control() & mask) {
+ // Add the associated literal to our sequence of replacement operands.
+ new_operands.push_back(
+ {SPV_OPERAND_TYPE_LITERAL_INTEGER,
+ {merge_inst->GetSingleWordInOperand(
+ kLoopControlFirstLiteralInOperandIndex + literal_index)}});
+ }
+ // Increment our index into the original loop control mask's literals,
+ // whether or not the bit was set in the new mask.
+ literal_index++;
+ }
+ }
+
+ // If PeelCount is set in the new mask, |message_.peel_count| provides the
+ // associated peel count.
+ if (message_.loop_control() & SpvLoopControlPeelCountMask) {
+ new_operands.push_back(
+ {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.peel_count()}});
+ }
+
+ // Similar, but for PartialCount.
+ if (message_.loop_control() & SpvLoopControlPartialCountMask) {
+ new_operands.push_back(
+ {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.partial_count()}});
+ }
+
+ // Replace the input operands of the OpLoopMerge with the new operands we have
+ // accumulated.
+ merge_inst->SetInOperands(std::move(new_operands));
+}
+
+protobufs::Transformation TransformationSetLoopControl::ToMessage() const {
+ protobufs::Transformation result;
+ *result.mutable_set_loop_control() = message_;
+ return result;
+}
+
+bool TransformationSetLoopControl::LoopControlBitIsAddedByTransformation(
+ SpvLoopControlMask loop_control_single_bit_mask,
+ uint32_t existing_loop_control_mask) const {
+ return !(loop_control_single_bit_mask & existing_loop_control_mask) &&
+ (loop_control_single_bit_mask & message_.loop_control());
+}
+
+bool TransformationSetLoopControl::PartialCountIsSupported(
+ opt::IRContext* context) {
+ // TODO(afd): We capture the universal environments for which this loop
+ // control is definitely not supported. The check should be refined on
+ // demand for other target environments.
+ switch (context->grammar().target_env()) {
+ case SPV_ENV_UNIVERSAL_1_0:
+ case SPV_ENV_UNIVERSAL_1_1:
+ case SPV_ENV_UNIVERSAL_1_2:
+ case SPV_ENV_UNIVERSAL_1_3:
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool TransformationSetLoopControl::PeelCountIsSupported(
+ opt::IRContext* context) {
+ // TODO(afd): We capture the universal environments for which this loop
+ // control is definitely not supported. The check should be refined on
+ // demand for other target environments.
+ switch (context->grammar().target_env()) {
+ case SPV_ENV_UNIVERSAL_1_0:
+ case SPV_ENV_UNIVERSAL_1_1:
+ case SPV_ENV_UNIVERSAL_1_2:
+ case SPV_ENV_UNIVERSAL_1_3:
+ return false;
+ default:
+ return true;
+ }
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_set_loop_control.h b/source/fuzz/transformation_set_loop_control.h
new file mode 100644
index 0000000..28b148c
--- /dev/null
+++ b/source/fuzz/transformation_set_loop_control.h
@@ -0,0 +1,79 @@
+// 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_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_H_
+#define SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationSetLoopControl : public Transformation {
+ public:
+ const static uint32_t kLoopControlMaskInOperandIndex = 2;
+ const static uint32_t kLoopControlFirstLiteralInOperandIndex = 3;
+
+ explicit TransformationSetLoopControl(
+ const protobufs::TransformationSetLoopControl& message);
+
+ TransformationSetLoopControl(uint32_t block_id, uint32_t loop_control,
+ uint32_t peel_count, uint32_t partial_count);
+
+ // - |message_.block_id| must be a block containing an OpLoopMerge
+ // instruction.
+ // - |message_.loop_control| must be a legal loop control mask that
+ // only uses controls available in the SPIR-V version associated with
+ // |context|, and must not add loop controls that are only valid in the
+ // presence of guarantees about what the loop does (e.g. MinIterations).
+ // - |message_.peel_count| (respectively |message_.partial_count|) must be
+ // zero PeelCount (respectively PartialCount) is set in
+ // |message_.loop_control|.
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // - The loop control operand of the OpLoopMergeInstruction in
+ // |message_.block_id| is overwritten with |message_.loop_control|.
+ // - The literals associated with the loop control are updated to reflect any
+ // controls with associated literals that have been removed (e.g.
+ // MinIterations), and any that have been added (PeelCount and/or
+ // PartialCount).
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ // Does the version of SPIR-V being used support the PartialCount loop
+ // control?
+ static bool PartialCountIsSupported(opt::IRContext* context);
+
+ // Does the version of SPIR-V being used support the PeelCount loop control?
+ static bool PeelCountIsSupported(opt::IRContext* context);
+
+ private:
+ // Returns true if and only if |loop_single_bit_mask| is *not* set in
+ // |existing_loop_control| but *is* set in |message_.loop_control|.
+ bool LoopControlBitIsAddedByTransformation(
+ SpvLoopControlMask loop_control_single_bit_mask,
+ uint32_t existing_loop_control_mask) const;
+
+ protobufs::TransformationSetLoopControl message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_H_
diff --git a/source/fuzz/transformation_set_memory_operands_mask.cpp b/source/fuzz/transformation_set_memory_operands_mask.cpp
new file mode 100644
index 0000000..a14e1a6
--- /dev/null
+++ b/source/fuzz/transformation_set_memory_operands_mask.cpp
@@ -0,0 +1,201 @@
+// 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/fuzz/transformation_set_memory_operands_mask.h"
+
+#include "source/fuzz/instruction_descriptor.h"
+
+namespace spvtools {
+namespace fuzz {
+
+namespace {
+
+const uint32_t kOpLoadMemoryOperandsMaskIndex = 1;
+const uint32_t kOpStoreMemoryOperandsMaskIndex = 2;
+const uint32_t kOpCopyMemoryFirstMemoryOperandsMaskIndex = 2;
+const uint32_t kOpCopyMemorySizedFirstMemoryOperandsMaskIndex = 3;
+
+} // namespace
+
+TransformationSetMemoryOperandsMask::TransformationSetMemoryOperandsMask(
+ const spvtools::fuzz::protobufs::TransformationSetMemoryOperandsMask&
+ message)
+ : message_(message) {}
+
+TransformationSetMemoryOperandsMask::TransformationSetMemoryOperandsMask(
+ const protobufs::InstructionDescriptor& memory_access_instruction,
+ uint32_t memory_operands_mask, uint32_t memory_operands_mask_index) {
+ *message_.mutable_memory_access_instruction() = memory_access_instruction;
+ message_.set_memory_operands_mask(memory_operands_mask);
+ message_.set_memory_operands_mask_index(memory_operands_mask_index);
+}
+
+bool TransformationSetMemoryOperandsMask::IsApplicable(
+ opt::IRContext* context,
+ const spvtools::fuzz::FactManager& /*unused*/) const {
+ if (message_.memory_operands_mask_index() != 0) {
+ // The following conditions should never be violated, even if
+ // transformations end up being replayed in a different way to the manner in
+ // which they were applied during fuzzing, hence why these are assertions
+ // rather than applicability checks.
+ assert(message_.memory_operands_mask_index() == 1);
+ assert(message_.memory_access_instruction().target_instruction_opcode() ==
+ SpvOpCopyMemory ||
+ message_.memory_access_instruction().target_instruction_opcode() ==
+ SpvOpCopyMemorySized);
+ assert(MultipleMemoryOperandMasksAreSupported(context));
+ }
+
+ auto instruction =
+ FindInstruction(message_.memory_access_instruction(), context);
+ if (!instruction) {
+ return false;
+ }
+ if (!IsMemoryAccess(*instruction)) {
+ return false;
+ }
+
+ auto original_mask_in_operand_index = GetInOperandIndexForMask(
+ *instruction, message_.memory_operands_mask_index());
+ assert(original_mask_in_operand_index != 0 &&
+ "The given mask index is not valid.");
+ uint32_t original_mask =
+ original_mask_in_operand_index < instruction->NumInOperands()
+ ? instruction->GetSingleWordInOperand(original_mask_in_operand_index)
+ : static_cast<uint32_t>(SpvMemoryAccessMaskNone);
+ uint32_t new_mask = message_.memory_operands_mask();
+
+ // Volatile must not be removed
+ if ((original_mask & SpvMemoryAccessVolatileMask) &&
+ !(new_mask & SpvMemoryAccessVolatileMask)) {
+ return false;
+ }
+
+ // Nontemporal can be added or removed, and no other flag is allowed to
+ // change. We do this by checking that the masks are equal once we set
+ // their Volatile and Nontemporal flags to the same value (this works
+ // because valid manipulation of Volatile is checked above, and the manner
+ // in which Nontemporal is manipulated does not matter).
+ return (original_mask | SpvMemoryAccessVolatileMask |
+ SpvMemoryAccessNontemporalMask) ==
+ (new_mask | SpvMemoryAccessVolatileMask |
+ SpvMemoryAccessNontemporalMask);
+}
+
+void TransformationSetMemoryOperandsMask::Apply(
+ opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
+ auto instruction =
+ FindInstruction(message_.memory_access_instruction(), context);
+ auto original_mask_in_operand_index = GetInOperandIndexForMask(
+ *instruction, message_.memory_operands_mask_index());
+ // Either add a new operand, if no mask operand was already present, or
+ // replace an existing mask operand.
+ if (original_mask_in_operand_index >= instruction->NumInOperands()) {
+ instruction->AddOperand(
+ {SPV_OPERAND_TYPE_MEMORY_ACCESS, {message_.memory_operands_mask()}});
+
+ } else {
+ instruction->SetInOperand(original_mask_in_operand_index,
+ {message_.memory_operands_mask()});
+ }
+}
+
+protobufs::Transformation TransformationSetMemoryOperandsMask::ToMessage()
+ const {
+ protobufs::Transformation result;
+ *result.mutable_set_memory_operands_mask() = message_;
+ return result;
+}
+
+bool TransformationSetMemoryOperandsMask::IsMemoryAccess(
+ const opt::Instruction& instruction) {
+ switch (instruction.opcode()) {
+ case SpvOpLoad:
+ case SpvOpStore:
+ case SpvOpCopyMemory:
+ case SpvOpCopyMemorySized:
+ return true;
+ default:
+ return false;
+ }
+}
+
+uint32_t TransformationSetMemoryOperandsMask::GetInOperandIndexForMask(
+ const opt::Instruction& instruction, uint32_t mask_index) {
+ // Get the input operand index associated with the first memory operands mask
+ // for the instruction.
+ uint32_t first_mask_in_operand_index = 0;
+ switch (instruction.opcode()) {
+ case SpvOpLoad:
+ first_mask_in_operand_index = kOpLoadMemoryOperandsMaskIndex;
+ break;
+ case SpvOpStore:
+ first_mask_in_operand_index = kOpStoreMemoryOperandsMaskIndex;
+ break;
+ case SpvOpCopyMemory:
+ first_mask_in_operand_index = kOpCopyMemoryFirstMemoryOperandsMaskIndex;
+ break;
+ case SpvOpCopyMemorySized:
+ first_mask_in_operand_index =
+ kOpCopyMemorySizedFirstMemoryOperandsMaskIndex;
+ break;
+ default:
+ assert(false && "Unknown memory instruction.");
+ break;
+ }
+ // If we are looking for the input operand index of the first mask, return it.
+ if (mask_index == 0) {
+ return first_mask_in_operand_index;
+ }
+ assert(mask_index == 1 && "Memory operands mask index must be 0 or 1.");
+
+ // We are looking for the input operand index of the second mask. This is a
+ // little complicated because, depending on the contents of the first mask,
+ // there may be some input operands separating the two masks.
+ uint32_t first_mask =
+ instruction.GetSingleWordInOperand(first_mask_in_operand_index);
+
+ // Consider each bit that might have an associated extra input operand, and
+ // count how many there are expected to be.
+ uint32_t first_mask_extra_operand_count = 0;
+ for (auto mask_bit :
+ {SpvMemoryAccessAlignedMask, SpvMemoryAccessMakePointerAvailableMask,
+ SpvMemoryAccessMakePointerAvailableKHRMask,
+ SpvMemoryAccessMakePointerVisibleMask,
+ SpvMemoryAccessMakePointerVisibleKHRMask}) {
+ if (first_mask & mask_bit) {
+ first_mask_extra_operand_count++;
+ }
+ }
+ return first_mask_in_operand_index + first_mask_extra_operand_count + 1;
+}
+
+bool TransformationSetMemoryOperandsMask::
+ MultipleMemoryOperandMasksAreSupported(opt::IRContext* context) {
+ // TODO(afd): We capture the universal environments for which this loop
+ // control is definitely not supported. The check should be refined on
+ // demand for other target environments.
+ switch (context->grammar().target_env()) {
+ case SPV_ENV_UNIVERSAL_1_0:
+ case SPV_ENV_UNIVERSAL_1_1:
+ case SPV_ENV_UNIVERSAL_1_2:
+ case SPV_ENV_UNIVERSAL_1_3:
+ return false;
+ default:
+ return true;
+ }
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_set_memory_operands_mask.h b/source/fuzz/transformation_set_memory_operands_mask.h
new file mode 100644
index 0000000..20ae145
--- /dev/null
+++ b/source/fuzz/transformation_set_memory_operands_mask.h
@@ -0,0 +1,76 @@
+// 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_FUZZ_TRANSFORMATION_SET_MEMORY_OPERANDS_MASK_H_
+#define SOURCE_FUZZ_TRANSFORMATION_SET_MEMORY_OPERANDS_MASK_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationSetMemoryOperandsMask : public Transformation {
+ public:
+ explicit TransformationSetMemoryOperandsMask(
+ const protobufs::TransformationSetMemoryOperandsMask& message);
+
+ TransformationSetMemoryOperandsMask(
+ const protobufs::InstructionDescriptor& memory_access_instruction,
+ uint32_t memory_operands_mask, uint32_t memory_operands_mask_index);
+
+ // - |message_.memory_access_instruction| must describe a memory access
+ // instruction.
+ // - |message_.memory_operands_mask_index| must be suitable for this memory
+ // access instruction, e.g. it must be 0 in the case of OpLoad, and may be
+ // 1 in the case of OpCopyMemory if the SPIR-V version is 1.4 or higher.
+ // - |message_.memory_operands_mask| must be identical to the original memory
+ // operands mask, except that Volatile may be added, and Nontemporal may be
+ // toggled.
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // Replaces the operands mask identified by
+ // |message_.memory_operands_mask_index| in the instruction described by
+ // |message_.memory_access_instruction| with |message_.memory_operands_mask|,
+ // creating an input operand for the mask if no such operand was present.
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ // Helper function that determines whether |instruction| is a memory
+ // instruction (e.g. OpLoad).
+ static bool IsMemoryAccess(const opt::Instruction& instruction);
+
+ // Does the version of SPIR-V being used support multiple memory operand
+ // masks on relevant memory access instructions?
+ static bool MultipleMemoryOperandMasksAreSupported(opt::IRContext* context);
+
+ // Helper function to get the input operand index associated with mask number
+ // |mask_index|. This is a bit tricky if there are multiple masks, because the
+ // index associated with the second mask depends on whether the first mask
+ // includes any flags such as Aligned that have corresponding operands.
+ static uint32_t GetInOperandIndexForMask(const opt::Instruction& instruction,
+ uint32_t mask_index);
+
+ private:
+ protobufs::TransformationSetMemoryOperandsMask message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_SET_MEMORY_OPERANDS_MASK_H_
diff --git a/source/fuzz/transformation_set_selection_control.cpp b/source/fuzz/transformation_set_selection_control.cpp
new file mode 100644
index 0000000..ebabdef
--- /dev/null
+++ b/source/fuzz/transformation_set_selection_control.cpp
@@ -0,0 +1,60 @@
+// 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/fuzz/transformation_set_selection_control.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationSetSelectionControl::TransformationSetSelectionControl(
+ const spvtools::fuzz::protobufs::TransformationSetSelectionControl& message)
+ : message_(message) {}
+
+TransformationSetSelectionControl::TransformationSetSelectionControl(
+ uint32_t block_id, uint32_t selection_control) {
+ message_.set_block_id(block_id);
+ message_.set_selection_control(selection_control);
+}
+
+bool TransformationSetSelectionControl::IsApplicable(
+ opt::IRContext* context, const FactManager& /*unused*/) const {
+ assert((message_.selection_control() == SpvSelectionControlMaskNone ||
+ message_.selection_control() == SpvSelectionControlFlattenMask ||
+ message_.selection_control() == SpvSelectionControlDontFlattenMask) &&
+ "Selection control should never be set to something other than "
+ "'None', 'Flatten' or 'DontFlatten'");
+ if (auto block = context->get_instr_block(message_.block_id())) {
+ if (auto merge_inst = block->GetMergeInst()) {
+ return merge_inst->opcode() == SpvOpSelectionMerge;
+ }
+ }
+ // Either the block did not exit, or did not end with OpSelectionMerge.
+ return false;
+}
+
+void TransformationSetSelectionControl::Apply(opt::IRContext* context,
+ FactManager* /*unused*/) const {
+ context->get_instr_block(message_.block_id())
+ ->GetMergeInst()
+ ->SetInOperand(1, {message_.selection_control()});
+}
+
+protobufs::Transformation TransformationSetSelectionControl::ToMessage() const {
+ protobufs::Transformation result;
+ *result.mutable_set_selection_control() = message_;
+ return result;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_set_selection_control.h b/source/fuzz/transformation_set_selection_control.h
new file mode 100644
index 0000000..19e0c3c
--- /dev/null
+++ b/source/fuzz/transformation_set_selection_control.h
@@ -0,0 +1,54 @@
+// 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_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_
+#define SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationSetSelectionControl : public Transformation {
+ public:
+ explicit TransformationSetSelectionControl(
+ const protobufs::TransformationSetSelectionControl& message);
+
+ TransformationSetSelectionControl(uint32_t block_id,
+ uint32_t selection_control);
+
+ // - |message_.block_id| must be a block containing an OpSelectionMerge
+ // instruction.
+ // - |message_.selection_control| must be one of None, Flatten or
+ // DontFlatten.
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // - The selection control operand of the OpSelectionMergeInstruction in
+ // |message_.block_id| is overwritten with |message_.selection_control|.
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ private:
+ protobufs::TransformationSetSelectionControl message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_
diff --git a/source/fuzz/transformation_split_block.cpp b/source/fuzz/transformation_split_block.cpp
index a2da371..9f6da7c 100644
--- a/source/fuzz/transformation_split_block.cpp
+++ b/source/fuzz/transformation_split_block.cpp
@@ -17,6 +17,7 @@
#include <utility>
#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
#include "source/util/make_unique.h"
namespace spvtools {
@@ -26,11 +27,10 @@
const spvtools::fuzz::protobufs::TransformationSplitBlock& message)
: message_(message) {}
-TransformationSplitBlock::TransformationSplitBlock(uint32_t base_instruction_id,
- uint32_t offset,
- uint32_t fresh_id) {
- message_.set_base_instruction_id(base_instruction_id);
- message_.set_offset(offset);
+TransformationSplitBlock::TransformationSplitBlock(
+ const protobufs::InstructionDescriptor& instruction_to_split_before,
+ uint32_t fresh_id) {
+ *message_.mutable_instruction_to_split_before() = instruction_to_split_before;
message_.set_fresh_id(fresh_id);
}
@@ -40,31 +40,28 @@
// We require the id for the new block to be unused.
return false;
}
- auto base_instruction =
- context->get_def_use_mgr()->GetDef(message_.base_instruction_id());
- if (!base_instruction) {
+ auto instruction_to_split_before =
+ FindInstruction(message_.instruction_to_split_before(), context);
+ if (!instruction_to_split_before) {
// The instruction describing the block we should split does not exist.
return false;
}
- auto block_containing_base_instruction =
- context->get_instr_block(base_instruction);
- if (!block_containing_base_instruction) {
- // The instruction describing the block we should split is not contained in
- // a block.
- return false;
- }
+ auto block_to_split = context->get_instr_block(instruction_to_split_before);
+ assert(block_to_split &&
+ "We should not have managed to find the "
+ "instruction if it was not contained in a block.");
- if (block_containing_base_instruction->IsLoopHeader()) {
+ if (block_to_split->IsLoopHeader()) {
// We cannot split a loop header block: back-edges would become invalid.
return false;
}
- auto split_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset(
- block_containing_base_instruction, base_instruction, message_.offset());
- if (split_before == block_containing_base_instruction->end()) {
- // The offset was inappropriate.
- return false;
- }
+ auto split_before = fuzzerutil::GetIteratorForInstruction(
+ block_to_split, instruction_to_split_before);
+ assert(split_before != block_to_split->end() &&
+ "At this point we know the"
+ " block split point exists.");
+
if (split_before->PreviousNode() &&
split_before->PreviousNode()->opcode() == SpvOpSelectionMerge) {
// We cannot split directly after a selection merge: this would separate
@@ -84,44 +81,39 @@
void TransformationSplitBlock::Apply(opt::IRContext* context,
FactManager* /*unused*/) const {
- auto base_instruction =
- context->get_def_use_mgr()->GetDef(message_.base_instruction_id());
- assert(base_instruction && "Base instruction must exist");
- auto block_containing_base_instruction =
- context->get_instr_block(base_instruction);
- assert(block_containing_base_instruction &&
- "Base instruction must be in a block");
- auto split_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset(
- block_containing_base_instruction, base_instruction, message_.offset());
- assert(split_before != block_containing_base_instruction->end() &&
+ opt::Instruction* instruction_to_split_before =
+ FindInstruction(message_.instruction_to_split_before(), context);
+ opt::BasicBlock* block_to_split =
+ context->get_instr_block(instruction_to_split_before);
+ auto split_before = fuzzerutil::GetIteratorForInstruction(
+ block_to_split, instruction_to_split_before);
+ assert(split_before != block_to_split->end() &&
"If the transformation is applicable, we should have an "
"instruction to split on.");
+
// We need to make sure the module's id bound is large enough to add the
// fresh id.
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
// Split the block.
- auto new_bb = block_containing_base_instruction->SplitBasicBlock(
- context, message_.fresh_id(), split_before);
+ auto new_bb = block_to_split->SplitBasicBlock(context, message_.fresh_id(),
+ split_before);
// The split does not automatically add a branch between the two parts of
// the original block, so we add one.
- block_containing_base_instruction->AddInstruction(
- MakeUnique<opt::Instruction>(
- context, SpvOpBranch, 0, 0,
- std::initializer_list<opt::Operand>{
- opt::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID,
- {message_.fresh_id()})}));
+ block_to_split->AddInstruction(MakeUnique<opt::Instruction>(
+ context, SpvOpBranch, 0, 0,
+ std::initializer_list<opt::Operand>{opt::Operand(
+ spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message_.fresh_id()})}));
// If we split before OpPhi instructions, we need to update their
// predecessor operand so that the block they used to be inside is now the
// predecessor.
- new_bb->ForEachPhiInst(
- [block_containing_base_instruction](opt::Instruction* phi_inst) {
- // The following assertion is a sanity check. It is guaranteed to hold
- // if IsApplicable holds.
- assert(phi_inst->NumInOperands() == 2 &&
- "We can only split a block before an OpPhi if block has exactly "
- "one predecessor.");
- phi_inst->SetInOperand(1, {block_containing_base_instruction->id()});
- });
+ new_bb->ForEachPhiInst([block_to_split](opt::Instruction* phi_inst) {
+ // The following assertion is a sanity check. It is guaranteed to hold
+ // if IsApplicable holds.
+ assert(phi_inst->NumInOperands() == 2 &&
+ "We can only split a block before an OpPhi if block has exactly "
+ "one predecessor.");
+ phi_inst->SetInOperand(1, {block_to_split->id()});
+ });
// Invalidate all analyses
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
}
diff --git a/source/fuzz/transformation_split_block.h b/source/fuzz/transformation_split_block.h
index 4a7095a..63dc7f5 100644
--- a/source/fuzz/transformation_split_block.h
+++ b/source/fuzz/transformation_split_block.h
@@ -28,8 +28,9 @@
explicit TransformationSplitBlock(
const protobufs::TransformationSplitBlock& message);
- TransformationSplitBlock(uint32_t base_instruction_id, uint32_t offset,
- uint32_t fresh_id);
+ TransformationSplitBlock(
+ const protobufs::InstructionDescriptor& instruction_to_split_before,
+ uint32_t fresh_id);
// - |message_.base_instruction_id| must be the result id of an instruction
// 'base' in some block 'blk'.
diff --git a/source/fuzz/transformation_vector_shuffle.cpp b/source/fuzz/transformation_vector_shuffle.cpp
new file mode 100644
index 0000000..e2d889d
--- /dev/null
+++ b/source/fuzz/transformation_vector_shuffle.cpp
@@ -0,0 +1,203 @@
+// 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/fuzz/transformation_vector_shuffle.h"
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationVectorShuffle::TransformationVectorShuffle(
+ const spvtools::fuzz::protobufs::TransformationVectorShuffle& message)
+ : message_(message) {}
+
+TransformationVectorShuffle::TransformationVectorShuffle(
+ const protobufs::InstructionDescriptor& instruction_to_insert_before,
+ uint32_t fresh_id, uint32_t vector1, uint32_t vector2,
+ const std::vector<uint32_t>& component) {
+ *message_.mutable_instruction_to_insert_before() =
+ instruction_to_insert_before;
+ message_.set_fresh_id(fresh_id);
+ message_.set_vector1(vector1);
+ message_.set_vector2(vector2);
+ for (auto a_component : component) {
+ message_.add_component(a_component);
+ }
+}
+
+bool TransformationVectorShuffle::IsApplicable(
+ opt::IRContext* context,
+ const spvtools::fuzz::FactManager& /*unused*/) const {
+ // The fresh id must not already be in use.
+ if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
+ return false;
+ }
+ // The instruction before which the shuffle will be inserted must exist.
+ auto instruction_to_insert_before =
+ FindInstruction(message_.instruction_to_insert_before(), context);
+ if (!instruction_to_insert_before) {
+ return false;
+ }
+ // The first vector must be an instruction with a type id
+ auto vector1_instruction =
+ context->get_def_use_mgr()->GetDef(message_.vector1());
+ if (!vector1_instruction || !vector1_instruction->type_id()) {
+ return false;
+ }
+ // The second vector must be an instruction with a type id
+ auto vector2_instruction =
+ context->get_def_use_mgr()->GetDef(message_.vector2());
+ if (!vector2_instruction || !vector2_instruction->type_id()) {
+ return false;
+ }
+ auto vector1_type =
+ context->get_type_mgr()->GetType(vector1_instruction->type_id());
+ // The first vector instruction's type must actually be a vector type.
+ if (!vector1_type->AsVector()) {
+ return false;
+ }
+ auto vector2_type =
+ context->get_type_mgr()->GetType(vector2_instruction->type_id());
+ // The second vector instruction's type must actually be a vector type.
+ if (!vector2_type->AsVector()) {
+ return false;
+ }
+ // The element types of the vectors must be the same.
+ if (vector1_type->AsVector()->element_type() !=
+ vector2_type->AsVector()->element_type()) {
+ return false;
+ }
+ uint32_t combined_size = vector1_type->AsVector()->element_count() +
+ vector2_type->AsVector()->element_count();
+ for (auto a_compoment : message_.component()) {
+ // 0xFFFFFFFF is used to represent an undefined component. Unless
+ // undefined, a component must be less than the combined size of the
+ // vectors.
+ if (a_compoment != 0xFFFFFFFF && a_compoment >= combined_size) {
+ return false;
+ }
+ }
+ // The module must already declare an appropriate type in which to store the
+ // result of the shuffle.
+ if (!GetResultTypeId(context, *vector1_type->AsVector()->element_type())) {
+ return false;
+ }
+ // Each of the vectors used in the shuffle must be available at the insertion
+ // point.
+ for (auto used_instruction : {vector1_instruction, vector2_instruction}) {
+ if (auto block = context->get_instr_block(used_instruction)) {
+ if (!context->GetDominatorAnalysis(block->GetParent())
+ ->Dominates(used_instruction, instruction_to_insert_before)) {
+ return false;
+ }
+ }
+ }
+
+ // It must be legitimate to insert an OpVectorShuffle before the identified
+ // instruction.
+ return fuzzerutil::CanInsertOpcodeBeforeInstruction(
+ SpvOpVectorShuffle, instruction_to_insert_before);
+}
+
+void TransformationVectorShuffle::Apply(
+ opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const {
+ // Make input operands for a shuffle instruction - these comprise the two
+ // vectors being shuffled, followed by the integer literal components.
+ opt::Instruction::OperandList shuffle_operands = {
+ {SPV_OPERAND_TYPE_ID, {message_.vector1()}},
+ {SPV_OPERAND_TYPE_ID, {message_.vector2()}}};
+ for (auto a_component : message_.component()) {
+ shuffle_operands.push_back(
+ {SPV_OPERAND_TYPE_LITERAL_INTEGER, {a_component}});
+ }
+
+ uint32_t result_type_id = GetResultTypeId(
+ context, *GetVectorType(context, message_.vector1())->element_type());
+
+ // Add a shuffle instruction right before the instruction identified by
+ // |message_.instruction_to_insert_before|.
+ FindInstruction(message_.instruction_to_insert_before(), context)
+ ->InsertBefore(MakeUnique<opt::Instruction>(
+ context, SpvOpVectorShuffle, result_type_id, message_.fresh_id(),
+ shuffle_operands));
+ fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
+ context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
+
+ // Add synonym facts relating the defined elements of the shuffle result to
+ // the vector components that they come from.
+ for (uint32_t component_index = 0;
+ component_index < static_cast<uint32_t>(message_.component_size());
+ component_index++) {
+ uint32_t component = message_.component(component_index);
+ if (component == 0xFFFFFFFF) {
+ // This component is undefined, so move on - but first note that the
+ // overall shuffle result cannot be synonymous with any vector.
+ continue;
+ }
+
+ // This describes the element of the result vector associated with
+ // |component_index|.
+ protobufs::DataDescriptor descriptor_for_result_component =
+ MakeDataDescriptor(message_.fresh_id(), {component_index});
+
+ protobufs::DataDescriptor descriptor_for_source_component;
+
+ // Get a data descriptor for the component of the input vector to which
+ // |component| refers.
+ if (component <
+ GetVectorType(context, message_.vector1())->element_count()) {
+ descriptor_for_source_component =
+ MakeDataDescriptor(message_.vector1(), {component});
+ } else {
+ auto index_into_vector_2 =
+ component -
+ GetVectorType(context, message_.vector1())->element_count();
+ assert(index_into_vector_2 <
+ GetVectorType(context, message_.vector2())->element_count() &&
+ "Vector shuffle index is out of bounds.");
+ descriptor_for_source_component =
+ MakeDataDescriptor(message_.vector2(), {index_into_vector_2});
+ }
+
+ // Add a fact relating this input vector component with the associated
+ // result component.
+ fact_manager->AddFactDataSynonym(descriptor_for_result_component,
+ descriptor_for_source_component, context);
+ }
+}
+
+protobufs::Transformation TransformationVectorShuffle::ToMessage() const {
+ protobufs::Transformation result;
+ *result.mutable_vector_shuffle() = message_;
+ return result;
+}
+
+uint32_t TransformationVectorShuffle::GetResultTypeId(
+ opt::IRContext* context, const opt::analysis::Type& element_type) const {
+ opt::analysis::Vector result_type(
+ &element_type, static_cast<uint32_t>(message_.component_size()));
+ return context->get_type_mgr()->GetId(&result_type);
+}
+
+opt::analysis::Vector* TransformationVectorShuffle::GetVectorType(
+ opt::IRContext* context, uint32_t id_of_vector) {
+ return context->get_type_mgr()
+ ->GetType(context->get_def_use_mgr()->GetDef(id_of_vector)->type_id())
+ ->AsVector();
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_vector_shuffle.h b/source/fuzz/transformation_vector_shuffle.h
new file mode 100644
index 0000000..81ed227
--- /dev/null
+++ b/source/fuzz/transformation_vector_shuffle.h
@@ -0,0 +1,82 @@
+// 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_FUZZ_TRANSFORMATION_VECTOR_SHUFFLE_H_
+#define SOURCE_FUZZ_TRANSFORMATION_VECTOR_SHUFFLE_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+#include "source/opt/types.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationVectorShuffle : public Transformation {
+ public:
+ explicit TransformationVectorShuffle(
+ const protobufs::TransformationVectorShuffle& message);
+
+ TransformationVectorShuffle(
+ const protobufs::InstructionDescriptor& instruction_to_insert_before,
+ uint32_t fresh_id, uint32_t vector1, uint32_t vector2,
+ const std::vector<uint32_t>& component);
+
+ // - |message_.fresh_id| must not be in use
+ // - |message_.instruction_to_insert_before| must identify an instruction
+ // before which it is legitimate to insert an OpVectorShuffle
+ // - |message_.vector1| and |message_.vector2| must be instructions of vector
+ // type, and the element types of these vectors must be the same
+ // - Each element of |message_.component| must either be 0xFFFFFFFF
+ // (representing an undefined component), or must be less than the combined
+ // sizes of the input vectors
+ // - The module must already contain a vector type with the same element type
+ // as |message_.vector1| and |message_.vector2|, and with the size of
+ // |message_component| as its element count
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // Inserts an OpVectorShuffle instruction before
+ // |message_.instruction_to_insert_before|, shuffles vectors
+ // |message_.vector1| and |message_.vector2| using the indices provided by
+ // |message_.component|, into |message_.fresh_id|. Adds a fact to the fact
+ // manager recording the fact each element of |message_.fresh_id| is
+ // synonymous with the element of |message_.vector1| or |message_.vector2|
+ // from which it came (with undefined components being ignored). If the
+ // result vector is a contiguous sub-range of one of the input vectors, a
+ // fact is added to record that |message_.fresh_id| is synonymous with this
+ // sub-range.
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ private:
+ // Returns a type id that already exists in |context| suitable for
+ // representing the result of the shuffle, where |element_type| is known to
+ // be the common element type of the vectors to which the shuffle is being
+ // applied. Returns 0 if no such id exists.
+ uint32_t GetResultTypeId(opt::IRContext* context,
+ const opt::analysis::Type& element_type) const;
+
+ static opt::analysis::Vector* GetVectorType(opt::IRContext* context,
+ uint32_t id_of_vector);
+
+ protobufs::TransformationVectorShuffle message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_VECTOR_SHUFFLE_H_
diff --git a/source/fuzz/uniform_buffer_element_descriptor.h b/source/fuzz/uniform_buffer_element_descriptor.h
index d35de57..f5d7320 100644
--- a/source/fuzz/uniform_buffer_element_descriptor.h
+++ b/source/fuzz/uniform_buffer_element_descriptor.h
@@ -49,4 +49,4 @@
} // namespace fuzz
} // namespace spvtools
-#endif // #define SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_
+#endif // SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_
diff --git a/source/link/CMakeLists.txt b/source/link/CMakeLists.txt
index 8ca4df3..d308319 100644
--- a/source/link/CMakeLists.txt
+++ b/source/link/CMakeLists.txt
@@ -17,8 +17,10 @@
spvtools_default_compile_options(SPIRV-Tools-link)
target_include_directories(SPIRV-Tools-link
- PUBLIC ${spirv-tools_SOURCE_DIR}/include
- PUBLIC ${SPIRV_HEADER_INCLUDE_DIR}
+ PUBLIC
+ $<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
+ $<BUILD_INTERFACE:${SPIRV_HEADER_INCLUDE_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
)
# We need the IR functionnalities from the optimizer
@@ -29,8 +31,16 @@
spvtools_check_symbol_exports(SPIRV-Tools-link)
if(ENABLE_SPIRV_TOOLS_INSTALL)
- install(TARGETS SPIRV-Tools-link
+ install(TARGETS SPIRV-Tools-link EXPORT SPIRV-Tools-linkTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ export(EXPORT SPIRV-Tools-linkTargets FILE SPIRV-Tools-linkTargets.cmake)
+
+ spvtools_config_package_dir(SPIRV-Tools-link PACKAGE_DIR)
+ install(EXPORT SPIRV-Tools-linkTargets FILE SPIRV-Tools-linkTargets.cmake
+ DESTINATION ${PACKAGE_DIR})
+
+ spvtools_generate_config_file(SPIRV-Tools-link)
+ install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-linkConfig.cmake DESTINATION ${PACKAGE_DIR})
endif(ENABLE_SPIRV_TOOLS_INSTALL)
diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt
index 2309ca9..0f719cb 100644
--- a/source/opt/CMakeLists.txt
+++ b/source/opt/CMakeLists.txt
@@ -27,6 +27,7 @@
composite.h
const_folding_rules.h
constants.h
+ convert_to_half_pass.h
copy_prop_arrays.h
dead_branch_elim_pass.h
dead_insert_elim_pass.h
@@ -68,7 +69,6 @@
local_redundancy_elimination.h
local_single_block_elim_pass.h
local_single_store_elim_pass.h
- local_ssa_elim_pass.h
log.h
loop_dependence.h
loop_descriptor.h
@@ -93,6 +93,7 @@
redundancy_elimination.h
reflect.h
register_pressure.h
+ relax_float_ops_pass.h
remove_duplicates_pass.h
replace_invalid_opc.h
scalar_analysis.h
@@ -132,6 +133,7 @@
composite.cpp
const_folding_rules.cpp
constants.cpp
+ convert_to_half_pass.cpp
copy_prop_arrays.cpp
dead_branch_elim_pass.cpp
dead_insert_elim_pass.cpp
@@ -173,7 +175,6 @@
local_redundancy_elimination.cpp
local_single_block_elim_pass.cpp
local_single_store_elim_pass.cpp
- local_ssa_elim_pass.cpp
loop_dependence.cpp
loop_dependence_helpers.cpp
loop_descriptor.cpp
@@ -196,6 +197,7 @@
reduce_load_size.cpp
redundancy_elimination.cpp
register_pressure.cpp
+ relax_float_ops_pass.cpp
remove_duplicates_pass.cpp
replace_invalid_opc.cpp
scalar_analysis.cpp
@@ -231,8 +233,10 @@
spvtools_default_compile_options(SPIRV-Tools-opt)
target_include_directories(SPIRV-Tools-opt
- PUBLIC ${spirv-tools_SOURCE_DIR}/include
- PUBLIC ${SPIRV_HEADER_INCLUDE_DIR}
+ PUBLIC
+ $<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
+ $<BUILD_INTERFACE:${SPIRV_HEADER_INCLUDE_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
)
# We need the assembling and disassembling functionalities in the main library.
@@ -243,8 +247,16 @@
spvtools_check_symbol_exports(SPIRV-Tools-opt)
if(ENABLE_SPIRV_TOOLS_INSTALL)
- install(TARGETS SPIRV-Tools-opt
+ install(TARGETS SPIRV-Tools-opt EXPORT SPIRV-Tools-optTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ export(EXPORT SPIRV-Tools-optTargets FILE SPIRV-Tools-optTargets.cmake)
+
+ spvtools_config_package_dir(SPIRV-Tools-opt PACKAGE_DIR)
+ install(EXPORT SPIRV-Tools-optTargets FILE SPIRV-Tools-optTargets.cmake
+ DESTINATION ${PACKAGE_DIR})
+
+ spvtools_generate_config_file(SPIRV-Tools-opt)
+ install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-optConfig.cmake DESTINATION ${PACKAGE_DIR})
endif(ENABLE_SPIRV_TOOLS_INSTALL)
diff --git a/source/opt/amd_ext_to_khr.cpp b/source/opt/amd_ext_to_khr.cpp
index 1cb5ba5..e9b7f86 100644
--- a/source/opt/amd_ext_to_khr.cpp
+++ b/source/opt/amd_ext_to_khr.cpp
@@ -14,6 +14,9 @@
#include "source/opt/amd_ext_to_khr.h"
+#include <set>
+#include <string>
+
#include "ir_builder.h"
#include "source/opt/ir_context.h"
#include "spv-amd-shader-ballot.insts.inc"
@@ -24,22 +27,125 @@
namespace {
-enum ExtOpcodes {
+enum AmdShaderBallotExtOpcodes {
AmdShaderBallotSwizzleInvocationsAMD = 1,
AmdShaderBallotSwizzleInvocationsMaskedAMD = 2,
AmdShaderBallotWriteInvocationAMD = 3,
AmdShaderBallotMbcntAMD = 4
};
+enum AmdShaderTrinaryMinMaxExtOpCodes {
+ FMin3AMD = 1,
+ UMin3AMD = 2,
+ SMin3AMD = 3,
+ FMax3AMD = 4,
+ UMax3AMD = 5,
+ SMax3AMD = 6,
+ FMid3AMD = 7,
+ UMid3AMD = 8,
+ SMid3AMD = 9
+};
+
+enum AmdGcnShader { CubeFaceCoordAMD = 2, CubeFaceIndexAMD = 1, TimeAMD = 3 };
+
analysis::Type* GetUIntType(IRContext* ctx) {
analysis::Integer int_type(32, false);
return ctx->get_type_mgr()->GetRegisteredType(&int_type);
}
+bool NotImplementedYet(IRContext*, Instruction*,
+ const std::vector<const analysis::Constant*>&) {
+ assert(false && "Not implemented.");
+ return false;
+}
+
+// Returns a folding rule that replaces |op(a,b,c)| by |op(op(a,b),c)|, where
+// |op| is either min or max. |opcode| is the binary opcode in the GLSLstd450
+// extended instruction set that corresponds to the trinary instruction being
+// replaced.
+template <GLSLstd450 opcode>
+bool ReplaceTrinaryMinMax(IRContext* ctx, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ uint32_t glsl405_ext_inst_id =
+ ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+ if (glsl405_ext_inst_id == 0) {
+ ctx->AddExtInstImport("GLSL.std.450");
+ glsl405_ext_inst_id =
+ ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+ }
+
+ InstructionBuilder ir_builder(
+ ctx, inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+
+ uint32_t op1 = inst->GetSingleWordInOperand(2);
+ uint32_t op2 = inst->GetSingleWordInOperand(3);
+ uint32_t op3 = inst->GetSingleWordInOperand(4);
+
+ Instruction* temp = ir_builder.AddNaryExtendedInstruction(
+ inst->type_id(), glsl405_ext_inst_id, opcode, {op1, op2});
+
+ Instruction::OperandList new_operands;
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl405_ext_inst_id}});
+ new_operands.push_back({SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
+ {static_cast<uint32_t>(opcode)}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {temp->result_id()}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {op3}});
+
+ inst->SetInOperands(std::move(new_operands));
+ ctx->UpdateDefUse(inst);
+ return true;
+}
+
+// Returns a folding rule that replaces |mid(a,b,c)| by |clamp(a, min(b,c),
+// max(b,c)|. The three parameters are the opcode that correspond to the min,
+// max, and clamp operations for the type of the instruction being replaced.
+template <GLSLstd450 min_opcode, GLSLstd450 max_opcode, GLSLstd450 clamp_opcode>
+bool ReplaceTrinaryMid(IRContext* ctx, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ uint32_t glsl405_ext_inst_id =
+ ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+ if (glsl405_ext_inst_id == 0) {
+ ctx->AddExtInstImport("GLSL.std.450");
+ glsl405_ext_inst_id =
+ ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+ }
+
+ InstructionBuilder ir_builder(
+ ctx, inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+
+ uint32_t op1 = inst->GetSingleWordInOperand(2);
+ uint32_t op2 = inst->GetSingleWordInOperand(3);
+ uint32_t op3 = inst->GetSingleWordInOperand(4);
+
+ Instruction* min = ir_builder.AddNaryExtendedInstruction(
+ inst->type_id(), glsl405_ext_inst_id, static_cast<uint32_t>(min_opcode),
+ {op2, op3});
+ Instruction* max = ir_builder.AddNaryExtendedInstruction(
+ inst->type_id(), glsl405_ext_inst_id, static_cast<uint32_t>(max_opcode),
+ {op2, op3});
+
+ Instruction::OperandList new_operands;
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl405_ext_inst_id}});
+ new_operands.push_back({SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
+ {static_cast<uint32_t>(clamp_opcode)}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {op1}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {min->result_id()}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {max->result_id()}});
+
+ inst->SetInOperands(std::move(new_operands));
+ ctx->UpdateDefUse(inst);
+ return true;
+}
+
// Returns a folding rule that will replace the opcode with |opcode| and add
// the capabilities required. The folding rule assumes it is folding an
// OpGroup*NonUniformAMD instruction from the SPV_AMD_shader_ballot extension.
-FoldingRule ReplaceGroupNonuniformOperationOpCode(SpvOp new_opcode) {
+template <SpvOp new_opcode>
+bool ReplaceGroupNonuniformOperationOpCode(
+ IRContext* ctx, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
switch (new_opcode) {
case SpvOpGroupNonUniformIAdd:
case SpvOpGroupNonUniformFAdd:
@@ -56,27 +162,24 @@
"Should be replacing with a group non uniform arithmetic operation.");
}
- return [new_opcode](IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- switch (inst->opcode()) {
- case SpvOpGroupIAddNonUniformAMD:
- case SpvOpGroupFAddNonUniformAMD:
- case SpvOpGroupUMinNonUniformAMD:
- case SpvOpGroupSMinNonUniformAMD:
- case SpvOpGroupFMinNonUniformAMD:
- case SpvOpGroupUMaxNonUniformAMD:
- case SpvOpGroupSMaxNonUniformAMD:
- case SpvOpGroupFMaxNonUniformAMD:
- break;
- default:
- assert(false &&
- "Should be replacing a group non uniform arithmetic operation.");
- }
+ switch (inst->opcode()) {
+ case SpvOpGroupIAddNonUniformAMD:
+ case SpvOpGroupFAddNonUniformAMD:
+ case SpvOpGroupUMinNonUniformAMD:
+ case SpvOpGroupSMinNonUniformAMD:
+ case SpvOpGroupFMinNonUniformAMD:
+ case SpvOpGroupUMaxNonUniformAMD:
+ case SpvOpGroupSMaxNonUniformAMD:
+ case SpvOpGroupFMaxNonUniformAMD:
+ break;
+ default:
+ assert(false &&
+ "Should be replacing a group non uniform arithmetic operation.");
+ }
- ctx->AddCapability(SpvCapabilityGroupNonUniformArithmetic);
- inst->SetOpcode(new_opcode);
- return true;
- };
+ ctx->AddCapability(SpvCapabilityGroupNonUniformArithmetic);
+ inst->SetOpcode(new_opcode);
+ return true;
}
// Returns a folding rule that will replace the SwizzleInvocationsAMD extended
@@ -112,84 +215,82 @@
// clang-format on
//
// Also adding the capabilities and builtins that are needed.
-FoldingRule ReplaceSwizzleInvocations() {
- return [](IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- analysis::TypeManager* type_mgr = ctx->get_type_mgr();
- analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
+bool ReplaceSwizzleInvocations(IRContext* ctx, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ analysis::TypeManager* type_mgr = ctx->get_type_mgr();
+ analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
- ctx->AddExtension("SPV_KHR_shader_ballot");
- ctx->AddCapability(SpvCapabilityGroupNonUniformBallot);
- ctx->AddCapability(SpvCapabilityGroupNonUniformShuffle);
+ ctx->AddExtension("SPV_KHR_shader_ballot");
+ ctx->AddCapability(SpvCapabilityGroupNonUniformBallot);
+ ctx->AddCapability(SpvCapabilityGroupNonUniformShuffle);
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ InstructionBuilder ir_builder(
+ ctx, inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- uint32_t data_id = inst->GetSingleWordInOperand(2);
- uint32_t offset_id = inst->GetSingleWordInOperand(3);
+ uint32_t data_id = inst->GetSingleWordInOperand(2);
+ uint32_t offset_id = inst->GetSingleWordInOperand(3);
- // Get the subgroup invocation id.
- uint32_t var_id =
- ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId);
- assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
- Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
- Instruction* var_ptr_type =
- ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
- uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1);
+ // Get the subgroup invocation id.
+ uint32_t var_id =
+ ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId);
+ assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
+ Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
+ Instruction* var_ptr_type =
+ ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
+ uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1);
- Instruction* id = ir_builder.AddLoad(uint_type_id, var_id);
+ Instruction* id = ir_builder.AddLoad(uint_type_id, var_id);
- uint32_t quad_mask = ir_builder.GetUintConstantId(3);
+ uint32_t quad_mask = ir_builder.GetUintConstantId(3);
- // This gives the offset in the group of 4 of this invocation.
- Instruction* quad_idx = ir_builder.AddBinaryOp(
- uint_type_id, SpvOpBitwiseAnd, id->result_id(), quad_mask);
+ // This gives the offset in the group of 4 of this invocation.
+ Instruction* quad_idx = ir_builder.AddBinaryOp(uint_type_id, SpvOpBitwiseAnd,
+ id->result_id(), quad_mask);
- // Get the invocation id of the first invocation in the group of 4.
- Instruction* quad_ldr = ir_builder.AddBinaryOp(
- uint_type_id, SpvOpBitwiseXor, id->result_id(), quad_idx->result_id());
+ // Get the invocation id of the first invocation in the group of 4.
+ Instruction* quad_ldr = ir_builder.AddBinaryOp(
+ uint_type_id, SpvOpBitwiseXor, id->result_id(), quad_idx->result_id());
- // Get the offset of the target invocation from the offset vector.
- Instruction* my_offset =
- ir_builder.AddBinaryOp(uint_type_id, SpvOpVectorExtractDynamic,
- offset_id, quad_idx->result_id());
+ // Get the offset of the target invocation from the offset vector.
+ Instruction* my_offset =
+ ir_builder.AddBinaryOp(uint_type_id, SpvOpVectorExtractDynamic, offset_id,
+ quad_idx->result_id());
- // Determine the index of the invocation to read from.
- Instruction* target_inv = ir_builder.AddBinaryOp(
- uint_type_id, SpvOpIAdd, quad_ldr->result_id(), my_offset->result_id());
+ // Determine the index of the invocation to read from.
+ Instruction* target_inv = ir_builder.AddBinaryOp(
+ uint_type_id, SpvOpIAdd, quad_ldr->result_id(), my_offset->result_id());
- // Do the group operations
- uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
- uint32_t subgroup_scope = ir_builder.GetUintConstantId(SpvScopeSubgroup);
- const auto* ballot_value_const = const_mgr->GetConstant(
- type_mgr->GetUIntVectorType(4),
- {uint_max_id, uint_max_id, uint_max_id, uint_max_id});
- Instruction* ballot_value =
- const_mgr->GetDefiningInstruction(ballot_value_const);
- Instruction* is_active = ir_builder.AddNaryOp(
- type_mgr->GetBoolTypeId(), SpvOpGroupNonUniformBallotBitExtract,
- {subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
- Instruction* shuffle = ir_builder.AddNaryOp(
- inst->type_id(), SpvOpGroupNonUniformShuffle,
- {subgroup_scope, data_id, target_inv->result_id()});
+ // Do the group operations
+ uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
+ uint32_t subgroup_scope = ir_builder.GetUintConstantId(SpvScopeSubgroup);
+ const auto* ballot_value_const = const_mgr->GetConstant(
+ type_mgr->GetUIntVectorType(4),
+ {uint_max_id, uint_max_id, uint_max_id, uint_max_id});
+ Instruction* ballot_value =
+ const_mgr->GetDefiningInstruction(ballot_value_const);
+ Instruction* is_active = ir_builder.AddNaryOp(
+ type_mgr->GetBoolTypeId(), SpvOpGroupNonUniformBallotBitExtract,
+ {subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
+ Instruction* shuffle =
+ ir_builder.AddNaryOp(inst->type_id(), SpvOpGroupNonUniformShuffle,
+ {subgroup_scope, data_id, target_inv->result_id()});
- // Create the null constant to use in the select.
- const auto* null = const_mgr->GetConstant(
- type_mgr->GetType(inst->type_id()), std::vector<uint32_t>());
- Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
+ // Create the null constant to use in the select.
+ const auto* null = const_mgr->GetConstant(type_mgr->GetType(inst->type_id()),
+ std::vector<uint32_t>());
+ Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
- // Build the select.
- inst->SetOpcode(SpvOpSelect);
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {null_inst->result_id()}});
+ // Build the select.
+ inst->SetOpcode(SpvOpSelect);
+ Instruction::OperandList new_operands;
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {null_inst->result_id()}});
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- };
+ inst->SetInOperands(std::move(new_operands));
+ ctx->UpdateDefUse(inst);
+ return true;
}
// Returns a folding rule that will replace the SwizzleInvocationsMaskedAMD
@@ -225,89 +326,86 @@
// clang-format on
//
// Also adding the capabilities and builtins that are needed.
-FoldingRule ReplaceSwizzleInvocationsMasked() {
- return [](IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- analysis::TypeManager* type_mgr = ctx->get_type_mgr();
- analysis::DefUseManager* def_use_mgr = ctx->get_def_use_mgr();
- analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
+bool ReplaceSwizzleInvocationsMasked(
+ IRContext* ctx, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ analysis::TypeManager* type_mgr = ctx->get_type_mgr();
+ analysis::DefUseManager* def_use_mgr = ctx->get_def_use_mgr();
+ analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
- // ctx->AddCapability(SpvCapabilitySubgroupBallotKHR);
- ctx->AddCapability(SpvCapabilityGroupNonUniformBallot);
- ctx->AddCapability(SpvCapabilityGroupNonUniformShuffle);
+ ctx->AddCapability(SpvCapabilityGroupNonUniformBallot);
+ ctx->AddCapability(SpvCapabilityGroupNonUniformShuffle);
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ InstructionBuilder ir_builder(
+ ctx, inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- // Get the operands to inst, and the components of the mask
- uint32_t data_id = inst->GetSingleWordInOperand(2);
+ // Get the operands to inst, and the components of the mask
+ uint32_t data_id = inst->GetSingleWordInOperand(2);
- Instruction* mask_inst =
- def_use_mgr->GetDef(inst->GetSingleWordInOperand(3));
- assert(mask_inst->opcode() == SpvOpConstantComposite &&
- "The mask is suppose to be a vector constant.");
- assert(mask_inst->NumInOperands() == 3 &&
- "The mask is suppose to have 3 components.");
+ Instruction* mask_inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(3));
+ assert(mask_inst->opcode() == SpvOpConstantComposite &&
+ "The mask is suppose to be a vector constant.");
+ assert(mask_inst->NumInOperands() == 3 &&
+ "The mask is suppose to have 3 components.");
- uint32_t uint_x = mask_inst->GetSingleWordInOperand(0);
- uint32_t uint_y = mask_inst->GetSingleWordInOperand(1);
- uint32_t uint_z = mask_inst->GetSingleWordInOperand(2);
+ uint32_t uint_x = mask_inst->GetSingleWordInOperand(0);
+ uint32_t uint_y = mask_inst->GetSingleWordInOperand(1);
+ uint32_t uint_z = mask_inst->GetSingleWordInOperand(2);
- // Get the subgroup invocation id.
- uint32_t var_id =
- ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId);
- ctx->AddExtension("SPV_KHR_shader_ballot");
- assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
- Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
- Instruction* var_ptr_type =
- ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
- uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1);
+ // Get the subgroup invocation id.
+ uint32_t var_id =
+ ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId);
+ ctx->AddExtension("SPV_KHR_shader_ballot");
+ assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
+ Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
+ Instruction* var_ptr_type =
+ ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
+ uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1);
- Instruction* id = ir_builder.AddLoad(uint_type_id, var_id);
+ Instruction* id = ir_builder.AddLoad(uint_type_id, var_id);
- // Do the bitwise operations.
- uint32_t mask_extended = ir_builder.GetUintConstantId(0xFFFFFFE0);
- Instruction* and_mask = ir_builder.AddBinaryOp(uint_type_id, SpvOpBitwiseOr,
- uint_x, mask_extended);
- Instruction* and_result = ir_builder.AddBinaryOp(
- uint_type_id, SpvOpBitwiseAnd, id->result_id(), and_mask->result_id());
- Instruction* or_result = ir_builder.AddBinaryOp(
- uint_type_id, SpvOpBitwiseOr, and_result->result_id(), uint_y);
- Instruction* target_inv = ir_builder.AddBinaryOp(
- uint_type_id, SpvOpBitwiseXor, or_result->result_id(), uint_z);
+ // Do the bitwise operations.
+ uint32_t mask_extended = ir_builder.GetUintConstantId(0xFFFFFFE0);
+ Instruction* and_mask = ir_builder.AddBinaryOp(uint_type_id, SpvOpBitwiseOr,
+ uint_x, mask_extended);
+ Instruction* and_result = ir_builder.AddBinaryOp(
+ uint_type_id, SpvOpBitwiseAnd, id->result_id(), and_mask->result_id());
+ Instruction* or_result = ir_builder.AddBinaryOp(
+ uint_type_id, SpvOpBitwiseOr, and_result->result_id(), uint_y);
+ Instruction* target_inv = ir_builder.AddBinaryOp(
+ uint_type_id, SpvOpBitwiseXor, or_result->result_id(), uint_z);
- // Do the group operations
- uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
- uint32_t subgroup_scope = ir_builder.GetUintConstantId(SpvScopeSubgroup);
- const auto* ballot_value_const = const_mgr->GetConstant(
- type_mgr->GetUIntVectorType(4),
- {uint_max_id, uint_max_id, uint_max_id, uint_max_id});
- Instruction* ballot_value =
- const_mgr->GetDefiningInstruction(ballot_value_const);
- Instruction* is_active = ir_builder.AddNaryOp(
- type_mgr->GetBoolTypeId(), SpvOpGroupNonUniformBallotBitExtract,
- {subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
- Instruction* shuffle = ir_builder.AddNaryOp(
- inst->type_id(), SpvOpGroupNonUniformShuffle,
- {subgroup_scope, data_id, target_inv->result_id()});
+ // Do the group operations
+ uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
+ uint32_t subgroup_scope = ir_builder.GetUintConstantId(SpvScopeSubgroup);
+ const auto* ballot_value_const = const_mgr->GetConstant(
+ type_mgr->GetUIntVectorType(4),
+ {uint_max_id, uint_max_id, uint_max_id, uint_max_id});
+ Instruction* ballot_value =
+ const_mgr->GetDefiningInstruction(ballot_value_const);
+ Instruction* is_active = ir_builder.AddNaryOp(
+ type_mgr->GetBoolTypeId(), SpvOpGroupNonUniformBallotBitExtract,
+ {subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
+ Instruction* shuffle =
+ ir_builder.AddNaryOp(inst->type_id(), SpvOpGroupNonUniformShuffle,
+ {subgroup_scope, data_id, target_inv->result_id()});
- // Create the null constant to use in the select.
- const auto* null = const_mgr->GetConstant(
- type_mgr->GetType(inst->type_id()), std::vector<uint32_t>());
- Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
+ // Create the null constant to use in the select.
+ const auto* null = const_mgr->GetConstant(type_mgr->GetType(inst->type_id()),
+ std::vector<uint32_t>());
+ Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
- // Build the select.
- inst->SetOpcode(SpvOpSelect);
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {null_inst->result_id()}});
+ // Build the select.
+ inst->SetOpcode(SpvOpSelect);
+ Instruction::OperandList new_operands;
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {null_inst->result_id()}});
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- };
+ inst->SetInOperands(std::move(new_operands));
+ ctx->UpdateDefUse(inst);
+ return true;
}
// Returns a folding rule that will replace the WriteInvocationAMD extended
@@ -326,40 +424,38 @@
// %result = OpSelect %type %cmp %write_value %input_value
//
// Also adding the capabilities and builtins that are needed.
-FoldingRule ReplaceWriteInvocation() {
- return [](IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- uint32_t var_id =
- ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId);
- ctx->AddCapability(SpvCapabilitySubgroupBallotKHR);
- ctx->AddExtension("SPV_KHR_shader_ballot");
- assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
- Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
- Instruction* var_ptr_type =
- ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
+bool ReplaceWriteInvocation(IRContext* ctx, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ uint32_t var_id =
+ ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId);
+ ctx->AddCapability(SpvCapabilitySubgroupBallotKHR);
+ ctx->AddExtension("SPV_KHR_shader_ballot");
+ assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
+ Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
+ Instruction* var_ptr_type =
+ ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- Instruction* t =
- ir_builder.AddLoad(var_ptr_type->GetSingleWordInOperand(1), var_id);
- analysis::Bool bool_type;
- uint32_t bool_type_id = ctx->get_type_mgr()->GetTypeInstruction(&bool_type);
- Instruction* cmp =
- ir_builder.AddBinaryOp(bool_type_id, SpvOpIEqual, t->result_id(),
- inst->GetSingleWordInOperand(4));
+ InstructionBuilder ir_builder(
+ ctx, inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ Instruction* t =
+ ir_builder.AddLoad(var_ptr_type->GetSingleWordInOperand(1), var_id);
+ analysis::Bool bool_type;
+ uint32_t bool_type_id = ctx->get_type_mgr()->GetTypeInstruction(&bool_type);
+ Instruction* cmp =
+ ir_builder.AddBinaryOp(bool_type_id, SpvOpIEqual, t->result_id(),
+ inst->GetSingleWordInOperand(4));
- // Build a select.
- inst->SetOpcode(SpvOpSelect);
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {cmp->result_id()}});
- new_operands.push_back(inst->GetInOperand(3));
- new_operands.push_back(inst->GetInOperand(2));
+ // Build a select.
+ inst->SetOpcode(SpvOpSelect);
+ Instruction::OperandList new_operands;
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {cmp->result_id()}});
+ new_operands.push_back(inst->GetInOperand(3));
+ new_operands.push_back(inst->GetInOperand(2));
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- };
+ inst->SetInOperands(std::move(new_operands));
+ ctx->UpdateDefUse(inst);
+ return true;
}
// Returns a folding rule that will replace the MbcntAMD extended instruction in
@@ -384,51 +480,324 @@
// %result = OpBitCount %uint %and
//
// Also adding the capabilities and builtins that are needed.
-FoldingRule ReplaceMbcnt() {
- return [](IRContext* context, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- analysis::TypeManager* type_mgr = context->get_type_mgr();
- analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
+bool ReplaceMbcnt(IRContext* context, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ analysis::TypeManager* type_mgr = context->get_type_mgr();
+ analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
- uint32_t var_id = context->GetBuiltinInputVarId(SpvBuiltInSubgroupLtMask);
- assert(var_id != 0 && "Could not get SubgroupLtMask variable.");
- context->AddCapability(SpvCapabilityGroupNonUniformBallot);
- Instruction* var_inst = def_use_mgr->GetDef(var_id);
- Instruction* var_ptr_type = def_use_mgr->GetDef(var_inst->type_id());
- Instruction* var_type =
- def_use_mgr->GetDef(var_ptr_type->GetSingleWordInOperand(1));
- assert(var_type->opcode() == SpvOpTypeVector &&
- "Variable is suppose to be a vector of 4 ints");
+ uint32_t var_id = context->GetBuiltinInputVarId(SpvBuiltInSubgroupLtMask);
+ assert(var_id != 0 && "Could not get SubgroupLtMask variable.");
+ context->AddCapability(SpvCapabilityGroupNonUniformBallot);
+ Instruction* var_inst = def_use_mgr->GetDef(var_id);
+ Instruction* var_ptr_type = def_use_mgr->GetDef(var_inst->type_id());
+ Instruction* var_type =
+ def_use_mgr->GetDef(var_ptr_type->GetSingleWordInOperand(1));
+ assert(var_type->opcode() == SpvOpTypeVector &&
+ "Variable is suppose to be a vector of 4 ints");
- // Get the type for the shuffle.
- analysis::Vector temp_type(GetUIntType(context), 2);
- const analysis::Type* shuffle_type =
- context->get_type_mgr()->GetRegisteredType(&temp_type);
- uint32_t shuffle_type_id = type_mgr->GetTypeInstruction(shuffle_type);
+ // Get the type for the shuffle.
+ analysis::Vector temp_type(GetUIntType(context), 2);
+ const analysis::Type* shuffle_type =
+ context->get_type_mgr()->GetRegisteredType(&temp_type);
+ uint32_t shuffle_type_id = type_mgr->GetTypeInstruction(shuffle_type);
- uint32_t mask_id = inst->GetSingleWordInOperand(2);
- Instruction* mask_inst = def_use_mgr->GetDef(mask_id);
+ uint32_t mask_id = inst->GetSingleWordInOperand(2);
+ Instruction* mask_inst = def_use_mgr->GetDef(mask_id);
- // Testing with amd's shader compiler shows that a 64-bit mask is expected.
- assert(type_mgr->GetType(mask_inst->type_id())->AsInteger() != nullptr);
- assert(type_mgr->GetType(mask_inst->type_id())->AsInteger()->width() == 64);
+ // Testing with amd's shader compiler shows that a 64-bit mask is expected.
+ assert(type_mgr->GetType(mask_inst->type_id())->AsInteger() != nullptr);
+ assert(type_mgr->GetType(mask_inst->type_id())->AsInteger()->width() == 64);
- InstructionBuilder ir_builder(
- context, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- Instruction* load = ir_builder.AddLoad(var_type->result_id(), var_id);
- Instruction* shuffle = ir_builder.AddVectorShuffle(
- shuffle_type_id, load->result_id(), load->result_id(), {0, 1});
- Instruction* bitcast = ir_builder.AddUnaryOp(
- mask_inst->type_id(), SpvOpBitcast, shuffle->result_id());
- Instruction* t = ir_builder.AddBinaryOp(
- mask_inst->type_id(), SpvOpBitwiseAnd, bitcast->result_id(), mask_id);
+ InstructionBuilder ir_builder(
+ context, inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ Instruction* load = ir_builder.AddLoad(var_type->result_id(), var_id);
+ Instruction* shuffle = ir_builder.AddVectorShuffle(
+ shuffle_type_id, load->result_id(), load->result_id(), {0, 1});
+ Instruction* bitcast = ir_builder.AddUnaryOp(
+ mask_inst->type_id(), SpvOpBitcast, shuffle->result_id());
+ Instruction* t = ir_builder.AddBinaryOp(mask_inst->type_id(), SpvOpBitwiseAnd,
+ bitcast->result_id(), mask_id);
- inst->SetOpcode(SpvOpBitCount);
- inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {t->result_id()}}});
- context->UpdateDefUse(inst);
- return true;
- };
+ inst->SetOpcode(SpvOpBitCount);
+ inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {t->result_id()}}});
+ context->UpdateDefUse(inst);
+ return true;
+}
+
+// A folding rule that will replace the CubeFaceCoordAMD extended
+// instruction in the SPV_AMD_gcn_shader_ballot. Returns true if the folding is
+// successful.
+//
+// The instruction
+//
+// %result = OpExtInst %v2float %1 CubeFaceCoordAMD %input
+//
+// with
+//
+// %x = OpCompositeExtract %float %input 0
+// %y = OpCompositeExtract %float %input 1
+// %z = OpCompositeExtract %float %input 2
+// %nx = OpFNegate %float %x
+// %ny = OpFNegate %float %y
+// %nz = OpFNegate %float %z
+// %ax = OpExtInst %float %n_1 FAbs %x
+// %ay = OpExtInst %float %n_1 FAbs %y
+// %az = OpExtInst %float %n_1 FAbs %z
+// %amax_x_y = OpExtInst %float %n_1 FMax %ay %ax
+// %amax = OpExtInst %float %n_1 FMax %az %amax_x_y
+// %cubema = OpFMul %float %float_2 %amax
+// %is_z_max = OpFOrdGreaterThanEqual %bool %az %amax_x_y
+// %not_is_z_max = OpLogicalNot %bool %is_z_max
+// %y_gt_x = OpFOrdGreaterThanEqual %bool %ay %ax
+// %is_y_max = OpLogicalAnd %bool %not_is_z_max %y_gt_x
+// %is_z_neg = OpFOrdLessThan %bool %z %float_0
+// %cubesc_case_1 = OpSelect %float %is_z_neg %nx %x
+// %is_x_neg = OpFOrdLessThan %bool %x %float_0
+// %cubesc_case_2 = OpSelect %float %is_x_neg %z %nz
+// %sel = OpSelect %float %is_y_max %x %cubesc_case_2
+// %cubesc = OpSelect %float %is_z_max %cubesc_case_1 %sel
+// %is_y_neg = OpFOrdLessThan %bool %y %float_0
+// %cubetc_case_1 = OpSelect %float %is_y_neg %nz %z
+// %cubetc = OpSelect %float %is_y_max %cubetc_case_1 %ny
+// %cube = OpCompositeConstruct %v2float %cubesc %cubetc
+// %denom = OpCompositeConstruct %v2float %cubema %cubema
+// %div = OpFDiv %v2float %cube %denom
+// %result = OpFAdd %v2float %div %const
+//
+// Also adding the capabilities and builtins that are needed.
+bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ analysis::TypeManager* type_mgr = ctx->get_type_mgr();
+ analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
+
+ uint32_t float_type_id = type_mgr->GetFloatTypeId();
+ const analysis::Type* v2_float_type = type_mgr->GetFloatVectorType(2);
+ uint32_t v2_float_type_id = type_mgr->GetId(v2_float_type);
+ uint32_t bool_id = type_mgr->GetBoolTypeId();
+
+ InstructionBuilder ir_builder(
+ ctx, inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+
+ uint32_t input_id = inst->GetSingleWordInOperand(2);
+ uint32_t glsl405_ext_inst_id =
+ ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+ if (glsl405_ext_inst_id == 0) {
+ ctx->AddExtInstImport("GLSL.std.450");
+ glsl405_ext_inst_id =
+ ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+ }
+
+ // Get the constants that will be used.
+ uint32_t f0_const_id = const_mgr->GetFloatConst(0.0);
+ uint32_t f2_const_id = const_mgr->GetFloatConst(2.0);
+ uint32_t f0_5_const_id = const_mgr->GetFloatConst(0.5);
+ const analysis::Constant* vec_const =
+ const_mgr->GetConstant(v2_float_type, {f0_5_const_id, f0_5_const_id});
+ uint32_t vec_const_id =
+ const_mgr->GetDefiningInstruction(vec_const)->result_id();
+
+ // Extract the input values.
+ Instruction* x = ir_builder.AddCompositeExtract(float_type_id, input_id, {0});
+ Instruction* y = ir_builder.AddCompositeExtract(float_type_id, input_id, {1});
+ Instruction* z = ir_builder.AddCompositeExtract(float_type_id, input_id, {2});
+
+ // Negate the input values.
+ Instruction* nx =
+ ir_builder.AddUnaryOp(float_type_id, SpvOpFNegate, x->result_id());
+ Instruction* ny =
+ ir_builder.AddUnaryOp(float_type_id, SpvOpFNegate, y->result_id());
+ Instruction* nz =
+ ir_builder.AddUnaryOp(float_type_id, SpvOpFNegate, z->result_id());
+
+ // Get the abolsute values of the inputs.
+ Instruction* ax = ir_builder.AddNaryExtendedInstruction(
+ float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {x->result_id()});
+ Instruction* ay = ir_builder.AddNaryExtendedInstruction(
+ float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {y->result_id()});
+ Instruction* az = ir_builder.AddNaryExtendedInstruction(
+ float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()});
+
+ // Find which values are negative. Used in later computations.
+ Instruction* is_z_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
+ z->result_id(), f0_const_id);
+ Instruction* is_y_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
+ y->result_id(), f0_const_id);
+ Instruction* is_x_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
+ x->result_id(), f0_const_id);
+
+ // Compute cubema
+ Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction(
+ float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
+ {ax->result_id(), ay->result_id()});
+ Instruction* amax = ir_builder.AddNaryExtendedInstruction(
+ float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
+ {az->result_id(), amax_x_y->result_id()});
+ Instruction* cubema = ir_builder.AddBinaryOp(float_type_id, SpvOpFMul,
+ f2_const_id, amax->result_id());
+
+ // Do the comparisons needed for computing cubesc and cubetc.
+ Instruction* is_z_max =
+ ir_builder.AddBinaryOp(bool_id, SpvOpFOrdGreaterThanEqual,
+ az->result_id(), amax_x_y->result_id());
+ Instruction* not_is_z_max =
+ ir_builder.AddUnaryOp(bool_id, SpvOpLogicalNot, is_z_max->result_id());
+ Instruction* y_gr_x = ir_builder.AddBinaryOp(
+ bool_id, SpvOpFOrdGreaterThanEqual, ay->result_id(), ax->result_id());
+ Instruction* is_y_max = ir_builder.AddBinaryOp(
+ bool_id, SpvOpLogicalAnd, not_is_z_max->result_id(), y_gr_x->result_id());
+
+ // Select the correct value for cubesc.
+ Instruction* cubesc_case_1 = ir_builder.AddSelect(
+ float_type_id, is_z_neg->result_id(), nx->result_id(), x->result_id());
+ Instruction* cubesc_case_2 = ir_builder.AddSelect(
+ float_type_id, is_x_neg->result_id(), z->result_id(), nz->result_id());
+ Instruction* sel =
+ ir_builder.AddSelect(float_type_id, is_y_max->result_id(), x->result_id(),
+ cubesc_case_2->result_id());
+ Instruction* cubesc =
+ ir_builder.AddSelect(float_type_id, is_z_max->result_id(),
+ cubesc_case_1->result_id(), sel->result_id());
+
+ // Select the correct value for cubetc.
+ Instruction* cubetc_case_1 = ir_builder.AddSelect(
+ float_type_id, is_y_neg->result_id(), nz->result_id(), z->result_id());
+ Instruction* cubetc =
+ ir_builder.AddSelect(float_type_id, is_y_max->result_id(),
+ cubetc_case_1->result_id(), ny->result_id());
+
+ // Do the division
+ Instruction* cube = ir_builder.AddCompositeConstruct(
+ v2_float_type_id, {cubesc->result_id(), cubetc->result_id()});
+ Instruction* denom = ir_builder.AddCompositeConstruct(
+ v2_float_type_id, {cubema->result_id(), cubema->result_id()});
+ Instruction* div = ir_builder.AddBinaryOp(
+ v2_float_type_id, SpvOpFDiv, cube->result_id(), denom->result_id());
+
+ // Get the final result by adding 0.5 to |div|.
+ inst->SetOpcode(SpvOpFAdd);
+ Instruction::OperandList new_operands;
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {div->result_id()}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {vec_const_id}});
+
+ inst->SetInOperands(std::move(new_operands));
+ ctx->UpdateDefUse(inst);
+ return true;
+}
+
+// A folding rule that will replace the CubeFaceCoordAMD extended
+// instruction in the SPV_AMD_gcn_shader_ballot. Returns true if the folding
+// is successful.
+//
+// The instruction
+//
+// %result = OpExtInst %v2float %1 CubeFaceCoordAMD %input
+//
+// with
+//
+// %x = OpCompositeExtract %float %input 0
+// %y = OpCompositeExtract %float %input 1
+// %z = OpCompositeExtract %float %input 2
+// %ax = OpExtInst %float %n_1 FAbs %x
+// %ay = OpExtInst %float %n_1 FAbs %y
+// %az = OpExtInst %float %n_1 FAbs %z
+// %is_z_neg = OpFOrdLessThan %bool %z %float_0
+// %is_y_neg = OpFOrdLessThan %bool %y %float_0
+// %is_x_neg = OpFOrdLessThan %bool %x %float_0
+// %amax_x_y = OpExtInst %float %n_1 FMax %ay %ax
+// %is_z_max = OpFOrdGreaterThanEqual %bool %az %amax_x_y
+// %y_gt_x = OpFOrdGreaterThanEqual %bool %ay %ax
+// %case_z = OpSelect %float %is_z_neg %float_5 %float4
+// %case_y = OpSelect %float %is_y_neg %float_3 %float2
+// %case_x = OpSelect %float %is_x_neg %float_1 %float0
+// %sel = OpSelect %float %y_gt_x %case_y %case_x
+// %result = OpSelect %float %is_z_max %case_z %sel
+//
+// Also adding the capabilities and builtins that are needed.
+bool ReplaceCubeFaceIndex(IRContext* ctx, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ analysis::TypeManager* type_mgr = ctx->get_type_mgr();
+ analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
+
+ uint32_t float_type_id = type_mgr->GetFloatTypeId();
+ uint32_t bool_id = type_mgr->GetBoolTypeId();
+
+ InstructionBuilder ir_builder(
+ ctx, inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+
+ uint32_t input_id = inst->GetSingleWordInOperand(2);
+ uint32_t glsl405_ext_inst_id =
+ ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+ if (glsl405_ext_inst_id == 0) {
+ ctx->AddExtInstImport("GLSL.std.450");
+ glsl405_ext_inst_id =
+ ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+ }
+
+ // Get the constants that will be used.
+ uint32_t f0_const_id = const_mgr->GetFloatConst(0.0);
+ uint32_t f1_const_id = const_mgr->GetFloatConst(1.0);
+ uint32_t f2_const_id = const_mgr->GetFloatConst(2.0);
+ uint32_t f3_const_id = const_mgr->GetFloatConst(3.0);
+ uint32_t f4_const_id = const_mgr->GetFloatConst(4.0);
+ uint32_t f5_const_id = const_mgr->GetFloatConst(5.0);
+
+ // Extract the input values.
+ Instruction* x = ir_builder.AddCompositeExtract(float_type_id, input_id, {0});
+ Instruction* y = ir_builder.AddCompositeExtract(float_type_id, input_id, {1});
+ Instruction* z = ir_builder.AddCompositeExtract(float_type_id, input_id, {2});
+
+ // Get the absolute values of the inputs.
+ Instruction* ax = ir_builder.AddNaryExtendedInstruction(
+ float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {x->result_id()});
+ Instruction* ay = ir_builder.AddNaryExtendedInstruction(
+ float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {y->result_id()});
+ Instruction* az = ir_builder.AddNaryExtendedInstruction(
+ float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()});
+
+ // Find which values are negative. Used in later computations.
+ Instruction* is_z_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
+ z->result_id(), f0_const_id);
+ Instruction* is_y_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
+ y->result_id(), f0_const_id);
+ Instruction* is_x_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
+ x->result_id(), f0_const_id);
+
+ // Find the max value.
+ Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction(
+ float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
+ {ax->result_id(), ay->result_id()});
+ Instruction* is_z_max =
+ ir_builder.AddBinaryOp(bool_id, SpvOpFOrdGreaterThanEqual,
+ az->result_id(), amax_x_y->result_id());
+ Instruction* y_gr_x = ir_builder.AddBinaryOp(
+ bool_id, SpvOpFOrdGreaterThanEqual, ay->result_id(), ax->result_id());
+
+ // Get the value for each case.
+ Instruction* case_z = ir_builder.AddSelect(
+ float_type_id, is_z_neg->result_id(), f5_const_id, f4_const_id);
+ Instruction* case_y = ir_builder.AddSelect(
+ float_type_id, is_y_neg->result_id(), f3_const_id, f2_const_id);
+ Instruction* case_x = ir_builder.AddSelect(
+ float_type_id, is_x_neg->result_id(), f1_const_id, f0_const_id);
+
+ // Select the correct case.
+ Instruction* sel =
+ ir_builder.AddSelect(float_type_id, y_gr_x->result_id(),
+ case_y->result_id(), case_x->result_id());
+
+ // Get the final result by adding 0.5 to |div|.
+ inst->SetOpcode(SpvOpSelect);
+ Instruction::OperandList new_operands;
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_z_max->result_id()}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {case_z->result_id()}});
+ new_operands.push_back({SPV_OPERAND_TYPE_ID, {sel->result_id()}});
+
+ inst->SetInOperands(std::move(new_operands));
+ ctx->UpdateDefUse(inst);
+ return true;
}
class AmdExtFoldingRules : public FoldingRules {
@@ -438,33 +807,70 @@
protected:
virtual void AddFoldingRules() override {
rules_[SpvOpGroupIAddNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode(SpvOpGroupNonUniformIAdd));
+ ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformIAdd>);
rules_[SpvOpGroupFAddNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode(SpvOpGroupNonUniformFAdd));
+ ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformFAdd>);
rules_[SpvOpGroupUMinNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode(SpvOpGroupNonUniformUMin));
+ ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformUMin>);
rules_[SpvOpGroupSMinNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode(SpvOpGroupNonUniformSMin));
+ ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformSMin>);
rules_[SpvOpGroupFMinNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode(SpvOpGroupNonUniformFMin));
+ ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformFMin>);
rules_[SpvOpGroupUMaxNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode(SpvOpGroupNonUniformUMax));
+ ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformUMax>);
rules_[SpvOpGroupSMaxNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode(SpvOpGroupNonUniformSMax));
+ ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformSMax>);
rules_[SpvOpGroupFMaxNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode(SpvOpGroupNonUniformFMax));
+ ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformFMax>);
uint32_t extension_id =
context()->module()->GetExtInstImportId("SPV_AMD_shader_ballot");
- ext_rules_[{extension_id, AmdShaderBallotSwizzleInvocationsAMD}].push_back(
- ReplaceSwizzleInvocations());
- ext_rules_[{extension_id, AmdShaderBallotSwizzleInvocationsMaskedAMD}]
- .push_back(ReplaceSwizzleInvocationsMasked());
- ext_rules_[{extension_id, AmdShaderBallotWriteInvocationAMD}].push_back(
- ReplaceWriteInvocation());
- ext_rules_[{extension_id, AmdShaderBallotMbcntAMD}].push_back(
- ReplaceMbcnt());
+ if (extension_id != 0) {
+ ext_rules_[{extension_id, AmdShaderBallotSwizzleInvocationsAMD}]
+ .push_back(ReplaceSwizzleInvocations);
+ ext_rules_[{extension_id, AmdShaderBallotSwizzleInvocationsMaskedAMD}]
+ .push_back(ReplaceSwizzleInvocationsMasked);
+ ext_rules_[{extension_id, AmdShaderBallotWriteInvocationAMD}].push_back(
+ ReplaceWriteInvocation);
+ ext_rules_[{extension_id, AmdShaderBallotMbcntAMD}].push_back(
+ ReplaceMbcnt);
+ }
+
+ extension_id = context()->module()->GetExtInstImportId(
+ "SPV_AMD_shader_trinary_minmax");
+
+ if (extension_id != 0) {
+ ext_rules_[{extension_id, FMin3AMD}].push_back(
+ ReplaceTrinaryMinMax<GLSLstd450FMin>);
+ ext_rules_[{extension_id, UMin3AMD}].push_back(
+ ReplaceTrinaryMinMax<GLSLstd450UMin>);
+ ext_rules_[{extension_id, SMin3AMD}].push_back(
+ ReplaceTrinaryMinMax<GLSLstd450SMin>);
+ ext_rules_[{extension_id, FMax3AMD}].push_back(
+ ReplaceTrinaryMinMax<GLSLstd450FMax>);
+ ext_rules_[{extension_id, UMax3AMD}].push_back(
+ ReplaceTrinaryMinMax<GLSLstd450UMax>);
+ ext_rules_[{extension_id, SMax3AMD}].push_back(
+ ReplaceTrinaryMinMax<GLSLstd450SMax>);
+ ext_rules_[{extension_id, FMid3AMD}].push_back(
+ ReplaceTrinaryMid<GLSLstd450FMin, GLSLstd450FMax, GLSLstd450FClamp>);
+ ext_rules_[{extension_id, UMid3AMD}].push_back(
+ ReplaceTrinaryMid<GLSLstd450UMin, GLSLstd450UMax, GLSLstd450UClamp>);
+ ext_rules_[{extension_id, SMid3AMD}].push_back(
+ ReplaceTrinaryMid<GLSLstd450SMin, GLSLstd450SMax, GLSLstd450SClamp>);
+ }
+
+ extension_id =
+ context()->module()->GetExtInstImportId("SPV_AMD_gcn_shader");
+
+ if (extension_id != 0) {
+ ext_rules_[{extension_id, CubeFaceCoordAMD}].push_back(
+ ReplaceCubeFaceCoord);
+ ext_rules_[{extension_id, CubeFaceIndexAMD}].push_back(
+ ReplaceCubeFaceIndex);
+ ext_rules_[{extension_id, TimeAMD}].push_back(NotImplementedYet);
+ }
}
};
@@ -497,12 +903,15 @@
// Now that instruction that require the extensions have been removed, we can
// remove the extension instructions.
+ std::set<std::string> ext_to_remove = {"SPV_AMD_shader_ballot",
+ "SPV_AMD_shader_trinary_minmax",
+ "SPV_AMD_gcn_shader"};
+
std::vector<Instruction*> to_be_killed;
for (Instruction& inst : context()->module()->extensions()) {
if (inst.opcode() == SpvOpExtension) {
- if (!strcmp("SPV_AMD_shader_ballot",
- reinterpret_cast<const char*>(
- &(inst.GetInOperand(0).words[0])))) {
+ if (ext_to_remove.count(reinterpret_cast<const char*>(
+ &(inst.GetInOperand(0).words[0]))) != 0) {
to_be_killed.push_back(&inst);
}
}
@@ -510,9 +919,8 @@
for (Instruction& inst : context()->ext_inst_imports()) {
if (inst.opcode() == SpvOpExtInstImport) {
- if (!strcmp("SPV_AMD_shader_ballot",
- reinterpret_cast<const char*>(
- &(inst.GetInOperand(0).words[0])))) {
+ if (ext_to_remove.count(reinterpret_cast<const char*>(
+ &(inst.GetInOperand(0).words[0]))) != 0) {
to_be_killed.push_back(&inst);
}
}
diff --git a/source/opt/cfg.cpp b/source/opt/cfg.cpp
index 72693cb..ac0fcc3 100644
--- a/source/opt/cfg.cpp
+++ b/source/opt/cfg.cpp
@@ -110,15 +110,26 @@
void CFG::ForEachBlockInReversePostOrder(
BasicBlock* bb, const std::function<void(BasicBlock*)>& f) {
+ WhileEachBlockInReversePostOrder(bb, [f](BasicBlock* b) {
+ f(b);
+ return true;
+ });
+}
+
+bool CFG::WhileEachBlockInReversePostOrder(
+ BasicBlock* bb, const std::function<bool(BasicBlock*)>& f) {
std::vector<BasicBlock*> po;
std::unordered_set<BasicBlock*> seen;
ComputePostOrderTraversal(bb, &po, &seen);
for (auto current_bb = po.rbegin(); current_bb != po.rend(); ++current_bb) {
if (!IsPseudoExitBlock(*current_bb) && !IsPseudoEntryBlock(*current_bb)) {
- f(*current_bb);
+ if (!f(*current_bb)) {
+ return false;
+ }
}
}
+ return true;
}
void CFG::ComputeStructuredSuccessors(Function* func) {
diff --git a/source/opt/cfg.h b/source/opt/cfg.h
index 5ff3aa0..f280682 100644
--- a/source/opt/cfg.h
+++ b/source/opt/cfg.h
@@ -60,23 +60,27 @@
// Compute structured block order into |order| for |func| starting at |root|.
// This order has the property that dominators come before all blocks they
- // dominate and merge blocks come after all blocks that are in the control
- // constructs of their header.
+ // dominate, merge blocks come after all blocks that are in the control
+ // constructs of their header, and continue blocks come after all of the
+ // blocks in the body of their loop.
void ComputeStructuredOrder(Function* func, BasicBlock* root,
std::list<BasicBlock*>* order);
- // Applies |f| to the basic block in post order starting with |bb|.
- // Note that basic blocks that cannot be reached from |bb| node will not be
- // processed.
+ // Applies |f| to all blocks that can be reach from |bb| in post order.
void ForEachBlockInPostOrder(BasicBlock* bb,
const std::function<void(BasicBlock*)>& f);
- // Applies |f| to the basic block in reverse post order starting with |bb|.
- // Note that basic blocks that cannot be reached from |bb| node will not be
- // processed.
+ // Applies |f| to all blocks that can be reach from |bb| in reverse post
+ // order.
void ForEachBlockInReversePostOrder(
BasicBlock* bb, const std::function<void(BasicBlock*)>& f);
+ // Applies |f| to all blocks that can be reach from |bb| in reverse post
+ // order. Return false if |f| return false on any basic block, and stops
+ // processing.
+ bool WhileEachBlockInReversePostOrder(
+ BasicBlock* bb, const std::function<bool(BasicBlock*)>& f);
+
// Registers |blk| as a basic block in the cfg, this also updates the
// predecessor lists of each successor of |blk|. |blk| must have a terminator
// instruction at the end of the block.
diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp
index 06a1a81..2a2493f 100644
--- a/source/opt/const_folding_rules.cpp
+++ b/source/opt/const_folding_rules.cpp
@@ -296,6 +296,51 @@
};
}
+// Returns the result of folding the constants in |constants| according the
+// |scalar_rule|. If |result_type| is a vector, then |scalar_rule| is applied
+// per component.
+const analysis::Constant* FoldFPBinaryOp(
+ BinaryScalarFoldingRule scalar_rule, uint32_t result_type_id,
+ const std::vector<const analysis::Constant*>& constants,
+ IRContext* context) {
+ analysis::ConstantManager* const_mgr = context->get_constant_mgr();
+ analysis::TypeManager* type_mgr = context->get_type_mgr();
+ const analysis::Type* result_type = type_mgr->GetType(result_type_id);
+ const analysis::Vector* vector_type = result_type->AsVector();
+
+ if (constants[0] == nullptr || constants[1] == nullptr) {
+ return nullptr;
+ }
+
+ if (vector_type != nullptr) {
+ std::vector<const analysis::Constant*> a_components;
+ std::vector<const analysis::Constant*> b_components;
+ std::vector<const analysis::Constant*> results_components;
+
+ a_components = constants[0]->GetVectorComponents(const_mgr);
+ b_components = constants[1]->GetVectorComponents(const_mgr);
+
+ // Fold each component of the vector.
+ for (uint32_t i = 0; i < a_components.size(); ++i) {
+ results_components.push_back(scalar_rule(vector_type->element_type(),
+ a_components[i], b_components[i],
+ const_mgr));
+ if (results_components[i] == nullptr) {
+ return nullptr;
+ }
+ }
+
+ // Build the constant object and return it.
+ std::vector<uint32_t> ids;
+ for (const analysis::Constant* member : results_components) {
+ ids.push_back(const_mgr->GetDefiningInstruction(member)->result_id());
+ }
+ return const_mgr->GetConstant(vector_type, ids);
+ } else {
+ return scalar_rule(result_type, constants[0], constants[1], const_mgr);
+ }
+}
+
// Returns a |ConstantFoldingRule| that folds floating point scalars using
// |scalar_rule| and vectors of floating point by applying |scalar_rule| to the
// elements of the vector. The |ConstantFoldingRule| that is returned assumes
@@ -305,46 +350,14 @@
return [scalar_rule](IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
- analysis::ConstantManager* const_mgr = context->get_constant_mgr();
- analysis::TypeManager* type_mgr = context->get_type_mgr();
- const analysis::Type* result_type = type_mgr->GetType(inst->type_id());
- const analysis::Vector* vector_type = result_type->AsVector();
-
if (!inst->IsFloatingPointFoldingAllowed()) {
return nullptr;
}
-
- if (constants[0] == nullptr || constants[1] == nullptr) {
- return nullptr;
+ if (inst->opcode() == SpvOpExtInst) {
+ return FoldFPBinaryOp(scalar_rule, inst->type_id(),
+ {constants[1], constants[2]}, context);
}
-
- if (vector_type != nullptr) {
- std::vector<const analysis::Constant*> a_components;
- std::vector<const analysis::Constant*> b_components;
- std::vector<const analysis::Constant*> results_components;
-
- a_components = constants[0]->GetVectorComponents(const_mgr);
- b_components = constants[1]->GetVectorComponents(const_mgr);
-
- // Fold each component of the vector.
- for (uint32_t i = 0; i < a_components.size(); ++i) {
- results_components.push_back(scalar_rule(vector_type->element_type(),
- a_components[i],
- b_components[i], const_mgr));
- if (results_components[i] == nullptr) {
- return nullptr;
- }
- }
-
- // Build the constant object and return it.
- std::vector<uint32_t> ids;
- for (const analysis::Constant* member : results_components) {
- ids.push_back(const_mgr->GetDefiningInstruction(member)->result_id());
- }
- return const_mgr->GetConstant(vector_type, ids);
- } else {
- return scalar_rule(result_type, constants[0], constants[1], const_mgr);
- }
+ return FoldFPBinaryOp(scalar_rule, inst->type_id(), constants, context);
};
}
@@ -435,29 +448,33 @@
// This macro defines a |BinaryScalarFoldingRule| that applies |op|. The
// operator |op| must work for both float and double, and use syntax "f1 op f2".
-#define FOLD_FPARITH_OP(op) \
- [](const analysis::Type* result_type, const analysis::Constant* a, \
- const analysis::Constant* b, \
- analysis::ConstantManager* const_mgr_in_macro) \
- -> const analysis::Constant* { \
- assert(result_type != nullptr && a != nullptr && b != nullptr); \
- assert(result_type == a->type() && result_type == b->type()); \
- const analysis::Float* float_type_in_macro = result_type->AsFloat(); \
- assert(float_type_in_macro != nullptr); \
- if (float_type_in_macro->width() == 32) { \
- float fa = a->GetFloat(); \
- float fb = b->GetFloat(); \
- utils::FloatProxy<float> result_in_macro(fa op fb); \
- std::vector<uint32_t> words_in_macro = result_in_macro.GetWords(); \
- return const_mgr_in_macro->GetConstant(result_type, words_in_macro); \
- } else if (float_type_in_macro->width() == 64) { \
- double fa = a->GetDouble(); \
- double fb = b->GetDouble(); \
- utils::FloatProxy<double> result_in_macro(fa op fb); \
- std::vector<uint32_t> words_in_macro = result_in_macro.GetWords(); \
- return const_mgr_in_macro->GetConstant(result_type, words_in_macro); \
- } \
- return nullptr; \
+#define FOLD_FPARITH_OP(op) \
+ [](const analysis::Type* result_type_in_macro, const analysis::Constant* a, \
+ const analysis::Constant* b, \
+ analysis::ConstantManager* const_mgr_in_macro) \
+ -> const analysis::Constant* { \
+ assert(result_type_in_macro != nullptr && a != nullptr && b != nullptr); \
+ assert(result_type_in_macro == a->type() && \
+ result_type_in_macro == b->type()); \
+ const analysis::Float* float_type_in_macro = \
+ result_type_in_macro->AsFloat(); \
+ assert(float_type_in_macro != nullptr); \
+ if (float_type_in_macro->width() == 32) { \
+ float fa = a->GetFloat(); \
+ float fb = b->GetFloat(); \
+ utils::FloatProxy<float> result_in_macro(fa op fb); \
+ std::vector<uint32_t> words_in_macro = result_in_macro.GetWords(); \
+ return const_mgr_in_macro->GetConstant(result_type_in_macro, \
+ words_in_macro); \
+ } else if (float_type_in_macro->width() == 64) { \
+ double fa = a->GetDouble(); \
+ double fb = b->GetDouble(); \
+ utils::FloatProxy<double> result_in_macro(fa op fb); \
+ std::vector<uint32_t> words_in_macro = result_in_macro.GetWords(); \
+ return const_mgr_in_macro->GetConstant(result_type_in_macro, \
+ words_in_macro); \
+ } \
+ return nullptr; \
}
// Define the folding rule for conversion between floating point and integer
@@ -834,34 +851,225 @@
}
const analysis::Constant* one;
- if (constants[1]->type()->AsFloat()->width() == 32) {
- one = const_mgr->GetConstant(constants[1]->type(),
+ bool is_vector = false;
+ const analysis::Type* result_type = constants[1]->type();
+ const analysis::Type* base_type = result_type;
+ if (base_type->AsVector()) {
+ is_vector = true;
+ base_type = base_type->AsVector()->element_type();
+ }
+ assert(base_type->AsFloat() != nullptr &&
+ "FMix is suppose to act on floats or vectors of floats.");
+
+ if (base_type->AsFloat()->width() == 32) {
+ one = const_mgr->GetConstant(base_type,
utils::FloatProxy<float>(1.0f).GetWords());
} else {
- one = const_mgr->GetConstant(constants[1]->type(),
+ one = const_mgr->GetConstant(base_type,
utils::FloatProxy<double>(1.0).GetWords());
}
- const analysis::Constant* temp1 =
- FOLD_FPARITH_OP(-)(constants[1]->type(), one, constants[3], const_mgr);
+ if (is_vector) {
+ uint32_t one_id = const_mgr->GetDefiningInstruction(one)->result_id();
+ one =
+ const_mgr->GetConstant(result_type, std::vector<uint32_t>(4, one_id));
+ }
+
+ const analysis::Constant* temp1 = FoldFPBinaryOp(
+ FOLD_FPARITH_OP(-), inst->type_id(), {one, constants[3]}, context);
if (temp1 == nullptr) {
return nullptr;
}
- const analysis::Constant* temp2 = FOLD_FPARITH_OP(*)(
- constants[1]->type(), constants[1], temp1, const_mgr);
+ const analysis::Constant* temp2 = FoldFPBinaryOp(
+ FOLD_FPARITH_OP(*), inst->type_id(), {constants[1], temp1}, context);
if (temp2 == nullptr) {
return nullptr;
}
- const analysis::Constant* temp3 = FOLD_FPARITH_OP(*)(
- constants[2]->type(), constants[2], constants[3], const_mgr);
+ const analysis::Constant* temp3 =
+ FoldFPBinaryOp(FOLD_FPARITH_OP(*), inst->type_id(),
+ {constants[2], constants[3]}, context);
if (temp3 == nullptr) {
return nullptr;
}
- return FOLD_FPARITH_OP(+)(temp2->type(), temp2, temp3, const_mgr);
+ return FoldFPBinaryOp(FOLD_FPARITH_OP(+), inst->type_id(), {temp2, temp3},
+ context);
};
}
+template <class IntType>
+IntType FoldIClamp(IntType x, IntType min_val, IntType max_val) {
+ if (x < min_val) {
+ x = min_val;
+ }
+ if (x > max_val) {
+ x = max_val;
+ }
+ return x;
+}
+
+const analysis::Constant* FoldMin(const analysis::Type* result_type,
+ const analysis::Constant* a,
+ const analysis::Constant* b,
+ analysis::ConstantManager*) {
+ if (const analysis::Integer* int_type = result_type->AsInteger()) {
+ if (int_type->width() == 32) {
+ if (int_type->IsSigned()) {
+ int32_t va = a->GetS32();
+ int32_t vb = b->GetS32();
+ return (va < vb ? a : b);
+ } else {
+ uint32_t va = a->GetU32();
+ uint32_t vb = b->GetU32();
+ return (va < vb ? a : b);
+ }
+ } else if (int_type->width() == 64) {
+ if (int_type->IsSigned()) {
+ int64_t va = a->GetS64();
+ int64_t vb = b->GetS64();
+ return (va < vb ? a : b);
+ } else {
+ uint64_t va = a->GetU64();
+ uint64_t vb = b->GetU64();
+ return (va < vb ? a : b);
+ }
+ }
+ } else if (const analysis::Float* float_type = result_type->AsFloat()) {
+ if (float_type->width() == 32) {
+ float va = a->GetFloat();
+ float vb = b->GetFloat();
+ return (va < vb ? a : b);
+ } else if (float_type->width() == 64) {
+ double va = a->GetDouble();
+ double vb = b->GetDouble();
+ return (va < vb ? a : b);
+ }
+ }
+ return nullptr;
+}
+
+const analysis::Constant* FoldMax(const analysis::Type* result_type,
+ const analysis::Constant* a,
+ const analysis::Constant* b,
+ analysis::ConstantManager*) {
+ if (const analysis::Integer* int_type = result_type->AsInteger()) {
+ if (int_type->width() == 32) {
+ if (int_type->IsSigned()) {
+ int32_t va = a->GetS32();
+ int32_t vb = b->GetS32();
+ return (va > vb ? a : b);
+ } else {
+ uint32_t va = a->GetU32();
+ uint32_t vb = b->GetU32();
+ return (va > vb ? a : b);
+ }
+ } else if (int_type->width() == 64) {
+ if (int_type->IsSigned()) {
+ int64_t va = a->GetS64();
+ int64_t vb = b->GetS64();
+ return (va > vb ? a : b);
+ } else {
+ uint64_t va = a->GetU64();
+ uint64_t vb = b->GetU64();
+ return (va > vb ? a : b);
+ }
+ }
+ } else if (const analysis::Float* float_type = result_type->AsFloat()) {
+ if (float_type->width() == 32) {
+ float va = a->GetFloat();
+ float vb = b->GetFloat();
+ return (va > vb ? a : b);
+ } else if (float_type->width() == 64) {
+ double va = a->GetDouble();
+ double vb = b->GetDouble();
+ return (va > vb ? a : b);
+ }
+ }
+ return nullptr;
+}
+
+// Fold an clamp instruction when all three operands are constant.
+const analysis::Constant* FoldClamp1(
+ IRContext* context, Instruction* inst,
+ const std::vector<const analysis::Constant*>& constants) {
+ assert(inst->opcode() == SpvOpExtInst &&
+ "Expecting an extended instruction.");
+ assert(inst->GetSingleWordInOperand(0) ==
+ context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
+ "Expecting a GLSLstd450 extended instruction.");
+
+ // Make sure all Clamp operands are constants.
+ for (uint32_t i = 1; i < 3; i++) {
+ if (constants[i] == nullptr) {
+ return nullptr;
+ }
+ }
+
+ const analysis::Constant* temp = FoldFPBinaryOp(
+ FoldMax, inst->type_id(), {constants[1], constants[2]}, context);
+ if (temp == nullptr) {
+ return nullptr;
+ }
+ return FoldFPBinaryOp(FoldMin, inst->type_id(), {temp, constants[3]},
+ context);
+}
+
+// Fold a clamp instruction when |x >= min_val|.
+const analysis::Constant* FoldClamp2(
+ IRContext* context, Instruction* inst,
+ const std::vector<const analysis::Constant*>& constants) {
+ assert(inst->opcode() == SpvOpExtInst &&
+ "Expecting an extended instruction.");
+ assert(inst->GetSingleWordInOperand(0) ==
+ context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
+ "Expecting a GLSLstd450 extended instruction.");
+
+ const analysis::Constant* x = constants[1];
+ const analysis::Constant* min_val = constants[2];
+
+ if (x == nullptr || min_val == nullptr) {
+ return nullptr;
+ }
+
+ const analysis::Constant* temp =
+ FoldFPBinaryOp(FoldMax, inst->type_id(), {x, min_val}, context);
+ if (temp == min_val) {
+ // We can assume that |min_val| is less than |max_val|. Therefore, if the
+ // result of the max operation is |min_val|, we know the result of the min
+ // operation, even if |max_val| is not a constant.
+ return min_val;
+ }
+ return nullptr;
+}
+
+// Fold a clamp instruction when |x >= max_val|.
+const analysis::Constant* FoldClamp3(
+ IRContext* context, Instruction* inst,
+ const std::vector<const analysis::Constant*>& constants) {
+ assert(inst->opcode() == SpvOpExtInst &&
+ "Expecting an extended instruction.");
+ assert(inst->GetSingleWordInOperand(0) ==
+ context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
+ "Expecting a GLSLstd450 extended instruction.");
+
+ const analysis::Constant* x = constants[1];
+ const analysis::Constant* max_val = constants[3];
+
+ if (x == nullptr || max_val == nullptr) {
+ return nullptr;
+ }
+
+ const analysis::Constant* temp =
+ FoldFPBinaryOp(FoldMin, inst->type_id(), {x, max_val}, context);
+ if (temp == max_val) {
+ // We can assume that |min_val| is less than |max_val|. Therefore, if the
+ // result of the max operation is |min_val|, we know the result of the min
+ // operation, even if |max_val| is not a constant.
+ return max_val;
+ }
+ return nullptr;
+}
+
} // namespace
void ConstantFoldingRules::AddFoldingRules() {
@@ -937,6 +1145,36 @@
feature_manager->GetExtInstImportId_GLSLstd450();
if (ext_inst_glslstd450_id != 0) {
ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FMix}].push_back(FoldFMix());
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SMin}].push_back(
+ FoldFPBinaryOp(FoldMin));
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UMin}].push_back(
+ FoldFPBinaryOp(FoldMin));
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FMin}].push_back(
+ FoldFPBinaryOp(FoldMin));
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SMax}].push_back(
+ FoldFPBinaryOp(FoldMax));
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UMax}].push_back(
+ FoldFPBinaryOp(FoldMax));
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FMax}].push_back(
+ FoldFPBinaryOp(FoldMax));
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UClamp}].push_back(
+ FoldClamp1);
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UClamp}].push_back(
+ FoldClamp2);
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UClamp}].push_back(
+ FoldClamp3);
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SClamp}].push_back(
+ FoldClamp1);
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SClamp}].push_back(
+ FoldClamp2);
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SClamp}].push_back(
+ FoldClamp3);
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FClamp}].push_back(
+ FoldClamp1);
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FClamp}].push_back(
+ FoldClamp2);
+ ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FClamp}].push_back(
+ FoldClamp3);
}
}
} // namespace opt
diff --git a/source/opt/constants.cpp b/source/opt/constants.cpp
index 5c1468b..0887ec2 100644
--- a/source/opt/constants.cpp
+++ b/source/opt/constants.cpp
@@ -389,6 +389,13 @@
return cst ? RegisterConstant(std::move(cst)) : nullptr;
}
+uint32_t ConstantManager::GetFloatConst(float val) {
+ Type* float_type = context()->get_type_mgr()->GetFloatType();
+ utils::FloatProxy<float> v(val);
+ const Constant* c = GetConstant(float_type, v.GetWords());
+ return GetDefiningInstruction(c)->result_id();
+}
+
std::vector<const analysis::Constant*> Constant::GetVectorComponents(
analysis::ConstantManager* const_mgr) const {
std::vector<const analysis::Constant*> components;
diff --git a/source/opt/constants.h b/source/opt/constants.h
index 93d0847..5f2fdc7 100644
--- a/source/opt/constants.h
+++ b/source/opt/constants.h
@@ -626,6 +626,9 @@
}
}
+ // Returns the id of a 32-bit floating point constant with value |val|.
+ uint32_t GetFloatConst(float val);
+
private:
// Creates a Constant instance with the given type and a vector of constant
// defining words. Returns a unique pointer to the created Constant instance
diff --git a/source/opt/convert_to_half_pass.cpp b/source/opt/convert_to_half_pass.cpp
new file mode 100644
index 0000000..4c02c73
--- /dev/null
+++ b/source/opt/convert_to_half_pass.cpp
@@ -0,0 +1,460 @@
+// Copyright (c) 2019 The Khronos Group Inc.
+// Copyright (c) 2019 Valve Corporation
+// Copyright (c) 2019 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "convert_to_half_pass.h"
+
+#include "source/opt/ir_builder.h"
+
+namespace {
+
+// Indices of operands in SPIR-V instructions
+static const int kImageSampleDrefIdInIdx = 2;
+
+} // anonymous namespace
+
+namespace spvtools {
+namespace opt {
+
+bool ConvertToHalfPass::IsArithmetic(Instruction* inst) {
+ return target_ops_core_.count(inst->opcode()) != 0 ||
+ (inst->opcode() == SpvOpExtInst &&
+ inst->GetSingleWordInOperand(0) ==
+ context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
+ target_ops_450_.count(inst->GetSingleWordInOperand(1)) != 0);
+}
+
+bool ConvertToHalfPass::IsFloat(Instruction* inst, uint32_t width) {
+ uint32_t ty_id = inst->type_id();
+ if (ty_id == 0) return false;
+ return Pass::IsFloat(ty_id, width);
+}
+
+bool ConvertToHalfPass::IsRelaxed(Instruction* inst) {
+ uint32_t r_id = inst->result_id();
+ for (auto r_inst : get_decoration_mgr()->GetDecorationsFor(r_id, false))
+ if (r_inst->opcode() == SpvOpDecorate &&
+ r_inst->GetSingleWordInOperand(1) == SpvDecorationRelaxedPrecision)
+ return true;
+ return false;
+}
+
+analysis::Type* ConvertToHalfPass::FloatScalarType(uint32_t width) {
+ analysis::Float float_ty(width);
+ return context()->get_type_mgr()->GetRegisteredType(&float_ty);
+}
+
+analysis::Type* ConvertToHalfPass::FloatVectorType(uint32_t v_len,
+ uint32_t width) {
+ analysis::Type* reg_float_ty = FloatScalarType(width);
+ analysis::Vector vec_ty(reg_float_ty, v_len);
+ return context()->get_type_mgr()->GetRegisteredType(&vec_ty);
+}
+
+analysis::Type* ConvertToHalfPass::FloatMatrixType(uint32_t v_cnt,
+ uint32_t vty_id,
+ uint32_t width) {
+ Instruction* vty_inst = get_def_use_mgr()->GetDef(vty_id);
+ uint32_t v_len = vty_inst->GetSingleWordInOperand(1);
+ analysis::Type* reg_vec_ty = FloatVectorType(v_len, width);
+ analysis::Matrix mat_ty(reg_vec_ty, v_cnt);
+ return context()->get_type_mgr()->GetRegisteredType(&mat_ty);
+}
+
+uint32_t ConvertToHalfPass::EquivFloatTypeId(uint32_t ty_id, uint32_t width) {
+ analysis::Type* reg_equiv_ty;
+ Instruction* ty_inst = get_def_use_mgr()->GetDef(ty_id);
+ if (ty_inst->opcode() == SpvOpTypeMatrix)
+ reg_equiv_ty = FloatMatrixType(ty_inst->GetSingleWordInOperand(1),
+ ty_inst->GetSingleWordInOperand(0), width);
+ else if (ty_inst->opcode() == SpvOpTypeVector)
+ reg_equiv_ty = FloatVectorType(ty_inst->GetSingleWordInOperand(1), width);
+ else // SpvOpTypeFloat
+ reg_equiv_ty = FloatScalarType(width);
+ return context()->get_type_mgr()->GetTypeInstruction(reg_equiv_ty);
+}
+
+void ConvertToHalfPass::GenConvert(uint32_t* val_idp, uint32_t width,
+ InstructionBuilder* builder) {
+ Instruction* val_inst = get_def_use_mgr()->GetDef(*val_idp);
+ uint32_t ty_id = val_inst->type_id();
+ uint32_t nty_id = EquivFloatTypeId(ty_id, width);
+ if (nty_id == ty_id) return;
+ Instruction* cvt_inst;
+ if (val_inst->opcode() == SpvOpUndef)
+ cvt_inst = builder->AddNullaryOp(nty_id, SpvOpUndef);
+ else
+ cvt_inst = builder->AddUnaryOp(nty_id, SpvOpFConvert, *val_idp);
+ *val_idp = cvt_inst->result_id();
+}
+
+bool ConvertToHalfPass::MatConvertCleanup(Instruction* inst) {
+ if (inst->opcode() != SpvOpFConvert) return false;
+ uint32_t mty_id = inst->type_id();
+ Instruction* mty_inst = get_def_use_mgr()->GetDef(mty_id);
+ if (mty_inst->opcode() != SpvOpTypeMatrix) return false;
+ uint32_t vty_id = mty_inst->GetSingleWordInOperand(0);
+ uint32_t v_cnt = mty_inst->GetSingleWordInOperand(1);
+ Instruction* vty_inst = get_def_use_mgr()->GetDef(vty_id);
+ uint32_t cty_id = vty_inst->GetSingleWordInOperand(0);
+ Instruction* cty_inst = get_def_use_mgr()->GetDef(cty_id);
+ InstructionBuilder builder(
+ context(), inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ // Convert each component vector, combine them with OpCompositeConstruct
+ // and replace original instruction.
+ uint32_t orig_width = (cty_inst->GetSingleWordInOperand(0) == 16) ? 32 : 16;
+ uint32_t orig_mat_id = inst->GetSingleWordInOperand(0);
+ uint32_t orig_vty_id = EquivFloatTypeId(vty_id, orig_width);
+ std::vector<Operand> opnds = {};
+ for (uint32_t vidx = 0; vidx < v_cnt; ++vidx) {
+ Instruction* ext_inst = builder.AddIdLiteralOp(
+ orig_vty_id, SpvOpCompositeExtract, orig_mat_id, vidx);
+ Instruction* cvt_inst =
+ builder.AddUnaryOp(vty_id, SpvOpFConvert, ext_inst->result_id());
+ opnds.push_back({SPV_OPERAND_TYPE_ID, {cvt_inst->result_id()}});
+ }
+ uint32_t mat_id = TakeNextId();
+ std::unique_ptr<Instruction> mat_inst(new Instruction(
+ context(), SpvOpCompositeConstruct, mty_id, mat_id, opnds));
+ (void)builder.AddInstruction(std::move(mat_inst));
+ context()->ReplaceAllUsesWith(inst->result_id(), mat_id);
+ // Turn original instruction into copy so it is valid.
+ inst->SetOpcode(SpvOpCopyObject);
+ inst->SetResultType(EquivFloatTypeId(mty_id, orig_width));
+ get_def_use_mgr()->AnalyzeInstUse(inst);
+ return true;
+}
+
+void ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) {
+ context()->get_decoration_mgr()->RemoveDecorationsFrom(
+ id, [](const Instruction& dec) {
+ if (dec.opcode() == SpvOpDecorate &&
+ dec.GetSingleWordInOperand(1u) == SpvDecorationRelaxedPrecision)
+ return true;
+ else
+ return false;
+ });
+}
+
+bool ConvertToHalfPass::GenHalfArith(Instruction* inst) {
+ bool modified = false;
+ // Convert all float32 based operands to float16 equivalent and change
+ // instruction type to float16 equivalent.
+ InstructionBuilder builder(
+ context(), inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ inst->ForEachInId([&builder, &modified, this](uint32_t* idp) {
+ Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
+ if (!IsFloat(op_inst, 32)) return;
+ GenConvert(idp, 16, &builder);
+ modified = true;
+ });
+ if (IsFloat(inst, 32)) {
+ inst->SetResultType(EquivFloatTypeId(inst->type_id(), 16));
+ modified = true;
+ }
+ if (modified) get_def_use_mgr()->AnalyzeInstUse(inst);
+ return modified;
+}
+
+bool ConvertToHalfPass::ProcessPhi(Instruction* inst) {
+ // Skip if not float32
+ if (!IsFloat(inst, 32)) return false;
+ // Skip if no relaxed operands.
+ bool relaxed_found = false;
+ uint32_t ocnt = 0;
+ inst->ForEachInId([&ocnt, &relaxed_found, this](uint32_t* idp) {
+ if (ocnt % 2 == 0) {
+ Instruction* val_inst = get_def_use_mgr()->GetDef(*idp);
+ if (IsRelaxed(val_inst)) relaxed_found = true;
+ }
+ ++ocnt;
+ });
+ if (!relaxed_found) return false;
+ // Add float16 converts of any float32 operands and change type
+ // of phi to float16 equivalent. Operand converts need to be added to
+ // preceeding blocks.
+ ocnt = 0;
+ uint32_t* prev_idp;
+ inst->ForEachInId([&ocnt, &prev_idp, this](uint32_t* idp) {
+ if (ocnt % 2 == 0) {
+ prev_idp = idp;
+ } else {
+ Instruction* val_inst = get_def_use_mgr()->GetDef(*prev_idp);
+ if (IsFloat(val_inst, 32)) {
+ BasicBlock* bp = context()->get_instr_block(*idp);
+ auto insert_before = bp->tail();
+ if (insert_before != bp->begin()) {
+ --insert_before;
+ if (insert_before->opcode() != SpvOpSelectionMerge &&
+ insert_before->opcode() != SpvOpLoopMerge)
+ ++insert_before;
+ }
+ InstructionBuilder builder(context(), &*insert_before,
+ IRContext::kAnalysisDefUse |
+ IRContext::kAnalysisInstrToBlockMapping);
+ GenConvert(prev_idp, 16, &builder);
+ }
+ }
+ ++ocnt;
+ });
+ inst->SetResultType(EquivFloatTypeId(inst->type_id(), 16));
+ get_def_use_mgr()->AnalyzeInstUse(inst);
+ return true;
+}
+
+bool ConvertToHalfPass::ProcessExtract(Instruction* inst) {
+ bool modified = false;
+ uint32_t comp_id = inst->GetSingleWordInOperand(0);
+ Instruction* comp_inst = get_def_use_mgr()->GetDef(comp_id);
+ // If extract is relaxed float32 based type and the composite is a relaxed
+ // float32 based type, convert it to float16 equivalent. This is slightly
+ // aggressive and pushes any likely conversion to apply to the whole
+ // composite rather than apply to each extracted component later. This
+ // can be a win if the platform can convert the entire composite in the same
+ // time as one component. It risks converting components that may not be
+ // used, although empirical data on a large set of real-world shaders seems
+ // to suggest this is not common and the composite convert is the best choice.
+ if (IsFloat(inst, 32) && IsRelaxed(inst) && IsFloat(comp_inst, 32) &&
+ IsRelaxed(comp_inst)) {
+ InstructionBuilder builder(
+ context(), inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ GenConvert(&comp_id, 16, &builder);
+ inst->SetInOperand(0, {comp_id});
+ comp_inst = get_def_use_mgr()->GetDef(comp_id);
+ modified = true;
+ }
+ // If the composite is a float16 based type, make sure the type of the
+ // extract agrees.
+ if (IsFloat(comp_inst, 16) && !IsFloat(inst, 16)) {
+ inst->SetResultType(EquivFloatTypeId(inst->type_id(), 16));
+ modified = true;
+ }
+ if (modified) get_def_use_mgr()->AnalyzeInstUse(inst);
+ return modified;
+}
+
+bool ConvertToHalfPass::ProcessConvert(Instruction* inst) {
+ // If float32 and relaxed, change to float16 convert
+ if (IsFloat(inst, 32) && IsRelaxed(inst)) {
+ inst->SetResultType(EquivFloatTypeId(inst->type_id(), 16));
+ get_def_use_mgr()->AnalyzeInstUse(inst);
+ }
+ // If operand and result types are the same, replace result with operand
+ // and change convert to copy to keep validator happy; DCE will clean it up
+ uint32_t val_id = inst->GetSingleWordInOperand(0);
+ Instruction* val_inst = get_def_use_mgr()->GetDef(val_id);
+ if (inst->type_id() == val_inst->type_id()) {
+ context()->ReplaceAllUsesWith(inst->result_id(), val_id);
+ inst->SetOpcode(SpvOpCopyObject);
+ }
+ return true; // modified
+}
+
+bool ConvertToHalfPass::ProcessImageRef(Instruction* inst) {
+ bool modified = false;
+ // If image reference, only need to convert dref args back to float32
+ if (dref_image_ops_.count(inst->opcode()) != 0) {
+ uint32_t dref_id = inst->GetSingleWordInOperand(kImageSampleDrefIdInIdx);
+ Instruction* dref_inst = get_def_use_mgr()->GetDef(dref_id);
+ if (IsFloat(dref_inst, 16) && IsRelaxed(dref_inst)) {
+ InstructionBuilder builder(
+ context(), inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ GenConvert(&dref_id, 32, &builder);
+ inst->SetInOperand(kImageSampleDrefIdInIdx, {dref_id});
+ get_def_use_mgr()->AnalyzeInstUse(inst);
+ modified = true;
+ }
+ }
+ return modified;
+}
+
+bool ConvertToHalfPass::ProcessDefault(Instruction* inst) {
+ bool modified = false;
+ // If non-relaxed instruction has changed operands, need to convert
+ // them back to float32
+ InstructionBuilder builder(
+ context(), inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ inst->ForEachInId([&builder, &modified, this](uint32_t* idp) {
+ Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
+ if (!IsFloat(op_inst, 16)) return;
+ if (!IsRelaxed(op_inst)) return;
+ uint32_t old_id = *idp;
+ GenConvert(idp, 32, &builder);
+ if (*idp != old_id) modified = true;
+ });
+ if (modified) get_def_use_mgr()->AnalyzeInstUse(inst);
+ return modified;
+}
+
+bool ConvertToHalfPass::GenHalfCode(Instruction* inst) {
+ bool modified = false;
+ // Remember id for later deletion of RelaxedPrecision decoration
+ bool inst_relaxed = IsRelaxed(inst);
+ if (inst_relaxed) relaxed_ids_.push_back(inst->result_id());
+ if (IsArithmetic(inst) && inst_relaxed)
+ modified = GenHalfArith(inst);
+ else if (inst->opcode() == SpvOpPhi)
+ modified = ProcessPhi(inst);
+ else if (inst->opcode() == SpvOpCompositeExtract)
+ modified = ProcessExtract(inst);
+ else if (inst->opcode() == SpvOpFConvert)
+ modified = ProcessConvert(inst);
+ else if (image_ops_.count(inst->opcode()) != 0)
+ modified = ProcessImageRef(inst);
+ else
+ modified = ProcessDefault(inst);
+ return modified;
+}
+
+bool ConvertToHalfPass::ProcessFunction(Function* func) {
+ bool modified = false;
+ cfg()->ForEachBlockInReversePostOrder(
+ func->entry().get(), [&modified, this](BasicBlock* bb) {
+ for (auto ii = bb->begin(); ii != bb->end(); ++ii)
+ modified |= GenHalfCode(&*ii);
+ });
+ cfg()->ForEachBlockInReversePostOrder(
+ func->entry().get(), [&modified, this](BasicBlock* bb) {
+ for (auto ii = bb->begin(); ii != bb->end(); ++ii)
+ modified |= MatConvertCleanup(&*ii);
+ });
+ return modified;
+}
+
+Pass::Status ConvertToHalfPass::ProcessImpl() {
+ Pass::ProcessFunction pfn = [this](Function* fp) {
+ return ProcessFunction(fp);
+ };
+ bool modified = context()->ProcessEntryPointCallTree(pfn);
+ // 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_) RemoveRelaxedDecoration(c_id);
+ for (auto& val : get_module()->types_values()) {
+ uint32_t v_id = val.result_id();
+ if (v_id != 0) RemoveRelaxedDecoration(v_id);
+ }
+ return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+}
+
+Pass::Status ConvertToHalfPass::Process() {
+ Initialize();
+ return ProcessImpl();
+}
+
+void ConvertToHalfPass::Initialize() {
+ target_ops_core_ = {
+ SpvOpVectorExtractDynamic,
+ SpvOpVectorInsertDynamic,
+ SpvOpVectorShuffle,
+ SpvOpCompositeConstruct,
+ SpvOpCompositeInsert,
+ SpvOpCopyObject,
+ SpvOpTranspose,
+ SpvOpConvertSToF,
+ SpvOpConvertUToF,
+ // SpvOpFConvert,
+ // SpvOpQuantizeToF16,
+ SpvOpFNegate,
+ SpvOpFAdd,
+ SpvOpFSub,
+ SpvOpFMul,
+ SpvOpFDiv,
+ SpvOpFMod,
+ SpvOpVectorTimesScalar,
+ SpvOpMatrixTimesScalar,
+ SpvOpVectorTimesMatrix,
+ SpvOpMatrixTimesVector,
+ SpvOpMatrixTimesMatrix,
+ SpvOpOuterProduct,
+ SpvOpDot,
+ SpvOpSelect,
+ SpvOpFOrdEqual,
+ SpvOpFUnordEqual,
+ SpvOpFOrdNotEqual,
+ SpvOpFUnordNotEqual,
+ SpvOpFOrdLessThan,
+ SpvOpFUnordLessThan,
+ SpvOpFOrdGreaterThan,
+ SpvOpFUnordGreaterThan,
+ SpvOpFOrdLessThanEqual,
+ SpvOpFUnordLessThanEqual,
+ SpvOpFOrdGreaterThanEqual,
+ SpvOpFUnordGreaterThanEqual,
+ };
+ target_ops_450_ = {
+ GLSLstd450Round, GLSLstd450RoundEven, GLSLstd450Trunc, GLSLstd450FAbs,
+ GLSLstd450FSign, GLSLstd450Floor, GLSLstd450Ceil, GLSLstd450Fract,
+ GLSLstd450Radians, GLSLstd450Degrees, GLSLstd450Sin, GLSLstd450Cos,
+ GLSLstd450Tan, GLSLstd450Asin, GLSLstd450Acos, GLSLstd450Atan,
+ GLSLstd450Sinh, GLSLstd450Cosh, GLSLstd450Tanh, GLSLstd450Asinh,
+ GLSLstd450Acosh, GLSLstd450Atanh, GLSLstd450Atan2, GLSLstd450Pow,
+ GLSLstd450Exp, GLSLstd450Log, GLSLstd450Exp2, GLSLstd450Log2,
+ GLSLstd450Sqrt, GLSLstd450InverseSqrt, GLSLstd450Determinant,
+ GLSLstd450MatrixInverse,
+ // TODO(greg-lunarg): GLSLstd450ModfStruct,
+ GLSLstd450FMin, GLSLstd450FMax, GLSLstd450FClamp, GLSLstd450FMix,
+ GLSLstd450Step, GLSLstd450SmoothStep, GLSLstd450Fma,
+ // TODO(greg-lunarg): GLSLstd450FrexpStruct,
+ GLSLstd450Ldexp, GLSLstd450Length, GLSLstd450Distance, GLSLstd450Cross,
+ GLSLstd450Normalize, GLSLstd450FaceForward, GLSLstd450Reflect,
+ GLSLstd450Refract, GLSLstd450NMin, GLSLstd450NMax, GLSLstd450NClamp};
+ image_ops_ = {SpvOpImageSampleImplicitLod,
+ SpvOpImageSampleExplicitLod,
+ SpvOpImageSampleDrefImplicitLod,
+ SpvOpImageSampleDrefExplicitLod,
+ SpvOpImageSampleProjImplicitLod,
+ SpvOpImageSampleProjExplicitLod,
+ SpvOpImageSampleProjDrefImplicitLod,
+ SpvOpImageSampleProjDrefExplicitLod,
+ SpvOpImageFetch,
+ SpvOpImageGather,
+ SpvOpImageDrefGather,
+ SpvOpImageRead,
+ SpvOpImageSparseSampleImplicitLod,
+ SpvOpImageSparseSampleExplicitLod,
+ SpvOpImageSparseSampleDrefImplicitLod,
+ SpvOpImageSparseSampleDrefExplicitLod,
+ SpvOpImageSparseSampleProjImplicitLod,
+ SpvOpImageSparseSampleProjExplicitLod,
+ SpvOpImageSparseSampleProjDrefImplicitLod,
+ SpvOpImageSparseSampleProjDrefExplicitLod,
+ SpvOpImageSparseFetch,
+ SpvOpImageSparseGather,
+ SpvOpImageSparseDrefGather,
+ SpvOpImageSparseTexelsResident,
+ SpvOpImageSparseRead};
+ dref_image_ops_ = {
+ SpvOpImageSampleDrefImplicitLod,
+ SpvOpImageSampleDrefExplicitLod,
+ SpvOpImageSampleProjDrefImplicitLod,
+ SpvOpImageSampleProjDrefExplicitLod,
+ SpvOpImageDrefGather,
+ SpvOpImageSparseSampleDrefImplicitLod,
+ SpvOpImageSparseSampleDrefExplicitLod,
+ SpvOpImageSparseSampleProjDrefImplicitLod,
+ SpvOpImageSparseSampleProjDrefExplicitLod,
+ SpvOpImageSparseDrefGather,
+ };
+ relaxed_ids_.clear();
+}
+
+} // namespace opt
+} // namespace spvtools
diff --git a/source/opt/convert_to_half_pass.h b/source/opt/convert_to_half_pass.h
new file mode 100644
index 0000000..5225848
--- /dev/null
+++ b/source/opt/convert_to_half_pass.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2019 Valve Corporation
+// Copyright (c) 2019 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_
+#define LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_
+
+#include "source/opt/ir_builder.h"
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+class ConvertToHalfPass : public Pass {
+ public:
+ ConvertToHalfPass() : Pass() {}
+
+ ~ConvertToHalfPass() override = default;
+
+ IRContext::Analysis GetPreservedAnalyses() override {
+ return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping;
+ }
+
+ // See optimizer.hpp for pass user documentation.
+ Status Process() override;
+
+ const char* name() const override { return "convert-to-half-pass"; }
+
+ private:
+ // Return true if |inst| is an arithmetic op that can be of type float16
+ bool IsArithmetic(Instruction* inst);
+
+ // Return true if |inst| returns scalar, vector or matrix type with base
+ // float and |width|
+ bool IsFloat(Instruction* inst, uint32_t width);
+
+ // Return true if |inst| is decorated with RelaxedPrecision
+ bool IsRelaxed(Instruction* inst);
+
+ // Return type id for float with |width|
+ analysis::Type* FloatScalarType(uint32_t width);
+
+ // Return type id for vector of length |vlen| of float of |width|
+ analysis::Type* FloatVectorType(uint32_t v_len, uint32_t width);
+
+ // Return type id for matrix of |v_cnt| vectors of length identical to
+ // |vty_id| of float of |width|
+ analysis::Type* FloatMatrixType(uint32_t v_cnt, uint32_t vty_id,
+ uint32_t width);
+
+ // Return equivalent to float type |ty_id| with |width|
+ uint32_t EquivFloatTypeId(uint32_t ty_id, uint32_t width);
+
+ // Append instructions to builder to convert value |*val_idp| to type
+ // |ty_id| but with |width|. Set |*val_idp| to the new id.
+ void GenConvert(uint32_t* val_idp, uint32_t width,
+ InstructionBuilder* builder);
+
+ // Remove RelaxedPrecision decoration of |id|.
+ void RemoveRelaxedDecoration(uint32_t id);
+
+ // If |inst| is an arithmetic, phi, extract or convert instruction of float32
+ // base type and decorated with RelaxedPrecision, change it to the equivalent
+ // float16 based type instruction. Specifically, insert instructions to
+ // convert all operands to float16 (if needed) and change its type to the
+ // equivalent float16 type. Otherwise, insert instructions to convert its
+ // operands back to their original types, if needed.
+ bool GenHalfCode(Instruction* inst);
+
+ // Gen code for relaxed arithmetic |inst|
+ bool GenHalfArith(Instruction* inst);
+
+ // Gen code for relaxed phi |inst|
+ bool ProcessPhi(Instruction* inst);
+
+ // Gen code for relaxed extract |inst|
+ bool ProcessExtract(Instruction* inst);
+
+ // Gen code for relaxed convert |inst|
+ bool ProcessConvert(Instruction* inst);
+
+ // Gen code for image reference |inst|
+ bool ProcessImageRef(Instruction* inst);
+
+ // Process default non-relaxed |inst|
+ bool ProcessDefault(Instruction* inst);
+
+ // If |inst| is an FConvert of a matrix type, decompose it to a series
+ // of vector extracts, converts and inserts into an Undef. These are
+ // generated by GenHalfCode because they are easier to manipulate, but are
+ // invalid so we need to clean them up.
+ bool MatConvertCleanup(Instruction* inst);
+
+ // Call GenHalfCode on every instruction in |func|.
+ // If code is generated for an instruction, replace the instruction
+ // with the new instructions that are generated.
+ bool ProcessFunction(Function* func);
+
+ Pass::Status ProcessImpl();
+
+ // Initialize state for converting to half
+ void Initialize();
+
+ // Set of core operations to be processed
+ std::unordered_set<uint32_t> target_ops_core_;
+
+ // Set of 450 extension operations to be processed
+ std::unordered_set<uint32_t> target_ops_450_;
+
+ // Set of sample operations
+ std::unordered_set<uint32_t> image_ops_;
+
+ // Set of dref sample operations
+ std::unordered_set<uint32_t> dref_image_ops_;
+
+ // Ids of all converted instructions
+ std::vector<uint32_t> relaxed_ids_;
+};
+
+} // namespace opt
+} // namespace spvtools
+
+#endif // LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_
diff --git a/source/opt/copy_prop_arrays.cpp b/source/opt/copy_prop_arrays.cpp
index 00757e3..b3b90da 100644
--- a/source/opt/copy_prop_arrays.cpp
+++ b/source/opt/copy_prop_arrays.cpp
@@ -306,8 +306,7 @@
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
const analysis::Constant* last_access =
const_mgr->FindDeclaredConstant(memory_object->AccessChain().back());
- if (!last_access ||
- (!last_access->AsIntConstant() && !last_access->AsNullConstant())) {
+ if (!last_access || !last_access->type()->AsInteger()) {
return nullptr;
}
@@ -340,7 +339,7 @@
last_access =
const_mgr->FindDeclaredConstant(member_object->AccessChain().back());
- if (!last_access || !last_access->AsIntConstant()) {
+ if (!last_access || !last_access->type()->AsInteger()) {
return nullptr;
}
@@ -368,8 +367,7 @@
} else if (const analysis::Array* array_type = result_type->AsArray()) {
const analysis::Constant* length_const =
const_mgr->FindDeclaredConstant(array_type->LengthId());
- assert(length_const->AsIntConstant());
- number_of_elements = length_const->AsIntConstant()->GetU32();
+ number_of_elements = length_const->GetU32();
} else if (const analysis::Vector* vector_type = result_type->AsVector()) {
number_of_elements = vector_type->element_count();
} else if (const analysis::Matrix* matrix_type = result_type->AsMatrix()) {
@@ -401,7 +399,7 @@
const analysis::Constant* last_access =
const_mgr->FindDeclaredConstant(memory_object->AccessChain().back());
- if (!last_access || !last_access->AsIntConstant()) {
+ if (!last_access || !last_access->type()->AsInteger()) {
return nullptr;
}
@@ -449,7 +447,7 @@
const analysis::Constant* current_last_access =
const_mgr->FindDeclaredConstant(
current_memory_object->AccessChain().back());
- if (!current_last_access || !current_last_access->AsIntConstant()) {
+ if (!current_last_access || !current_last_access->type()->AsInteger()) {
return nullptr;
}
@@ -513,7 +511,7 @@
const analysis::Constant* index_const =
const_mgr->FindDeclaredConstant(use->GetSingleWordInOperand(i));
if (index_const) {
- access_chain.push_back(index_const->AsIntConstant()->GetU32());
+ access_chain.push_back(index_const->GetU32());
} else {
// Variable index means the type is a type where every element
// is the same type. Use element 0 to get the type.
@@ -613,7 +611,7 @@
const analysis::Constant* index_const =
const_mgr->FindDeclaredConstant(use->GetSingleWordInOperand(i));
if (index_const) {
- access_chain.push_back(index_const->AsIntConstant()->GetU32());
+ access_chain.push_back(index_const->GetU32());
} else {
// Variable index means the type is an type where every element
// is the same type. Use element 0 to get the type.
@@ -749,8 +747,8 @@
const analysis::Constant* length_const =
context->get_constant_mgr()->FindDeclaredConstant(
array_type->LengthId());
- assert(length_const->AsIntConstant());
- return length_const->AsIntConstant()->GetU32();
+ assert(length_const->type()->AsInteger());
+ return length_const->GetU32();
} else if (const analysis::Vector* vector_type = type->AsVector()) {
return vector_type->element_count();
} else if (const analysis::Matrix* matrix_type = type->AsMatrix()) {
@@ -776,8 +774,7 @@
if (!element_index_const) {
access_indices.push_back(0);
} else {
- assert(element_index_const->AsIntConstant());
- access_indices.push_back(element_index_const->AsIntConstant()->GetU32());
+ access_indices.push_back(element_index_const->GetU32());
}
}
return access_indices;
diff --git a/source/opt/feature_manager.h b/source/opt/feature_manager.h
index 761a208..2fe3291 100644
--- a/source/opt/feature_manager.h
+++ b/source/opt/feature_manager.h
@@ -57,6 +57,9 @@
// Add the extension |ext| to the feature manager.
void AddExtension(Instruction* ext);
+ // Analyzes |module| and records imported external instruction sets.
+ void AddExtInstImportIds(Module* module);
+
private:
// Analyzes |module| and records enabled extensions.
void AddExtensions(Module* module);
@@ -64,9 +67,6 @@
// Analyzes |module| and records enabled capabilities.
void AddCapabilities(Module* module);
- // Analyzes |module| and records imported external instruction sets.
- void AddExtInstImportIds(Module* module);
-
// Auxiliary object for querying SPIR-V grammar facts.
const AssemblyGrammar& grammar_;
diff --git a/source/opt/fold.cpp b/source/opt/fold.cpp
index 276e835..6550fb4 100644
--- a/source/opt/fold.cpp
+++ b/source/opt/fold.cpp
@@ -56,6 +56,10 @@
return ~operand;
case SpvOp::SpvOpLogicalNot:
return !static_cast<bool>(operand);
+ case SpvOp::SpvOpUConvert:
+ return operand;
+ case SpvOp::SpvOpSConvert:
+ return operand;
default:
assert(false &&
"Unsupported unary operation for OpSpecConstantOp instruction");
@@ -596,6 +600,8 @@
case SpvOp::SpvOpSMod:
case SpvOp::SpvOpSNegate:
case SpvOp::SpvOpSRem:
+ case SpvOp::SpvOpSConvert:
+ case SpvOp::SpvOpUConvert:
case SpvOp::SpvOpUDiv:
case SpvOp::SpvOpUGreaterThan:
case SpvOp::SpvOpUGreaterThanEqual:
@@ -646,6 +652,9 @@
if (folded_const != nullptr) {
Instruction* const_inst =
const_mgr->GetDefiningInstruction(folded_const, inst->type_id());
+ if (const_inst == nullptr) {
+ return nullptr;
+ }
assert(const_inst->type_id() == inst->type_id());
// May be a new instruction that needs to be analysed.
context_->UpdateDefUse(const_inst);
diff --git a/source/opt/fold_spec_constant_op_and_composite_pass.cpp b/source/opt/fold_spec_constant_op_and_composite_pass.cpp
index 56d0137..8ab717e 100644
--- a/source/opt/fold_spec_constant_op_and_composite_pass.cpp
+++ b/source/opt/fold_spec_constant_op_and_composite_pass.cpp
@@ -316,6 +316,59 @@
}
return false;
}
+
+// Encodes the integer |value| of in a word vector format appropriate for
+// representing this value as a operands for a constant definition. Performs
+// zero-extension/sign-extension/truncation when needed, based on the signess of
+// the given target type.
+//
+// Note: type |type| argument must be either Integer or Bool.
+utils::SmallVector<uint32_t, 2> EncodeIntegerAsWords(const analysis::Type& type,
+ uint32_t value) {
+ const uint32_t all_ones = ~0;
+ uint32_t bit_width = 0;
+ uint32_t pad_value = 0;
+ bool result_type_signed = false;
+ if (auto* int_ty = type.AsInteger()) {
+ bit_width = int_ty->width();
+ result_type_signed = int_ty->IsSigned();
+ if (result_type_signed && static_cast<int32_t>(value) < 0) {
+ pad_value = all_ones;
+ }
+ } else if (type.AsBool()) {
+ bit_width = 1;
+ } else {
+ assert(false && "type must be Integer or Bool");
+ }
+
+ assert(bit_width > 0);
+ uint32_t first_word = value;
+ const uint32_t bits_per_word = 32;
+
+ // Truncate first_word if the |type| has width less than uint32.
+ if (bit_width < bits_per_word) {
+ const uint32_t num_high_bits_to_mask = bits_per_word - bit_width;
+ const bool is_negative_after_truncation =
+ result_type_signed &&
+ utils::IsBitAtPositionSet(first_word, bit_width - 1);
+
+ if (is_negative_after_truncation) {
+ // Truncate and sign-extend |first_word|. No padding words will be
+ // added and |pad_value| can be left as-is.
+ first_word = utils::SetHighBits(first_word, num_high_bits_to_mask);
+ } else {
+ first_word = utils::ClearHighBits(first_word, num_high_bits_to_mask);
+ }
+ }
+
+ utils::SmallVector<uint32_t, 2> words = {first_word};
+ for (uint32_t current_bit = bits_per_word; current_bit < bit_width;
+ current_bit += bits_per_word) {
+ words.push_back(pad_value);
+ }
+
+ return words;
+}
} // namespace
Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation(
@@ -345,10 +398,10 @@
if (result_type->AsInteger() || result_type->AsBool()) {
// Scalar operation
- uint32_t result_val =
+ const uint32_t result_val =
context()->get_instruction_folder().FoldScalars(spec_opcode, operands);
- auto result_const =
- context()->get_constant_mgr()->GetConstant(result_type, {result_val});
+ auto result_const = context()->get_constant_mgr()->GetConstant(
+ result_type, EncodeIntegerAsWords(*result_type, result_val));
return context()->get_constant_mgr()->BuildInstructionAndAddToModule(
result_const, pos);
} else if (result_type->AsVector()) {
@@ -360,9 +413,9 @@
context()->get_instruction_folder().FoldVectors(spec_opcode, num_dims,
operands);
std::vector<const analysis::Constant*> result_vector_components;
- for (uint32_t r : result_vec) {
- if (auto rc =
- context()->get_constant_mgr()->GetConstant(element_type, {r})) {
+ for (const uint32_t r : result_vec) {
+ if (auto rc = context()->get_constant_mgr()->GetConstant(
+ element_type, EncodeIntegerAsWords(*element_type, r))) {
result_vector_components.push_back(rc);
if (!context()->get_constant_mgr()->BuildInstructionAndAddToModule(
rc, pos)) {
diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp
index a125dda..de740ca 100644
--- a/source/opt/folding_rules.cpp
+++ b/source/opt/folding_rules.cpp
@@ -18,6 +18,7 @@
#include <memory>
#include <utility>
+#include "ir_builder.h"
#include "source/latest_version_glsl_std_450_header.h"
#include "source/opt/ir_context.h"
@@ -35,6 +36,45 @@
const uint32_t kFMixAIdInIdx = 4;
const uint32_t kStoreObjectInIdx = 1;
+// Some image instructions may contain an "image operands" argument.
+// Returns the operand index for the "image operands".
+// Returns -1 if the instruction does not have image operands.
+int32_t ImageOperandsMaskInOperandIndex(Instruction* inst) {
+ const auto opcode = inst->opcode();
+ switch (opcode) {
+ case SpvOpImageSampleImplicitLod:
+ case SpvOpImageSampleExplicitLod:
+ case SpvOpImageSampleProjImplicitLod:
+ case SpvOpImageSampleProjExplicitLod:
+ case SpvOpImageFetch:
+ case SpvOpImageRead:
+ case SpvOpImageSparseSampleImplicitLod:
+ case SpvOpImageSparseSampleExplicitLod:
+ case SpvOpImageSparseSampleProjImplicitLod:
+ case SpvOpImageSparseSampleProjExplicitLod:
+ case SpvOpImageSparseFetch:
+ case SpvOpImageSparseRead:
+ return inst->NumOperands() > 4 ? 2 : -1;
+ case SpvOpImageSampleDrefImplicitLod:
+ case SpvOpImageSampleDrefExplicitLod:
+ case SpvOpImageSampleProjDrefImplicitLod:
+ case SpvOpImageSampleProjDrefExplicitLod:
+ case SpvOpImageGather:
+ case SpvOpImageDrefGather:
+ case SpvOpImageSparseSampleDrefImplicitLod:
+ case SpvOpImageSparseSampleDrefExplicitLod:
+ case SpvOpImageSparseSampleProjDrefImplicitLod:
+ case SpvOpImageSparseSampleProjDrefExplicitLod:
+ case SpvOpImageSparseGather:
+ case SpvOpImageSparseDrefGather:
+ return inst->NumOperands() > 5 ? 3 : -1;
+ case SpvOpImageWrite:
+ return inst->NumOperands() > 3 ? 3 : -1;
+ default:
+ return -1;
+ }
+}
+
// Returns the element width of |type|.
uint32_t ElementWidth(const analysis::Type* type) {
if (const analysis::Vector* vec_type = type->AsVector()) {
@@ -1239,6 +1279,117 @@
};
}
+// Helper function for MergeGenericAddSubArithmetic. If |addend| and
+// subtrahend of |sub| is the same, merge to copy of minuend of |sub|.
+bool MergeGenericAddendSub(uint32_t addend, uint32_t sub, Instruction* inst) {
+ IRContext* context = inst->context();
+ analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
+ Instruction* sub_inst = def_use_mgr->GetDef(sub);
+ if (sub_inst->opcode() != SpvOpFSub && sub_inst->opcode() != SpvOpISub)
+ return false;
+ if (sub_inst->opcode() == SpvOpFSub &&
+ !sub_inst->IsFloatingPointFoldingAllowed())
+ return false;
+ if (addend != sub_inst->GetSingleWordInOperand(1)) return false;
+ inst->SetOpcode(SpvOpCopyObject);
+ inst->SetInOperands(
+ {{SPV_OPERAND_TYPE_ID, {sub_inst->GetSingleWordInOperand(0)}}});
+ context->UpdateDefUse(inst);
+ return true;
+}
+
+// Folds addition of a subtraction where the subtrahend is equal to the
+// other addend. Return a copy of the minuend. Accepts generic (const and
+// non-const) operands.
+// Cases:
+// (a - b) + b = a
+// b + (a - b) = a
+FoldingRule MergeGenericAddSubArithmetic() {
+ return [](IRContext* context, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ assert(inst->opcode() == SpvOpFAdd || inst->opcode() == SpvOpIAdd);
+ const analysis::Type* type =
+ context->get_type_mgr()->GetType(inst->type_id());
+ bool uses_float = HasFloatingPoint(type);
+ if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false;
+
+ uint32_t width = ElementWidth(type);
+ if (width != 32 && width != 64) return false;
+
+ uint32_t add_op0 = inst->GetSingleWordInOperand(0);
+ uint32_t add_op1 = inst->GetSingleWordInOperand(1);
+ if (MergeGenericAddendSub(add_op0, add_op1, inst)) return true;
+ return MergeGenericAddendSub(add_op1, add_op0, inst);
+ };
+}
+
+// Helper function for FactorAddMuls. If |factor0_0| is the same as |factor1_0|,
+// generate |factor0_0| * (|factor0_1| + |factor1_1|).
+bool FactorAddMulsOpnds(uint32_t factor0_0, uint32_t factor0_1,
+ uint32_t factor1_0, uint32_t factor1_1,
+ Instruction* inst) {
+ IRContext* context = inst->context();
+ if (factor0_0 != factor1_0) return false;
+ InstructionBuilder ir_builder(
+ context, inst,
+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+ Instruction* new_add_inst = ir_builder.AddBinaryOp(
+ inst->type_id(), inst->opcode(), factor0_1, factor1_1);
+ inst->SetOpcode(inst->opcode() == SpvOpFAdd ? SpvOpFMul : SpvOpIMul);
+ inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {factor0_0}},
+ {SPV_OPERAND_TYPE_ID, {new_add_inst->result_id()}}});
+ context->UpdateDefUse(inst);
+ return true;
+}
+
+// Perform the following factoring identity, handling all operand order
+// combinations: (a * b) + (a * c) = a * (b + c)
+FoldingRule FactorAddMuls() {
+ return [](IRContext* context, Instruction* inst,
+ const std::vector<const analysis::Constant*>&) {
+ assert(inst->opcode() == SpvOpFAdd || inst->opcode() == SpvOpIAdd);
+ const analysis::Type* type =
+ context->get_type_mgr()->GetType(inst->type_id());
+ bool uses_float = HasFloatingPoint(type);
+ if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false;
+
+ analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
+ uint32_t add_op0 = inst->GetSingleWordInOperand(0);
+ Instruction* add_op0_inst = def_use_mgr->GetDef(add_op0);
+ if (add_op0_inst->opcode() != SpvOpFMul &&
+ add_op0_inst->opcode() != SpvOpIMul)
+ return false;
+ uint32_t add_op1 = inst->GetSingleWordInOperand(1);
+ Instruction* add_op1_inst = def_use_mgr->GetDef(add_op1);
+ if (add_op1_inst->opcode() != SpvOpFMul &&
+ add_op1_inst->opcode() != SpvOpIMul)
+ return false;
+
+ // Only perform this optimization if both of the muls only have one use.
+ // Otherwise this is a deoptimization in size and performance.
+ if (def_use_mgr->NumUses(add_op0_inst) > 1) return false;
+ if (def_use_mgr->NumUses(add_op1_inst) > 1) return false;
+
+ if (add_op0_inst->opcode() == SpvOpFMul &&
+ (!add_op0_inst->IsFloatingPointFoldingAllowed() ||
+ !add_op1_inst->IsFloatingPointFoldingAllowed()))
+ return false;
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ // Check if operand i in add_op0_inst matches operand j in add_op1_inst.
+ if (FactorAddMulsOpnds(add_op0_inst->GetSingleWordInOperand(i),
+ add_op0_inst->GetSingleWordInOperand(1 - i),
+ add_op1_inst->GetSingleWordInOperand(j),
+ add_op1_inst->GetSingleWordInOperand(1 - j),
+ inst))
+ return true;
+ }
+ }
+ return false;
+ };
+}
+
FoldingRule IntMultipleBy1() {
return [](IRContext*, Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
@@ -1274,6 +1425,12 @@
"Wrong opcode. Should be OpCompositeExtract.");
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
+
+ // If there are no index operands, then this rule cannot do anything.
+ if (inst->NumInOperands() <= 1) {
+ return false;
+ }
+
uint32_t cid = inst->GetSingleWordInOperand(kExtractCompositeIdInIdx);
Instruction* cinst = def_use_mgr->GetDef(cid);
@@ -2198,6 +2355,64 @@
};
}
+// If an image instruction's operand is a constant, updates the image operand
+// flag from Offset to ConstOffset.
+FoldingRule UpdateImageOperands() {
+ return [](IRContext*, Instruction* inst,
+ const std::vector<const analysis::Constant*>& constants) {
+ const auto opcode = inst->opcode();
+ (void)opcode;
+ assert((opcode == SpvOpImageSampleImplicitLod ||
+ opcode == SpvOpImageSampleExplicitLod ||
+ opcode == SpvOpImageSampleDrefImplicitLod ||
+ opcode == SpvOpImageSampleDrefExplicitLod ||
+ opcode == SpvOpImageSampleProjImplicitLod ||
+ opcode == SpvOpImageSampleProjExplicitLod ||
+ opcode == SpvOpImageSampleProjDrefImplicitLod ||
+ opcode == SpvOpImageSampleProjDrefExplicitLod ||
+ opcode == SpvOpImageFetch || opcode == SpvOpImageGather ||
+ opcode == SpvOpImageDrefGather || opcode == SpvOpImageRead ||
+ opcode == SpvOpImageWrite ||
+ opcode == SpvOpImageSparseSampleImplicitLod ||
+ opcode == SpvOpImageSparseSampleExplicitLod ||
+ opcode == SpvOpImageSparseSampleDrefImplicitLod ||
+ opcode == SpvOpImageSparseSampleDrefExplicitLod ||
+ opcode == SpvOpImageSparseSampleProjImplicitLod ||
+ opcode == SpvOpImageSparseSampleProjExplicitLod ||
+ opcode == SpvOpImageSparseSampleProjDrefImplicitLod ||
+ opcode == SpvOpImageSparseSampleProjDrefExplicitLod ||
+ opcode == SpvOpImageSparseFetch ||
+ opcode == SpvOpImageSparseGather ||
+ opcode == SpvOpImageSparseDrefGather ||
+ opcode == SpvOpImageSparseRead) &&
+ "Wrong opcode. Should be an image instruction.");
+
+ int32_t operand_index = ImageOperandsMaskInOperandIndex(inst);
+ if (operand_index >= 0) {
+ auto image_operands = inst->GetSingleWordInOperand(operand_index);
+ if (image_operands & SpvImageOperandsOffsetMask) {
+ uint32_t offset_operand_index = operand_index + 1;
+ if (image_operands & SpvImageOperandsBiasMask) offset_operand_index++;
+ if (image_operands & SpvImageOperandsLodMask) offset_operand_index++;
+ if (image_operands & SpvImageOperandsGradMask)
+ offset_operand_index += 2;
+ assert(((image_operands & SpvImageOperandsConstOffsetMask) == 0) &&
+ "Offset and ConstOffset may not be used together");
+ if (offset_operand_index < inst->NumOperands()) {
+ if (constants[offset_operand_index]) {
+ image_operands = image_operands | SpvImageOperandsConstOffsetMask;
+ image_operands = image_operands & ~SpvImageOperandsOffsetMask;
+ inst->SetInOperand(operand_index, {image_operands});
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ };
+}
+
} // namespace
void FoldingRules::AddFoldingRules() {
@@ -2220,6 +2435,8 @@
rules_[SpvOpFAdd].push_back(MergeAddNegateArithmetic());
rules_[SpvOpFAdd].push_back(MergeAddAddArithmetic());
rules_[SpvOpFAdd].push_back(MergeAddSubArithmetic());
+ rules_[SpvOpFAdd].push_back(MergeGenericAddSubArithmetic());
+ rules_[SpvOpFAdd].push_back(FactorAddMuls());
rules_[SpvOpFDiv].push_back(RedundantFDiv());
rules_[SpvOpFDiv].push_back(ReciprocalFDiv());
@@ -2245,6 +2462,8 @@
rules_[SpvOpIAdd].push_back(MergeAddNegateArithmetic());
rules_[SpvOpIAdd].push_back(MergeAddAddArithmetic());
rules_[SpvOpIAdd].push_back(MergeAddSubArithmetic());
+ rules_[SpvOpIAdd].push_back(MergeGenericAddSubArithmetic());
+ rules_[SpvOpIAdd].push_back(FactorAddMuls());
rules_[SpvOpIMul].push_back(IntMultipleBy1());
rules_[SpvOpIMul].push_back(MergeMulMulArithmetic());
@@ -2270,6 +2489,38 @@
rules_[SpvOpVectorShuffle].push_back(VectorShuffleFeedingShuffle());
+ rules_[SpvOpImageSampleImplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSampleExplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSampleDrefImplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSampleDrefExplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSampleProjImplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSampleProjExplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSampleProjDrefImplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSampleProjDrefExplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageFetch].push_back(UpdateImageOperands());
+ rules_[SpvOpImageGather].push_back(UpdateImageOperands());
+ rules_[SpvOpImageDrefGather].push_back(UpdateImageOperands());
+ rules_[SpvOpImageRead].push_back(UpdateImageOperands());
+ rules_[SpvOpImageWrite].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSparseSampleImplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSparseSampleExplicitLod].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSparseSampleDrefImplicitLod].push_back(
+ UpdateImageOperands());
+ rules_[SpvOpImageSparseSampleDrefExplicitLod].push_back(
+ UpdateImageOperands());
+ rules_[SpvOpImageSparseSampleProjImplicitLod].push_back(
+ UpdateImageOperands());
+ rules_[SpvOpImageSparseSampleProjExplicitLod].push_back(
+ UpdateImageOperands());
+ rules_[SpvOpImageSparseSampleProjDrefImplicitLod].push_back(
+ UpdateImageOperands());
+ rules_[SpvOpImageSparseSampleProjDrefExplicitLod].push_back(
+ UpdateImageOperands());
+ rules_[SpvOpImageSparseFetch].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSparseGather].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSparseDrefGather].push_back(UpdateImageOperands());
+ rules_[SpvOpImageSparseRead].push_back(UpdateImageOperands());
+
FeatureManager* feature_manager = context_->get_feature_mgr();
// Add rules for GLSLstd450
uint32_t ext_inst_glslstd450_id =
diff --git a/source/opt/function.cpp b/source/opt/function.cpp
index 2520052..efda68b 100644
--- a/source/opt/function.cpp
+++ b/source/opt/function.cpp
@@ -13,13 +13,14 @@
// limitations under the License.
#include "source/opt/function.h"
-#include "function.h"
-#include "ir_context.h"
-#include <source/util/bit_vector.h>
#include <ostream>
#include <sstream>
+#include "function.h"
+#include "ir_context.h"
+#include "source/util/bit_vector.h"
+
namespace spvtools {
namespace opt {
diff --git a/source/opt/function.h b/source/opt/function.h
index b1317ad..3908568 100644
--- a/source/opt/function.h
+++ b/source/opt/function.h
@@ -104,19 +104,24 @@
});
}
- // Runs the given function |f| on each instruction in this function, and
- // optionally on debug line instructions that might precede them.
+ // Runs the given function |f| on instructions in this function, in order,
+ // and optionally on debug line instructions that might precede them.
void ForEachInst(const std::function<void(Instruction*)>& f,
bool run_on_debug_line_insts = false);
void ForEachInst(const std::function<void(const Instruction*)>& f,
bool run_on_debug_line_insts = false) const;
+ // Runs the given function |f| on instructions in this function, in order,
+ // and optionally on debug line instructions that might precede them.
+ // If |f| returns false, iteration is terminated and this function returns
+ // false.
bool WhileEachInst(const std::function<bool(Instruction*)>& f,
bool run_on_debug_line_insts = false);
bool WhileEachInst(const std::function<bool(const Instruction*)>& f,
bool run_on_debug_line_insts = false) const;
// Runs the given function |f| on each parameter instruction in this function,
- // and optionally on debug line instructions that might precede them.
+ // in order, and optionally on debug line instructions that might precede
+ // them.
void ForEachParam(const std::function<void(const Instruction*)>& f,
bool run_on_debug_line_insts = false) const;
void ForEachParam(const std::function<void(Instruction*)>& f,
diff --git a/source/opt/generate_webgpu_initializers_pass.cpp b/source/opt/generate_webgpu_initializers_pass.cpp
index 9334b43..eaed3c2 100644
--- a/source/opt/generate_webgpu_initializers_pass.cpp
+++ b/source/opt/generate_webgpu_initializers_pass.cpp
@@ -59,6 +59,8 @@
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);
@@ -78,6 +80,8 @@
changed = true;
auto* constant_inst = GetNullConstantForVariable(inst);
+ if (!constant_inst) return Status::Failure;
+
AddNullInitializerToVariable(constant_inst, inst);
}
}
diff --git a/source/opt/graphics_robust_access_pass.cpp b/source/opt/graphics_robust_access_pass.cpp
index dd60e8c..e309d3a 100644
--- a/source/opt/graphics_robust_access_pass.cpp
+++ b/source/opt/graphics_robust_access_pass.cpp
@@ -160,7 +160,6 @@
namespace spvtools {
namespace opt {
-using opt::BasicBlock;
using opt::Instruction;
using opt::Operand;
using spvtools::MakeUnique;
diff --git a/source/opt/graphics_robust_access_pass.h b/source/opt/graphics_robust_access_pass.h
index 215cbf1..b21154e 100644
--- a/source/opt/graphics_robust_access_pass.h
+++ b/source/opt/graphics_robust_access_pass.h
@@ -81,8 +81,8 @@
// sign extension or zero extension. The new instruction is inserted
// immediately before |before_inst|, and is analyzed for definitions and uses.
// Returns the newly inserted instruction. Assumes the |value| is an integer
- // scalar of a narrower type than |bitwidth| bits.
- Instruction* WidenInteger(bool sign_extend, uint32_t bitwidth,
+ // scalar of a narrower type than |bit_width| bits.
+ Instruction* WidenInteger(bool sign_extend, uint32_t bit_width,
Instruction* value, Instruction* before_inst);
// Returns a new instruction that invokes the UClamp GLSL.std.450 extended
@@ -109,7 +109,8 @@
// the module is modified. Returns a status code to indicate success
// or failure. If assumptions are not met, returns an error status code
// and emits a diagnostic.
- spv_result_t ClampCoordinateForImageTexelPointer(opt::Instruction* itp);
+ spv_result_t ClampCoordinateForImageTexelPointer(
+ opt::Instruction* image_texel_pointer);
// Gets the instruction that defines the given id.
opt::Instruction* GetDef(uint32_t id) {
diff --git a/source/opt/inline_pass.cpp b/source/opt/inline_pass.cpp
index f348bbe..36991ec 100644
--- a/source/opt/inline_pass.cpp
+++ b/source/opt/inline_pass.cpp
@@ -720,9 +720,24 @@
return false;
}
+ // Do not inline functions with an OpKill if they are called from a continue
+ // construct. If it is inlined into a continue construct it will generate
+ // invalid code.
+ bool func_is_called_from_continue =
+ funcs_called_from_continue_.count(func->result_id()) != 0;
+
+ if (func_is_called_from_continue && ContainsKill(func)) {
+ return false;
+ }
+
return true;
}
+bool InlinePass::ContainsKill(Function* func) const {
+ return !func->WhileEachInst(
+ [](Instruction* inst) { return inst->opcode() != SpvOpKill; });
+}
+
void InlinePass::InitializeInline() {
false_id_ = 0;
@@ -732,6 +747,8 @@
inlinable_.clear();
no_return_in_loop_.clear();
early_return_funcs_.clear();
+ funcs_called_from_continue_ =
+ context()->GetStructuredCFGAnalysis()->FindFuncsCalledFromContinue();
for (auto& fn : *get_module()) {
// Initialize function and block maps.
diff --git a/source/opt/inline_pass.h b/source/opt/inline_pass.h
index ecfe964..bc5f781 100644
--- a/source/opt/inline_pass.h
+++ b/source/opt/inline_pass.h
@@ -139,6 +139,9 @@
// Return true if |func| is a function that can be inlined.
bool IsInlinableFunction(Function* func);
+ // Returns true if |func| contains an OpKill instruction.
+ bool ContainsKill(Function* func) const;
+
// Update phis in succeeding blocks to point to new last block
void UpdateSucceedingPhis(
std::vector<std::unique_ptr<BasicBlock>>& new_blocks);
@@ -164,6 +167,10 @@
// result id for OpConstantFalse
uint32_t false_id_;
+
+ // Set of functions that are originally called directly or indirectly from a
+ // continue construct.
+ std::unordered_set<uint32_t> funcs_called_from_continue_;
};
} // namespace opt
diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp
index b283354..4587343 100644
--- a/source/opt/inst_bindless_check_pass.cpp
+++ b/source/opt/inst_bindless_check_pass.cpp
@@ -296,7 +296,7 @@
// reference.
if (new_ref_id != 0) {
Instruction* phi_inst = builder.AddPhi(
- ref_type_id, {new_ref_id, valid_blk_id, builder.GetNullId(ref_type_id),
+ ref_type_id, {new_ref_id, valid_blk_id, GetNullId(ref_type_id),
last_invalid_blk_id});
context()->ReplaceAllUsesWith(ref->ref_inst->result_id(),
phi_inst->result_id());
diff --git a/source/opt/inst_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp
index 03221ef..fa6c2c6 100644
--- a/source/opt/inst_buff_addr_check_pass.cpp
+++ b/source/opt/inst_buff_addr_check_pass.cpp
@@ -96,8 +96,22 @@
uid2offset_[ref_inst->unique_id()], stage_idx,
{error_id, lo_uptr_inst->result_id(), hi_uptr_inst->result_id()},
&builder);
- // Gen zero for invalid reference
- uint32_t ref_type_id = ref_inst->type_id();
+ // Gen zero for invalid load. If pointer type, need to convert uint64
+ // zero to pointer; cannot create ConstantNull of pointer type.
+ uint32_t null_id = 0;
+ if (new_ref_id != 0) {
+ uint32_t ref_type_id = ref_inst->type_id();
+ analysis::TypeManager* type_mgr = context()->get_type_mgr();
+ analysis::Type* ref_type = type_mgr->GetType(ref_type_id);
+ if (ref_type->AsPointer() != nullptr) {
+ uint32_t null_u64_id = GetNullId(GetUint64Id());
+ Instruction* null_ptr_inst =
+ builder.AddUnaryOp(ref_type_id, SpvOpConvertUToPtr, null_u64_id);
+ null_id = null_ptr_inst->result_id();
+ } else {
+ null_id = GetNullId(ref_type_id);
+ }
+ }
(void)builder.AddBranch(merge_blk_id);
new_blocks->push_back(std::move(new_blk_ptr));
// Gen merge block
@@ -107,9 +121,9 @@
// result id of the original reference with that of the Phi. Kill original
// reference.
if (new_ref_id != 0) {
- Instruction* phi_inst = builder.AddPhi(
- ref_type_id, {new_ref_id, valid_blk_id, builder.GetNullId(ref_type_id),
- invalid_blk_id});
+ Instruction* phi_inst =
+ builder.AddPhi(ref_inst->type_id(),
+ {new_ref_id, valid_blk_id, null_id, invalid_blk_id});
context()->ReplaceAllUsesWith(ref_inst->result_id(), phi_inst->result_id());
}
new_blocks->push_back(std::move(new_blk_ptr));
diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp
index 246cdbb..2a3e7f0 100644
--- a/source/opt/instrument_pass.cpp
+++ b/source/opt/instrument_pass.cpp
@@ -325,29 +325,36 @@
std::unordered_map<uint32_t, uint32_t>* same_blk_post,
std::unordered_map<uint32_t, Instruction*>* same_blk_pre,
BasicBlock* block_ptr) {
- (*inst)->ForEachInId(
- [&same_blk_post, &same_blk_pre, &block_ptr, this](uint32_t* iid) {
- const auto map_itr = (*same_blk_post).find(*iid);
- if (map_itr == (*same_blk_post).end()) {
- const auto map_itr2 = (*same_blk_pre).find(*iid);
- if (map_itr2 != (*same_blk_pre).end()) {
- // Clone pre-call same-block ops, map result id.
- const Instruction* in_inst = map_itr2->second;
- std::unique_ptr<Instruction> sb_inst(in_inst->Clone(context()));
- CloneSameBlockOps(&sb_inst, same_blk_post, same_blk_pre, block_ptr);
- const uint32_t rid = sb_inst->result_id();
- const uint32_t nid = this->TakeNextId();
- get_decoration_mgr()->CloneDecorations(rid, nid);
- sb_inst->SetResultId(nid);
- (*same_blk_post)[rid] = nid;
- *iid = nid;
- block_ptr->AddInstruction(std::move(sb_inst));
- }
- } else {
- // Reset same-block op operand.
- *iid = map_itr->second;
- }
- });
+ bool changed = false;
+ (*inst)->ForEachInId([&same_blk_post, &same_blk_pre, &block_ptr, &changed,
+ this](uint32_t* iid) {
+ const auto map_itr = (*same_blk_post).find(*iid);
+ if (map_itr == (*same_blk_post).end()) {
+ const auto map_itr2 = (*same_blk_pre).find(*iid);
+ if (map_itr2 != (*same_blk_pre).end()) {
+ // Clone pre-call same-block ops, map result id.
+ const Instruction* in_inst = map_itr2->second;
+ std::unique_ptr<Instruction> sb_inst(in_inst->Clone(context()));
+ const uint32_t rid = sb_inst->result_id();
+ const uint32_t nid = this->TakeNextId();
+ get_decoration_mgr()->CloneDecorations(rid, nid);
+ sb_inst->SetResultId(nid);
+ get_def_use_mgr()->AnalyzeInstDefUse(&*sb_inst);
+ (*same_blk_post)[rid] = nid;
+ *iid = nid;
+ changed = true;
+ CloneSameBlockOps(&sb_inst, same_blk_post, same_blk_pre, block_ptr);
+ block_ptr->AddInstruction(std::move(sb_inst));
+ }
+ } else {
+ // Reset same-block op operand if necessary
+ if (*iid != map_itr->second) {
+ *iid = map_itr->second;
+ changed = true;
+ }
+ }
+ });
+ if (changed) get_def_use_mgr()->AnalyzeInstUse(&**inst);
}
void InstrumentPass::UpdateSucceedingPhis(
diff --git a/source/opt/ir_builder.h b/source/opt/ir_builder.h
index a0ca40c..b0c1d2e 100644
--- a/source/opt/ir_builder.h
+++ b/source/opt/ir_builder.h
@@ -59,27 +59,43 @@
preserved_analyses) {}
Instruction* AddNullaryOp(uint32_t type_id, SpvOp opcode) {
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> newUnOp(new Instruction(
- GetContext(), opcode, type_id,
- opcode == SpvOpReturn ? 0 : GetContext()->TakeNextId(), {}));
- return AddInstruction(std::move(newUnOp));
+ uint32_t result_id = 0;
+ if (type_id != 0) {
+ result_id = GetContext()->TakeNextId();
+ if (result_id == 0) {
+ return nullptr;
+ }
+ }
+ std::unique_ptr<Instruction> new_inst(
+ new Instruction(GetContext(), opcode, type_id, result_id, {}));
+ return AddInstruction(std::move(new_inst));
}
Instruction* AddUnaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1) {
- // TODO(1841): Handle id overflow.
+ uint32_t result_id = 0;
+ if (type_id != 0) {
+ result_id = GetContext()->TakeNextId();
+ if (result_id == 0) {
+ return nullptr;
+ }
+ }
std::unique_ptr<Instruction> newUnOp(new Instruction(
- GetContext(), opcode, type_id, GetContext()->TakeNextId(),
+ GetContext(), opcode, type_id, result_id,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}}));
return AddInstruction(std::move(newUnOp));
}
Instruction* AddBinaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1,
uint32_t operand2) {
- // TODO(1841): Handle id overflow.
+ uint32_t result_id = 0;
+ if (type_id != 0) {
+ result_id = GetContext()->TakeNextId();
+ if (result_id == 0) {
+ return nullptr;
+ }
+ }
std::unique_ptr<Instruction> newBinOp(new Instruction(
- GetContext(), opcode, type_id,
- opcode == SpvOpStore ? 0 : GetContext()->TakeNextId(),
+ GetContext(), opcode, type_id, opcode == SpvOpStore ? 0 : result_id,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}}));
return AddInstruction(std::move(newBinOp));
@@ -87,9 +103,15 @@
Instruction* AddTernaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1,
uint32_t operand2, uint32_t operand3) {
- // TODO(1841): Handle id overflow.
+ uint32_t result_id = 0;
+ if (type_id != 0) {
+ result_id = GetContext()->TakeNextId();
+ if (result_id == 0) {
+ return nullptr;
+ }
+ }
std::unique_ptr<Instruction> newTernOp(new Instruction(
- GetContext(), opcode, type_id, GetContext()->TakeNextId(),
+ GetContext(), opcode, type_id, result_id,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}}));
@@ -99,9 +121,15 @@
Instruction* AddQuadOp(uint32_t type_id, SpvOp opcode, uint32_t operand1,
uint32_t operand2, uint32_t operand3,
uint32_t operand4) {
- // TODO(1841): Handle id overflow.
+ uint32_t result_id = 0;
+ if (type_id != 0) {
+ result_id = GetContext()->TakeNextId();
+ if (result_id == 0) {
+ return nullptr;
+ }
+ }
std::unique_ptr<Instruction> newQuadOp(new Instruction(
- GetContext(), opcode, type_id, GetContext()->TakeNextId(),
+ GetContext(), opcode, type_id, result_id,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}},
@@ -109,13 +137,19 @@
return AddInstruction(std::move(newQuadOp));
}
- Instruction* AddIdLiteralOp(uint32_t type_id, SpvOp opcode, uint32_t operand1,
- uint32_t operand2) {
- // TODO(1841): Handle id overflow.
+ Instruction* AddIdLiteralOp(uint32_t type_id, SpvOp opcode, uint32_t id,
+ uint32_t uliteral) {
+ uint32_t result_id = 0;
+ if (type_id != 0) {
+ result_id = GetContext()->TakeNextId();
+ if (result_id == 0) {
+ return nullptr;
+ }
+ }
std::unique_ptr<Instruction> newBinOp(new Instruction(
- GetContext(), opcode, type_id, GetContext()->TakeNextId(),
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {operand2}}}));
+ GetContext(), opcode, type_id, result_id,
+ {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {id}},
+ {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {uliteral}}}));
return AddInstruction(std::move(newBinOp));
}
@@ -358,16 +392,6 @@
return uint_inst->result_id();
}
- uint32_t GetNullId(uint32_t type_id) {
- analysis::TypeManager* type_mgr = GetContext()->get_type_mgr();
- analysis::ConstantManager* const_mgr = GetContext()->get_constant_mgr();
- const analysis::Type* type = type_mgr->GetType(type_id);
- const analysis::Constant* null_const = const_mgr->GetConstant(type, {});
- Instruction* null_inst =
- const_mgr->GetDefiningInstruction(null_const, type_id);
- return null_inst->result_id();
- }
-
// Adds either a signed or unsigned 32 bit integer constant to the binary
// depedning on the |sign|. If |sign| is true then the value is added as a
// signed constant otherwise as an unsigned constant. If |sign| is false the
@@ -502,6 +526,27 @@
return AddInstruction(std::move(new_inst));
}
+ Instruction* AddNaryExtendedInstruction(
+ uint32_t result_type, uint32_t set, uint32_t instruction,
+ const std::vector<uint32_t>& ext_operands) {
+ std::vector<Operand> operands;
+ operands.push_back({SPV_OPERAND_TYPE_ID, {set}});
+ operands.push_back(
+ {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {instruction}});
+ for (uint32_t id : ext_operands) {
+ operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
+ }
+
+ uint32_t result_id = GetContext()->TakeNextId();
+ if (result_id == 0) {
+ return nullptr;
+ }
+
+ std::unique_ptr<Instruction> new_inst(new Instruction(
+ GetContext(), SpvOpExtInst, result_type, result_id, operands));
+ return AddInstruction(std::move(new_inst));
+ }
+
// Inserts the new instruction before the insertion point.
Instruction* AddInstruction(std::unique_ptr<Instruction>&& insn) {
Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));
diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp
index 1c747b7..d940180 100644
--- a/source/opt/ir_context.cpp
+++ b/source/opt/ir_context.cpp
@@ -94,6 +94,14 @@
if (analyses_to_invalidate & kAnalysisTypes) {
analyses_to_invalidate |= kAnalysisConstants;
}
+
+ // The dominator analysis hold the psuedo entry and exit nodes from the CFG.
+ // Also if the CFG change the dominators many changed as well, so the
+ // dominator analysis should be invalidated as well.
+ if (analyses_to_invalidate & kAnalysisCFG) {
+ analyses_to_invalidate |= kAnalysisDominatorAnalysis;
+ }
+
if (analyses_to_invalidate & kAnalysisDefUse) {
def_use_mgr_.reset(nullptr);
}
diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h
index e297fb1..45bf129 100644
--- a/source/opt/ir_context.h
+++ b/source/opt/ir_context.h
@@ -187,9 +187,6 @@
inline IteratorRange<Module::inst_iterator> debugs3();
inline IteratorRange<Module::const_inst_iterator> debugs3() const;
- // Clears all debug instructions (excluding OpLine & OpNoLine).
- inline void debug_clear();
-
// Add |capability| to the module, if it is not already enabled.
inline void AddCapability(SpvCapability capability);
@@ -199,6 +196,7 @@
inline void AddExtension(const std::string& ext_name);
inline void AddExtension(std::unique_ptr<Instruction>&& e);
// Appends an extended instruction set instruction to this module.
+ inline void AddExtInstImport(const std::string& name);
inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
// Set the memory model for this module.
inline void SetMemoryModel(std::unique_ptr<Instruction>&& m);
@@ -542,7 +540,7 @@
return GetFunction(inst->result_id());
}
- // Add to |todo| all ids of functions called in |func|.
+ // Add to |todo| all ids of functions called directly from |func|.
void AddCalls(const Function* func, std::queue<uint32_t>* todo);
// Applies |pfn| to every function in the call trees that are rooted at the
@@ -927,8 +925,6 @@
return ((const Module*)module_.get())->debugs3();
}
-void IRContext::debug_clear() { module_->debug_clear(); }
-
void IRContext::AddCapability(SpvCapability capability) {
if (!get_feature_mgr()->HasCapability(capability)) {
std::unique_ptr<Instruction> capability_inst(new Instruction(
@@ -971,9 +967,26 @@
module()->AddExtension(std::move(e));
}
+void IRContext::AddExtInstImport(const std::string& name) {
+ const auto num_chars = name.size();
+ // Compute num words, accommodate the terminating null character.
+ const auto num_words = (num_chars + 1 + 3) / 4;
+ std::vector<uint32_t> ext_words(num_words, 0u);
+ std::memcpy(ext_words.data(), name.data(), num_chars);
+ AddExtInstImport(std::unique_ptr<Instruction>(
+ new Instruction(this, SpvOpExtInstImport, 0u, TakeNextId(),
+ {{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
+}
+
void IRContext::AddExtInstImport(std::unique_ptr<Instruction>&& e) {
AddCombinatorsForExtension(e.get());
+ if (AreAnalysesValid(kAnalysisDefUse)) {
+ get_def_use_mgr()->AnalyzeInstDefUse(e.get());
+ }
module()->AddExtInstImport(std::move(e));
+ if (feature_mgr_ != nullptr) {
+ feature_mgr_->AddExtInstImportIds(module());
+ }
}
void IRContext::SetMemoryModel(std::unique_ptr<Instruction>&& m) {
diff --git a/source/opt/ir_loader.cpp b/source/opt/ir_loader.cpp
index edd4832..c68b3e2 100644
--- a/source/opt/ir_loader.cpp
+++ b/source/opt/ir_loader.cpp
@@ -159,6 +159,9 @@
for (auto& function : *module_) {
for (auto& bb : function) bb.SetParent(&function);
}
+
+ // Copy any trailing Op*Line instruction into the module
+ module_->SetTrailingDbgLineInfo(std::move(dbg_line_info_));
}
} // namespace opt
diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp
index 6eb130e..1921596 100644
--- a/source/opt/local_access_chain_convert_pass.cpp
+++ b/source/opt/local_access_chain_convert_pass.cpp
@@ -46,6 +46,10 @@
const Instruction* ptrInst, uint32_t* varId, uint32_t* varPteTypeId,
std::vector<std::unique_ptr<Instruction>>* newInsts) {
const uint32_t ldResultId = TakeNextId();
+ if (ldResultId == 0) {
+ return 0;
+ }
+
*varId = ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx);
const Instruction* varInst = get_def_use_mgr()->GetDef(*varId);
assert(varInst->opcode() == SpvOpVariable);
@@ -70,7 +74,7 @@
});
}
-void LocalAccessChainConvertPass::ReplaceAccessChainLoad(
+bool LocalAccessChainConvertPass::ReplaceAccessChainLoad(
const Instruction* address_inst, Instruction* original_load) {
// Build and append load of variable in ptrInst
std::vector<std::unique_ptr<Instruction>> new_inst;
@@ -78,6 +82,10 @@
uint32_t varPteTypeId;
const uint32_t ldResultId =
BuildAndAppendVarLoad(address_inst, &varId, &varPteTypeId, &new_inst);
+ if (ldResultId == 0) {
+ return false;
+ }
+
context()->get_decoration_mgr()->CloneDecorations(
original_load->result_id(), ldResultId, {SpvDecorationRelaxedPrecision});
original_load->InsertBefore(std::move(new_inst));
@@ -95,9 +103,10 @@
original_load->SetOpcode(SpvOpCompositeExtract);
original_load->ReplaceOperands(new_operands);
context()->UpdateDefUse(original_load);
+ return true;
}
-void LocalAccessChainConvertPass::GenAccessChainStoreReplacement(
+bool LocalAccessChainConvertPass::GenAccessChainStoreReplacement(
const Instruction* ptrInst, uint32_t valId,
std::vector<std::unique_ptr<Instruction>>* newInsts) {
// Build and append load of variable in ptrInst
@@ -105,11 +114,18 @@
uint32_t varPteTypeId;
const uint32_t ldResultId =
BuildAndAppendVarLoad(ptrInst, &varId, &varPteTypeId, newInsts);
+ if (ldResultId == 0) {
+ return false;
+ }
+
context()->get_decoration_mgr()->CloneDecorations(
varId, ldResultId, {SpvDecorationRelaxedPrecision});
// Build and append Insert
const uint32_t insResultId = TakeNextId();
+ if (insResultId == 0) {
+ return false;
+ }
std::vector<Operand> ins_in_opnds = {
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {valId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ldResultId}}};
@@ -125,6 +141,7 @@
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {varId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {insResultId}}},
newInsts);
+ return true;
}
bool LocalAccessChainConvertPass::IsConstantIndexAccessChain(
@@ -198,7 +215,8 @@
}
}
-bool LocalAccessChainConvertPass::ConvertLocalAccessChains(Function* func) {
+Pass::Status LocalAccessChainConvertPass::ConvertLocalAccessChains(
+ Function* func) {
FindTargetVars(func);
// Replace access chains of all targeted variables with equivalent
// extract and insert sequences
@@ -213,7 +231,9 @@
if (!IsNonPtrAccessChain(ptrInst->opcode())) break;
if (!IsTargetVar(varId)) break;
std::vector<std::unique_ptr<Instruction>> newInsts;
- ReplaceAccessChainLoad(ptrInst, &*ii);
+ if (!ReplaceAccessChainLoad(ptrInst, &*ii)) {
+ return Status::Failure;
+ }
modified = true;
} break;
case SpvOpStore: {
@@ -223,7 +243,9 @@
if (!IsTargetVar(varId)) break;
std::vector<std::unique_ptr<Instruction>> newInsts;
uint32_t valId = ii->GetSingleWordInOperand(kStoreValIdInIdx);
- GenAccessChainStoreReplacement(ptrInst, valId, &newInsts);
+ if (!GenAccessChainStoreReplacement(ptrInst, valId, &newInsts)) {
+ return Status::Failure;
+ }
dead_instructions.push_back(&*ii);
++ii;
ii = ii.InsertBefore(std::move(newInsts));
@@ -248,7 +270,7 @@
});
}
}
- return modified;
+ return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
}
void LocalAccessChainConvertPass::Initialize() {
@@ -294,12 +316,16 @@
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
- // Process all entry point functions.
- ProcessFunction pfn = [this](Function* fp) {
- return ConvertLocalAccessChains(fp);
- };
- bool modified = context()->ProcessEntryPointCallTree(pfn);
- return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+
+ // Process all functions in the module.
+ Status status = Status::SuccessWithoutChange;
+ for (Function& func : *get_module()) {
+ status = CombineStatus(status, ConvertLocalAccessChains(&func));
+ if (status == Status::Failure) {
+ break;
+ }
+ }
+ return status;
}
LocalAccessChainConvertPass::LocalAccessChainConvertPass() {}
diff --git a/source/opt/local_access_chain_convert_pass.h b/source/opt/local_access_chain_convert_pass.h
index 1c7e3d5..e3592bf 100644
--- a/source/opt/local_access_chain_convert_pass.h
+++ b/source/opt/local_access_chain_convert_pass.h
@@ -82,16 +82,16 @@
// Create a load/insert/store equivalent to a store of
// |valId| through (constant index) access chaing |ptrInst|.
- // Append to |newInsts|.
- void GenAccessChainStoreReplacement(
+ // Append to |newInsts|. Returns true if successful.
+ bool GenAccessChainStoreReplacement(
const Instruction* ptrInst, uint32_t valId,
std::vector<std::unique_ptr<Instruction>>* newInsts);
// For the (constant index) access chain |address_inst|, create an
// equivalent load and extract that replaces |original_load|. The result id
// of the extract will be the same as the original result id of
- // |original_load|.
- void ReplaceAccessChainLoad(const Instruction* address_inst,
+ // |original_load|. Returns true if successful.
+ bool ReplaceAccessChainLoad(const Instruction* address_inst,
Instruction* original_load);
// Return true if all indices of access chain |acp| are OpConstant integers
@@ -106,7 +106,9 @@
//
// Nested access chains and pointer access chains are not currently
// converted.
- bool ConvertLocalAccessChains(Function* func);
+ //
+ // Returns a status to indicate success or failure, and change or no change.
+ Status ConvertLocalAccessChains(Function* func);
// Initialize extensions whitelist
void InitExtensions();
diff --git a/source/opt/local_ssa_elim_pass.cpp b/source/opt/local_ssa_elim_pass.cpp
deleted file mode 100644
index c3f4ab6..0000000
--- a/source/opt/local_ssa_elim_pass.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2017 The Khronos Group Inc.
-// Copyright (c) 2017 Valve Corporation
-// Copyright (c) 2017 LunarG Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "source/opt/local_ssa_elim_pass.h"
-
-#include "source/cfa.h"
-#include "source/opt/iterator.h"
-#include "source/opt/ssa_rewrite_pass.h"
-
-namespace spvtools {
-namespace opt {
-
-bool LocalMultiStoreElimPass::AllExtensionsSupported() const {
- // If any extension not in whitelist, return false
- for (auto& ei : get_module()->extensions()) {
- const char* extName =
- reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
- if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
- return false;
- }
- return true;
-}
-
-Pass::Status LocalMultiStoreElimPass::ProcessImpl() {
- // Assumes relaxed logical addressing only (see instruction.h)
- // TODO(greg-lunarg): Add support for physical addressing
- if (context()->get_feature_mgr()->HasCapability(SpvCapabilityAddresses))
- return Status::SuccessWithoutChange;
- // Do not process if module contains OpGroupDecorate. Additional
- // support required in KillNamesAndDecorates().
- // TODO(greg-lunarg): Add support for OpGroupDecorate
- for (auto& ai : get_module()->annotations())
- if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
- // Do not process if any disallowed extensions are enabled
- if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
- // Process functions
- ProcessFunction pfn = [this](Function* fp) {
- return SSARewriter(this).RewriteFunctionIntoSSA(fp);
- };
- bool modified = context()->ProcessEntryPointCallTree(pfn);
- return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
-}
-
-LocalMultiStoreElimPass::LocalMultiStoreElimPass() = default;
-
-Pass::Status LocalMultiStoreElimPass::Process() {
- // Initialize extension whitelist
- InitExtensions();
- return ProcessImpl();
-}
-
-void LocalMultiStoreElimPass::InitExtensions() {
- extensions_whitelist_.clear();
- extensions_whitelist_.insert({
- "SPV_AMD_shader_explicit_vertex_parameter",
- "SPV_AMD_shader_trinary_minmax",
- "SPV_AMD_gcn_shader",
- "SPV_KHR_shader_ballot",
- "SPV_AMD_shader_ballot",
- "SPV_AMD_gpu_shader_half_float",
- "SPV_KHR_shader_draw_parameters",
- "SPV_KHR_subgroup_vote",
- "SPV_KHR_16bit_storage",
- "SPV_KHR_device_group",
- "SPV_KHR_multiview",
- "SPV_NVX_multiview_per_view_attributes",
- "SPV_NV_viewport_array2",
- "SPV_NV_stereo_view_rendering",
- "SPV_NV_sample_mask_override_coverage",
- "SPV_NV_geometry_shader_passthrough",
- "SPV_AMD_texture_gather_bias_lod",
- "SPV_KHR_storage_buffer_storage_class",
- "SPV_KHR_variable_pointers",
- "SPV_AMD_gpu_shader_int16",
- "SPV_KHR_post_depth_coverage",
- "SPV_KHR_shader_atomic_counter_ops",
- "SPV_EXT_shader_stencil_export",
- "SPV_EXT_shader_viewport_index_layer",
- "SPV_AMD_shader_image_load_store_lod",
- "SPV_AMD_shader_fragment_mask",
- "SPV_EXT_fragment_fully_covered",
- "SPV_AMD_gpu_shader_half_float_fetch",
- "SPV_GOOGLE_decorate_string",
- "SPV_GOOGLE_hlsl_functionality1",
- "SPV_GOOGLE_user_type",
- "SPV_NV_shader_subgroup_partitioned",
- "SPV_EXT_descriptor_indexing",
- "SPV_NV_fragment_shader_barycentric",
- "SPV_NV_compute_shader_derivatives",
- "SPV_NV_shader_image_footprint",
- "SPV_NV_shading_rate",
- "SPV_NV_mesh_shader",
- "SPV_NV_ray_tracing",
- "SPV_EXT_fragment_invocation_density",
- "SPV_EXT_physical_storage_buffer",
- });
-}
-
-} // namespace opt
-} // namespace spvtools
diff --git a/source/opt/local_ssa_elim_pass.h b/source/opt/local_ssa_elim_pass.h
deleted file mode 100644
index de80d5a..0000000
--- a/source/opt/local_ssa_elim_pass.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2017 The Khronos Group Inc.
-// Copyright (c) 2017 Valve Corporation
-// Copyright (c) 2017 LunarG Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SOURCE_OPT_LOCAL_SSA_ELIM_PASS_H_
-#define SOURCE_OPT_LOCAL_SSA_ELIM_PASS_H_
-
-#include <algorithm>
-#include <map>
-#include <queue>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-#include "source/opt/basic_block.h"
-#include "source/opt/def_use_manager.h"
-#include "source/opt/mem_pass.h"
-#include "source/opt/module.h"
-
-namespace spvtools {
-namespace opt {
-
-// See optimizer.hpp for documentation.
-class LocalMultiStoreElimPass : public MemPass {
- using cbb_ptr = const BasicBlock*;
-
- public:
- using GetBlocksFunction =
- std::function<std::vector<BasicBlock*>*(const BasicBlock*)>;
-
- LocalMultiStoreElimPass();
-
- const char* name() const override { return "eliminate-local-multi-store"; }
- Status Process() override;
-
- IRContext::Analysis GetPreservedAnalyses() override {
- return IRContext::kAnalysisDefUse |
- IRContext::kAnalysisInstrToBlockMapping |
- IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
- }
-
- private:
- // Initialize extensions whitelist
- void InitExtensions();
-
- // Return true if all extensions in this module are allowed by this pass.
- bool AllExtensionsSupported() const;
-
- Pass::Status ProcessImpl();
-
- // Extensions supported by this pass.
- std::unordered_set<std::string> extensions_whitelist_;
-};
-
-} // namespace opt
-} // namespace spvtools
-
-#endif // SOURCE_OPT_LOCAL_SSA_ELIM_PASS_H_
diff --git a/source/opt/mem_pass.cpp b/source/opt/mem_pass.cpp
index cc09767..04e2e8a 100644
--- a/source/opt/mem_pass.cpp
+++ b/source/opt/mem_pass.cpp
@@ -233,6 +233,10 @@
const auto uitr = type2undefs_.find(type_id);
if (uitr != type2undefs_.end()) return uitr->second;
const uint32_t undefId = TakeNextId();
+ if (undefId == 0) {
+ return 0;
+ }
+
std::unique_ptr<Instruction> undef_inst(
new Instruction(context(), SpvOpUndef, type_id, undefId, {}));
get_def_use_mgr()->AnalyzeInstDefUse(&*undef_inst);
diff --git a/source/opt/mem_pass.h b/source/opt/mem_pass.h
index 67ce26b..dcc16b6 100644
--- a/source/opt/mem_pass.h
+++ b/source/opt/mem_pass.h
@@ -121,9 +121,10 @@
return (op == SpvOpDecorate || op == SpvOpDecorateId);
}
- // Return undef in function for type. Create and insert an undef after the
- // first non-variable in the function if it doesn't already exist. Add
- // undef to function undef map.
+ // Return the id of an undef value with type |type_id|. Create and insert an
+ // undef after the first non-variable in the function if it doesn't already
+ // exist. Add undef to function undef map. Returns 0 of the value does not
+ // exist, and cannot be created.
uint32_t Type2Undef(uint32_t type_id);
// Cache of verified target vars
diff --git a/source/opt/module.cpp b/source/opt/module.cpp
index 04e4e97..c7fc247 100644
--- a/source/opt/module.cpp
+++ b/source/opt/module.cpp
@@ -121,6 +121,9 @@
static_cast<const Function*>(i.get())->ForEachInst(f,
run_on_debug_line_insts);
}
+ if (run_on_debug_line_insts) {
+ for (auto& i : trailing_dbg_line_info_) DELEGATE(i);
+ }
#undef DELEGATE
}
diff --git a/source/opt/module.h b/source/opt/module.h
index cf7c274..aefa2a5 100644
--- a/source/opt/module.h
+++ b/source/opt/module.h
@@ -192,22 +192,6 @@
inline IteratorRange<inst_iterator> execution_modes();
inline IteratorRange<const_inst_iterator> execution_modes() const;
- // Clears all debug instructions (excluding OpLine & OpNoLine).
- void debug_clear() {
- debug1_clear();
- debug2_clear();
- debug3_clear();
- }
-
- // Clears all debug 1 instructions (excluding OpLine & OpNoLine).
- void debug1_clear() { debugs1_.clear(); }
-
- // Clears all debug 2 instructions (excluding OpLine & OpNoLine).
- void debug2_clear() { debugs2_.clear(); }
-
- // Clears all debug 3 instructions (excluding OpLine & OpNoLine).
- void debug3_clear() { debugs3_.clear(); }
-
// Iterators for annotation instructions contained in this module.
inline inst_iterator annotation_begin();
inline inst_iterator annotation_end();
@@ -261,6 +245,19 @@
// Gets the associated context for this module
IRContext* context() const { return context_; }
+ // Sets the trailing debug line info to |dbg_line_info|.
+ void SetTrailingDbgLineInfo(std::vector<Instruction>&& dbg_line_info) {
+ trailing_dbg_line_info_ = std::move(dbg_line_info);
+ }
+
+ std::vector<Instruction>& trailing_dbg_line_info() {
+ return trailing_dbg_line_info_;
+ }
+
+ const std::vector<Instruction>& trailing_dbg_line_info() const {
+ return trailing_dbg_line_info_;
+ }
+
private:
ModuleHeader header_; // Module header
@@ -281,6 +278,10 @@
// Type declarations, constants, and global variable declarations.
InstructionList types_values_;
std::vector<std::unique_ptr<Function>> functions_;
+
+ // If the module ends with Op*Line instruction, they will not be attached to
+ // any instruction. We record them here, so they will not be lost.
+ std::vector<Instruction> trailing_dbg_line_info_;
};
// Pretty-prints |module| to |str|. Returns |str|.
diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp
index 635b075..ece1abe 100644
--- a/source/opt/optimizer.cpp
+++ b/source/opt/optimizer.cpp
@@ -21,12 +21,12 @@
#include <utility>
#include <vector>
-#include <source/spirv_optimizer_options.h>
#include "source/opt/build_module.h"
#include "source/opt/graphics_robust_access_pass.h"
#include "source/opt/log.h"
#include "source/opt/pass_manager.h"
#include "source/opt/passes.h"
+#include "source/spirv_optimizer_options.h"
#include "source/util/make_unique.h"
#include "source/util/string_utils.h"
@@ -415,6 +415,10 @@
} else if (pass_name == "inst-buff-addr-check") {
RegisterPass(CreateInstBuffAddrCheckPass(7, 23, 2));
RegisterPass(CreateAggressiveDCEPass());
+ } else if (pass_name == "convert-relaxed-to-half") {
+ RegisterPass(CreateConvertRelaxedToHalfPass());
+ } else if (pass_name == "relax-float-ops") {
+ RegisterPass(CreateRelaxFloatOpsPass());
} else if (pass_name == "simplify-instructions") {
RegisterPass(CreateSimplificationPass());
} else if (pass_name == "ssa-rewrite") {
@@ -556,20 +560,26 @@
return false;
}
- optimized_binary->clear();
- context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
-
#ifndef NDEBUG
if (status == opt::Pass::Status::SuccessWithoutChange) {
- auto changed = optimized_binary->size() != original_binary_size ||
- memcmp(optimized_binary->data(), original_binary,
- original_binary_size) != 0;
- assert(!changed &&
- "Binary unexpectedly changed despite optimizer saying there was no "
- "change");
+ std::vector<uint32_t> optimized_binary_with_nop;
+ context->module()->ToBinary(&optimized_binary_with_nop,
+ /* skip_nop = */ false);
+ assert(optimized_binary_with_nop.size() == original_binary_size &&
+ "Binary size unexpectedly changed despite the optimizer saying "
+ "there was no change");
+ assert(memcmp(optimized_binary_with_nop.data(), original_binary,
+ original_binary_size) == 0 &&
+ "Binary content unexpectedly changed despite the optimizer saying "
+ "there was no change");
}
#endif // !NDEBUG
+ // Note that |original_binary| and |optimized_binary| may share the same
+ // buffer and the below will invalidate |original_binary|.
+ optimized_binary->clear();
+ context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
+
return true;
}
@@ -711,7 +721,7 @@
Optimizer::PassToken CreateLocalMultiStoreElimPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
- MakeUnique<opt::LocalMultiStoreElimPass>());
+ MakeUnique<opt::SSARewritePass>());
}
Optimizer::PassToken CreateAggressiveDCEPass() {
@@ -877,6 +887,16 @@
MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id, version));
}
+Optimizer::PassToken CreateConvertRelaxedToHalfPass() {
+ return MakeUnique<Optimizer::PassToken::Impl>(
+ MakeUnique<opt::ConvertToHalfPass>());
+}
+
+Optimizer::PassToken CreateRelaxFloatOpsPass() {
+ return MakeUnique<Optimizer::PassToken::Impl>(
+ MakeUnique<opt::RelaxFloatOpsPass>());
+}
+
Optimizer::PassToken CreateCodeSinkingPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::CodeSinkingPass>());
diff --git a/source/opt/pass.cpp b/source/opt/pass.cpp
index f9e4a5d..09b78af 100644
--- a/source/opt/pass.cpp
+++ b/source/opt/pass.cpp
@@ -54,6 +54,36 @@
return ptrTypeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx);
}
+Instruction* Pass::GetBaseType(uint32_t ty_id) {
+ Instruction* ty_inst = get_def_use_mgr()->GetDef(ty_id);
+ if (ty_inst->opcode() == SpvOpTypeMatrix) {
+ uint32_t vty_id = ty_inst->GetSingleWordInOperand(0);
+ ty_inst = get_def_use_mgr()->GetDef(vty_id);
+ }
+ if (ty_inst->opcode() == SpvOpTypeVector) {
+ uint32_t cty_id = ty_inst->GetSingleWordInOperand(0);
+ ty_inst = get_def_use_mgr()->GetDef(cty_id);
+ }
+ return ty_inst;
+}
+
+bool Pass::IsFloat(uint32_t ty_id, uint32_t width) {
+ Instruction* ty_inst = GetBaseType(ty_id);
+ if (ty_inst->opcode() != SpvOpTypeFloat) return false;
+ return ty_inst->GetSingleWordInOperand(0) == width;
+}
+
+uint32_t Pass::GetNullId(uint32_t type_id) {
+ if (IsFloat(type_id, 16)) context()->AddCapability(SpvCapabilityFloat16);
+ analysis::TypeManager* type_mgr = context()->get_type_mgr();
+ analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
+ const analysis::Type* type = type_mgr->GetType(type_id);
+ const analysis::Constant* null_const = const_mgr->GetConstant(type, {});
+ Instruction* null_inst =
+ const_mgr->GetDefiningInstruction(null_const, type_id);
+ return null_inst->result_id();
+}
+
uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id,
Instruction* insertion_position) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
diff --git a/source/opt/pass.h b/source/opt/pass.h
index 686e9fc..a8c9c4b 100644
--- a/source/opt/pass.h
+++ b/source/opt/pass.h
@@ -109,6 +109,16 @@
// Return type id for |ptrInst|'s pointee
uint32_t GetPointeeTypeId(const Instruction* ptrInst) const;
+ // Return base type of |ty_id| type
+ Instruction* GetBaseType(uint32_t ty_id);
+
+ // Return true if |inst| returns scalar, vector or matrix type with base
+ // float and |width|
+ bool IsFloat(uint32_t ty_id, uint32_t width);
+
+ // Return the id of OpConstantNull of type |type_id|. Create if necessary.
+ uint32_t GetNullId(uint32_t type_id);
+
protected:
// Constructs a new pass.
//
diff --git a/source/opt/passes.h b/source/opt/passes.h
index d53af8f..1a3675c 100644
--- a/source/opt/passes.h
+++ b/source/opt/passes.h
@@ -25,6 +25,7 @@
#include "source/opt/code_sink.h"
#include "source/opt/combine_access_chains.h"
#include "source/opt/compact_ids_pass.h"
+#include "source/opt/convert_to_half_pass.h"
#include "source/opt/copy_prop_arrays.h"
#include "source/opt/dead_branch_elim_pass.h"
#include "source/opt/dead_insert_elim_pass.h"
@@ -51,7 +52,6 @@
#include "source/opt/local_redundancy_elimination.h"
#include "source/opt/local_single_block_elim_pass.h"
#include "source/opt/local_single_store_elim_pass.h"
-#include "source/opt/local_ssa_elim_pass.h"
#include "source/opt/loop_fission.h"
#include "source/opt/loop_fusion_pass.h"
#include "source/opt/loop_peeling.h"
@@ -63,6 +63,7 @@
#include "source/opt/process_lines_pass.h"
#include "source/opt/reduce_load_size.h"
#include "source/opt/redundancy_elimination.h"
+#include "source/opt/relax_float_ops_pass.h"
#include "source/opt/remove_duplicates_pass.h"
#include "source/opt/replace_invalid_opc.h"
#include "source/opt/scalar_replacement_pass.h"
diff --git a/source/opt/relax_float_ops_pass.cpp b/source/opt/relax_float_ops_pass.cpp
new file mode 100644
index 0000000..73f16dd
--- /dev/null
+++ b/source/opt/relax_float_ops_pass.cpp
@@ -0,0 +1,178 @@
+// Copyright (c) 2019 The Khronos Group Inc.
+// Copyright (c) 2019 Valve Corporation
+// Copyright (c) 2019 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "relax_float_ops_pass.h"
+
+#include "source/opt/ir_builder.h"
+
+namespace spvtools {
+namespace opt {
+
+bool RelaxFloatOpsPass::IsRelaxable(Instruction* inst) {
+ return target_ops_core_f_rslt_.count(inst->opcode()) != 0 ||
+ target_ops_core_f_opnd_.count(inst->opcode()) != 0 ||
+ sample_ops_.count(inst->opcode()) != 0 ||
+ (inst->opcode() == SpvOpExtInst &&
+ inst->GetSingleWordInOperand(0) ==
+ context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
+ target_ops_450_.count(inst->GetSingleWordInOperand(1)) != 0);
+}
+
+bool RelaxFloatOpsPass::IsFloat32(Instruction* inst) {
+ uint32_t ty_id;
+ if (target_ops_core_f_opnd_.count(inst->opcode()) != 0) {
+ uint32_t opnd_id = inst->GetSingleWordInOperand(0);
+ Instruction* opnd_inst = get_def_use_mgr()->GetDef(opnd_id);
+ ty_id = opnd_inst->type_id();
+ } else {
+ ty_id = inst->type_id();
+ if (ty_id == 0) return false;
+ }
+ return IsFloat(ty_id, 32);
+}
+
+bool RelaxFloatOpsPass::IsRelaxed(uint32_t r_id) {
+ for (auto r_inst : get_decoration_mgr()->GetDecorationsFor(r_id, false))
+ if (r_inst->opcode() == SpvOpDecorate &&
+ r_inst->GetSingleWordInOperand(1) == SpvDecorationRelaxedPrecision)
+ return true;
+ return false;
+}
+
+bool RelaxFloatOpsPass::ProcessInst(Instruction* r_inst) {
+ uint32_t r_id = r_inst->result_id();
+ if (r_id == 0) return false;
+ if (!IsFloat32(r_inst)) return false;
+ if (IsRelaxed(r_id)) return false;
+ if (!IsRelaxable(r_inst)) return false;
+ get_decoration_mgr()->AddDecoration(r_id, SpvDecorationRelaxedPrecision);
+ return true;
+}
+
+bool RelaxFloatOpsPass::ProcessFunction(Function* func) {
+ bool modified = false;
+ cfg()->ForEachBlockInReversePostOrder(
+ func->entry().get(), [&modified, this](BasicBlock* bb) {
+ for (auto ii = bb->begin(); ii != bb->end(); ++ii)
+ modified |= ProcessInst(&*ii);
+ });
+ return modified;
+}
+
+Pass::Status RelaxFloatOpsPass::ProcessImpl() {
+ Pass::ProcessFunction pfn = [this](Function* fp) {
+ return ProcessFunction(fp);
+ };
+ bool modified = context()->ProcessEntryPointCallTree(pfn);
+ return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+}
+
+Pass::Status RelaxFloatOpsPass::Process() {
+ Initialize();
+ return ProcessImpl();
+}
+
+void RelaxFloatOpsPass::Initialize() {
+ target_ops_core_f_rslt_ = {
+ SpvOpLoad,
+ SpvOpPhi,
+ SpvOpVectorExtractDynamic,
+ SpvOpVectorInsertDynamic,
+ SpvOpVectorShuffle,
+ SpvOpCompositeExtract,
+ SpvOpCompositeConstruct,
+ SpvOpCompositeInsert,
+ SpvOpCopyObject,
+ SpvOpTranspose,
+ SpvOpConvertSToF,
+ SpvOpConvertUToF,
+ SpvOpFConvert,
+ // SpvOpQuantizeToF16,
+ SpvOpFNegate,
+ SpvOpFAdd,
+ SpvOpFSub,
+ SpvOpFMul,
+ SpvOpFDiv,
+ SpvOpFMod,
+ SpvOpVectorTimesScalar,
+ SpvOpMatrixTimesScalar,
+ SpvOpVectorTimesMatrix,
+ SpvOpMatrixTimesVector,
+ SpvOpMatrixTimesMatrix,
+ SpvOpOuterProduct,
+ SpvOpDot,
+ SpvOpSelect,
+ };
+ target_ops_core_f_opnd_ = {
+ SpvOpFOrdEqual,
+ SpvOpFUnordEqual,
+ SpvOpFOrdNotEqual,
+ SpvOpFUnordNotEqual,
+ SpvOpFOrdLessThan,
+ SpvOpFUnordLessThan,
+ SpvOpFOrdGreaterThan,
+ SpvOpFUnordGreaterThan,
+ SpvOpFOrdLessThanEqual,
+ SpvOpFUnordLessThanEqual,
+ SpvOpFOrdGreaterThanEqual,
+ SpvOpFUnordGreaterThanEqual,
+ };
+ target_ops_450_ = {
+ GLSLstd450Round, GLSLstd450RoundEven, GLSLstd450Trunc, GLSLstd450FAbs,
+ GLSLstd450FSign, GLSLstd450Floor, GLSLstd450Ceil, GLSLstd450Fract,
+ GLSLstd450Radians, GLSLstd450Degrees, GLSLstd450Sin, GLSLstd450Cos,
+ GLSLstd450Tan, GLSLstd450Asin, GLSLstd450Acos, GLSLstd450Atan,
+ GLSLstd450Sinh, GLSLstd450Cosh, GLSLstd450Tanh, GLSLstd450Asinh,
+ GLSLstd450Acosh, GLSLstd450Atanh, GLSLstd450Atan2, GLSLstd450Pow,
+ GLSLstd450Exp, GLSLstd450Log, GLSLstd450Exp2, GLSLstd450Log2,
+ GLSLstd450Sqrt, GLSLstd450InverseSqrt, GLSLstd450Determinant,
+ GLSLstd450MatrixInverse,
+ // TODO(greg-lunarg): GLSLstd450ModfStruct,
+ GLSLstd450FMin, GLSLstd450FMax, GLSLstd450FClamp, GLSLstd450FMix,
+ GLSLstd450Step, GLSLstd450SmoothStep, GLSLstd450Fma,
+ // TODO(greg-lunarg): GLSLstd450FrexpStruct,
+ GLSLstd450Ldexp, GLSLstd450Length, GLSLstd450Distance, GLSLstd450Cross,
+ GLSLstd450Normalize, GLSLstd450FaceForward, GLSLstd450Reflect,
+ GLSLstd450Refract, GLSLstd450NMin, GLSLstd450NMax, GLSLstd450NClamp};
+ sample_ops_ = {SpvOpImageSampleImplicitLod,
+ SpvOpImageSampleExplicitLod,
+ SpvOpImageSampleDrefImplicitLod,
+ SpvOpImageSampleDrefExplicitLod,
+ SpvOpImageSampleProjImplicitLod,
+ SpvOpImageSampleProjExplicitLod,
+ SpvOpImageSampleProjDrefImplicitLod,
+ SpvOpImageSampleProjDrefExplicitLod,
+ SpvOpImageFetch,
+ SpvOpImageGather,
+ SpvOpImageDrefGather,
+ SpvOpImageRead,
+ SpvOpImageSparseSampleImplicitLod,
+ SpvOpImageSparseSampleExplicitLod,
+ SpvOpImageSparseSampleDrefImplicitLod,
+ SpvOpImageSparseSampleDrefExplicitLod,
+ SpvOpImageSparseSampleProjImplicitLod,
+ SpvOpImageSparseSampleProjExplicitLod,
+ SpvOpImageSparseSampleProjDrefImplicitLod,
+ SpvOpImageSparseSampleProjDrefExplicitLod,
+ SpvOpImageSparseFetch,
+ SpvOpImageSparseGather,
+ SpvOpImageSparseDrefGather,
+ SpvOpImageSparseTexelsResident,
+ SpvOpImageSparseRead};
+}
+
+} // namespace opt
+} // namespace spvtools
diff --git a/source/opt/relax_float_ops_pass.h b/source/opt/relax_float_ops_pass.h
new file mode 100644
index 0000000..5ee3d73
--- /dev/null
+++ b/source/opt/relax_float_ops_pass.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2019 Valve Corporation
+// Copyright (c) 2019 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef LIBSPIRV_OPT_RELAX_FLOAT_OPS_PASS_H_
+#define LIBSPIRV_OPT_RELAX_FLOAT_OPS_PASS_H_
+
+#include "source/opt/ir_builder.h"
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+class RelaxFloatOpsPass : public Pass {
+ public:
+ RelaxFloatOpsPass() : Pass() {}
+
+ ~RelaxFloatOpsPass() override = default;
+
+ IRContext::Analysis GetPreservedAnalyses() override {
+ return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping;
+ }
+
+ // See optimizer.hpp for pass user documentation.
+ Status Process() override;
+
+ const char* name() const override { return "convert-to-half-pass"; }
+
+ private:
+ // Return true if |inst| can have the RelaxedPrecision decoration applied
+ // to it.
+ bool IsRelaxable(Instruction* inst);
+
+ // Return true if |inst| returns scalar, vector or matrix type with base
+ // float and width 32
+ bool IsFloat32(Instruction* inst);
+
+ // Return true if |r_id| is decorated with RelaxedPrecision
+ bool IsRelaxed(uint32_t r_id);
+
+ // If |inst| is an instruction of float32-based type and is not decorated
+ // RelaxedPrecision, add such a decoration to the module.
+ bool ProcessInst(Instruction* inst);
+
+ // Call ProcessInst on every instruction in |func|.
+ bool ProcessFunction(Function* func);
+
+ Pass::Status ProcessImpl();
+
+ // Initialize state for converting to half
+ void Initialize();
+
+ // Set of float result core operations to be processed
+ std::unordered_set<uint32_t> target_ops_core_f_rslt_;
+
+ // Set of float operand core operations to be processed
+ std::unordered_set<uint32_t> target_ops_core_f_opnd_;
+
+ // Set of 450 extension operations to be processed
+ std::unordered_set<uint32_t> target_ops_450_;
+
+ // Set of sample operations
+ std::unordered_set<uint32_t> sample_ops_;
+};
+
+} // namespace opt
+} // namespace spvtools
+
+#endif // LIBSPIRV_OPT_RELAX_FLOAT_OPS_PASS_H_
diff --git a/source/opt/scalar_replacement_pass.cpp b/source/opt/scalar_replacement_pass.cpp
index d748e7f..36c0c0d 100644
--- a/source/opt/scalar_replacement_pass.cpp
+++ b/source/opt/scalar_replacement_pass.cpp
@@ -820,7 +820,8 @@
// Look for extract from the load.
std::vector<uint32_t> t;
if (def_use_mgr->WhileEachUser(use, [&t](Instruction* use2) {
- if (use2->opcode() != SpvOpCompositeExtract) {
+ if (use2->opcode() != SpvOpCompositeExtract ||
+ use2->NumInOperands() <= 1) {
return false;
}
t.push_back(use2->GetSingleWordInOperand(1));
diff --git a/source/opt/simplification_pass.cpp b/source/opt/simplification_pass.cpp
index 7b0887c..001f354 100644
--- a/source/opt/simplification_pass.cpp
+++ b/source/opt/simplification_pass.cpp
@@ -32,6 +32,18 @@
return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
}
+void SimplificationPass::AddNewOperands(
+ Instruction* folded_inst, std::unordered_set<Instruction*>* inst_seen,
+ std::vector<Instruction*>* work_list) {
+ analysis::DefUseManager* def_use_mgr = get_def_use_mgr();
+ folded_inst->ForEachInId(
+ [&inst_seen, &def_use_mgr, &work_list](uint32_t* iid) {
+ Instruction* iid_inst = def_use_mgr->GetDef(*iid);
+ if (!inst_seen->insert(iid_inst).second) return;
+ work_list->push_back(iid_inst);
+ });
+}
+
bool SimplificationPass::SimplifyFunction(Function* function) {
bool modified = false;
// Phase 1: Traverse all instructions in dominance order.
@@ -44,13 +56,15 @@
std::unordered_set<Instruction*> process_phis;
std::unordered_set<Instruction*> inst_to_kill;
std::unordered_set<Instruction*> in_work_list;
+ std::unordered_set<Instruction*> inst_seen;
const InstructionFolder& folder = context()->get_instruction_folder();
cfg()->ForEachBlockInReversePostOrder(
function->entry().get(),
[&modified, &process_phis, &work_list, &in_work_list, &inst_to_kill,
- &folder, this](BasicBlock* bb) {
+ &folder, &inst_seen, this](BasicBlock* bb) {
for (Instruction* inst = &*bb->begin(); inst; inst = inst->NextNode()) {
+ inst_seen.insert(inst);
if (inst->opcode() == SpvOpPhi) {
process_phis.insert(inst);
}
@@ -70,6 +84,9 @@
work_list.push_back(use);
}
});
+
+ AddNewOperands(inst, &inst_seen, &work_list);
+
if (inst->opcode() == SpvOpCopyObject) {
context()->ReplaceAllUsesWithPredicate(
inst->result_id(), inst->GetSingleWordInOperand(0),
@@ -97,6 +114,7 @@
for (size_t i = 0; i < work_list.size(); ++i) {
Instruction* inst = work_list[i];
in_work_list.erase(inst);
+ inst_seen.insert(inst);
bool is_foldable_copy =
inst->opcode() == SpvOpCopyObject &&
@@ -114,6 +132,8 @@
}
});
+ AddNewOperands(inst, &inst_seen, &work_list);
+
if (inst->opcode() == SpvOpCopyObject) {
context()->ReplaceAllUsesWithPredicate(
inst->result_id(), inst->GetSingleWordInOperand(0),
diff --git a/source/opt/simplification_pass.h b/source/opt/simplification_pass.h
index bcb88bf..149874b 100644
--- a/source/opt/simplification_pass.h
+++ b/source/opt/simplification_pass.h
@@ -42,6 +42,14 @@
// instruction in |function| until nothing else in the function can be
// simplified.
bool SimplifyFunction(Function* function);
+
+ // FactorAddMul can create |folded_inst| Mul of new Add. If Mul, push any Add
+ // operand not in |seen_inst| into |worklist|. This is heavily restricted to
+ // improve compile time but can be expanded for future simplifications which
+ // simiarly create new operations.
+ void AddNewOperands(Instruction* folded_inst,
+ std::unordered_set<Instruction*>* inst_seen,
+ std::vector<Instruction*>* work_list);
};
} // namespace opt
diff --git a/source/opt/ssa_rewrite_pass.cpp b/source/opt/ssa_rewrite_pass.cpp
index 7144ca0..69c3a1f 100644
--- a/source/opt/ssa_rewrite_pass.cpp
+++ b/source/opt/ssa_rewrite_pass.cpp
@@ -274,6 +274,9 @@
// of the CFG, the variable is not defined, so we use undef.
if (val_id == 0) {
val_id = pass_->GetUndefVal(var_id);
+ if (val_id == 0) {
+ return 0;
+ }
}
WriteVariable(var_id, bb, val_id);
@@ -313,12 +316,15 @@
}
}
-void SSARewriter::ProcessLoad(Instruction* inst, BasicBlock* bb) {
+bool SSARewriter::ProcessLoad(Instruction* inst, BasicBlock* bb) {
uint32_t var_id = 0;
(void)pass_->GetPtr(inst, &var_id);
if (pass_->IsTargetVar(var_id)) {
// Get the immediate reaching definition for |var_id|.
uint32_t val_id = GetReachingDef(var_id, bb);
+ if (val_id == 0) {
+ return false;
+ }
// Schedule a replacement for the result of this load instruction with
// |val_id|. After all the rewriting decisions are made, every use of
@@ -337,6 +343,7 @@
<< " (replacement for %" << load_id << " is %" << val_id << ")\n";
#endif
}
+ return true;
}
void SSARewriter::PrintPhiCandidates() const {
@@ -356,7 +363,7 @@
std::cerr << "\n";
}
-void SSARewriter::GenerateSSAReplacements(BasicBlock* bb) {
+bool SSARewriter::GenerateSSAReplacements(BasicBlock* bb) {
#if SSA_REWRITE_DEBUGGING_LEVEL > 1
std::cerr << "Generating SSA replacements for block: " << bb->id() << "\n";
std::cerr << bb->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES)
@@ -368,7 +375,9 @@
if (opcode == SpvOpStore || opcode == SpvOpVariable) {
ProcessStore(&inst, bb);
} else if (inst.opcode() == SpvOpLoad) {
- ProcessLoad(&inst, bb);
+ if (!ProcessLoad(&inst, bb)) {
+ return false;
+ }
}
}
@@ -381,6 +390,7 @@
PrintReplacementTable();
std::cerr << "\n\n";
#endif
+ return true;
}
uint32_t SSARewriter::GetReplacement(std::pair<uint32_t, uint32_t> repl) {
@@ -560,7 +570,7 @@
}
}
-bool SSARewriter::RewriteFunctionIntoSSA(Function* fp) {
+Pass::Status SSARewriter::RewriteFunctionIntoSSA(Function* fp) {
#if SSA_REWRITE_DEBUGGING_LEVEL > 0
std::cerr << "Function before SSA rewrite:\n"
<< fp->PrettyPrint(0) << "\n\n\n";
@@ -571,9 +581,17 @@
// Generate all the SSA replacements and Phi candidates. This will
// generate incomplete and trivial Phis.
- pass_->cfg()->ForEachBlockInReversePostOrder(
- fp->entry().get(),
- [this](BasicBlock* bb) { GenerateSSAReplacements(bb); });
+ bool succeeded = pass_->cfg()->WhileEachBlockInReversePostOrder(
+ fp->entry().get(), [this](BasicBlock* bb) {
+ if (!GenerateSSAReplacements(bb)) {
+ return false;
+ }
+ return true;
+ });
+
+ if (!succeeded) {
+ return Pass::Status::Failure;
+ }
// Remove trivial Phis and add arguments to incomplete Phis.
FinalizePhiCandidates();
@@ -586,16 +604,20 @@
<< fp->PrettyPrint(0) << "\n";
#endif
- return modified;
+ return modified ? Pass::Status::SuccessWithChange
+ : Pass::Status::SuccessWithoutChange;
}
Pass::Status SSARewritePass::Process() {
- bool modified = false;
+ Status status = Status::SuccessWithoutChange;
for (auto& fn : *get_module()) {
- modified |= SSARewriter(this).RewriteFunctionIntoSSA(&fn);
+ status =
+ CombineStatus(status, SSARewriter(this).RewriteFunctionIntoSSA(&fn));
+ if (status == Status::Failure) {
+ break;
+ }
}
- return modified ? Pass::Status::SuccessWithChange
- : Pass::Status::SuccessWithoutChange;
+ return status;
}
} // namespace opt
diff --git a/source/opt/ssa_rewrite_pass.h b/source/opt/ssa_rewrite_pass.h
index fddbdaf..bbe89c8 100644
--- a/source/opt/ssa_rewrite_pass.h
+++ b/source/opt/ssa_rewrite_pass.h
@@ -46,9 +46,9 @@
// entry point for the SSA rewrite algorithm. SSA-target variables are
// locally defined variables that meet the criteria set by IsSSATargetVar.
//
- // It returns true if function |fp| was modified. Otherwise, it returns
- // false.
- bool RewriteFunctionIntoSSA(Function* fp);
+ // Returns whether the function was modified or not, and whether or not the
+ // rewrite was successful.
+ Pass::Status RewriteFunctionIntoSSA(Function* fp);
private:
class PhiCandidate {
@@ -128,8 +128,8 @@
// Generates all the SSA rewriting decisions for basic block |bb|. This
// populates the Phi candidate table (|phi_candidate_|) and the load
- // replacement table (|load_replacement_).
- void GenerateSSAReplacements(BasicBlock* bb);
+ // replacement table (|load_replacement_). Returns true if successful.
+ bool GenerateSSAReplacements(BasicBlock* bb);
// Seals block |bb|. Sealing a basic block means |bb| and all its
// predecessors of |bb| have been scanned for loads/stores.
@@ -202,8 +202,8 @@
// Processes the load operation |inst| in basic block |bb|. This extracts
// the variable ID being stored into, determines whether the variable is an
// SSA-target variable, and, if it is, it reads its reaching definition by
- // calling |GetReachingDef|.
- void ProcessLoad(Instruction* inst, BasicBlock* bb);
+ // calling |GetReachingDef|. Returns true if successful.
+ bool ProcessLoad(Instruction* inst, BasicBlock* bb);
// Reads the current definition for variable |var_id| in basic block |bb|.
// If |var_id| is not defined in block |bb| it walks up the predecessors of
diff --git a/source/opt/strip_debug_info_pass.cpp b/source/opt/strip_debug_info_pass.cpp
index 5d9c5fe..9e7fad0 100644
--- a/source/opt/strip_debug_info_pass.cpp
+++ b/source/opt/strip_debug_info_pass.cpp
@@ -22,13 +22,34 @@
bool modified = !context()->debugs1().empty() ||
!context()->debugs2().empty() ||
!context()->debugs3().empty();
- context()->debug_clear();
+
+ std::vector<Instruction*> to_kill;
+ for (auto& dbg : context()->debugs1()) to_kill.push_back(&dbg);
+ for (auto& dbg : context()->debugs2()) to_kill.push_back(&dbg);
+ for (auto& dbg : context()->debugs3()) to_kill.push_back(&dbg);
+
+ // OpName must come first, since they may refer to other debug instructions.
+ // If they are after the instructions that refer to, then they will be killed
+ // when that instruction is killed, which will lead to a double kill.
+ std::sort(to_kill.begin(), to_kill.end(),
+ [](Instruction* lhs, Instruction* rhs) -> bool {
+ if (lhs->opcode() == SpvOpName && rhs->opcode() != SpvOpName)
+ return true;
+ return false;
+ });
+
+ for (auto* inst : to_kill) context()->KillInst(inst);
context()->module()->ForEachInst([&modified](Instruction* inst) {
modified |= !inst->dbg_line_insts().empty();
inst->dbg_line_insts().clear();
});
+ if (!get_module()->trailing_dbg_line_info().empty()) {
+ modified = true;
+ get_module()->trailing_dbg_line_info().clear();
+ }
+
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
diff --git a/source/opt/struct_cfg_analysis.cpp b/source/opt/struct_cfg_analysis.cpp
index 152ded5..b16322c 100644
--- a/source/opt/struct_cfg_analysis.cpp
+++ b/source/opt/struct_cfg_analysis.cpp
@@ -45,6 +45,7 @@
struct TraversalInfo {
ConstructInfo cinfo;
uint32_t merge_node;
+ uint32_t continue_node;
};
// Set up a stack to keep track of currently active constructs.
@@ -53,7 +54,9 @@
state[0].cinfo.containing_construct = 0;
state[0].cinfo.containing_loop = 0;
state[0].cinfo.containing_switch = 0;
+ state[0].cinfo.in_continue = false;
state[0].merge_node = 0;
+ state[0].continue_node = 0;
for (BasicBlock* block : order) {
if (context_->cfg()->IsPseudoEntryBlock(block) ||
@@ -65,6 +68,12 @@
state.pop_back();
}
+ // This works because the structured order is designed to keep the blocks in
+ // the continue construct between the continue header and the merge node.
+ if (block->id() == state.back().continue_node) {
+ state.back().cinfo.in_continue = true;
+ }
+
bb_to_construct_.emplace(std::make_pair(block->id(), state.back().cinfo));
if (Instruction* merge_inst = block->GetMergeInst()) {
@@ -76,8 +85,14 @@
if (merge_inst->opcode() == SpvOpLoopMerge) {
new_state.cinfo.containing_loop = block->id();
new_state.cinfo.containing_switch = 0;
+ new_state.cinfo.in_continue = false;
+ new_state.continue_node =
+ merge_inst->GetSingleWordInOperand(kContinueNodeIndex);
} else {
new_state.cinfo.containing_loop = state.back().cinfo.containing_loop;
+ new_state.cinfo.in_continue = state.back().cinfo.in_continue;
+ new_state.continue_node = state.back().continue_node;
+
if (merge_inst->NextNode()->opcode() == SpvOpSwitch) {
new_state.cinfo.containing_switch = block->id();
} else {
@@ -146,9 +161,59 @@
return LoopContinueBlock(bb_id) == bb_id;
}
+bool StructuredCFGAnalysis::IsInContainingLoopsContinueConstruct(
+ uint32_t bb_id) {
+ auto it = bb_to_construct_.find(bb_id);
+ if (it == bb_to_construct_.end()) {
+ return false;
+ }
+ return it->second.in_continue;
+}
+
+bool StructuredCFGAnalysis::IsInContinueConstruct(uint32_t bb_id) {
+ while (bb_id != 0) {
+ if (IsInContainingLoopsContinueConstruct(bb_id)) {
+ return true;
+ }
+ bb_id = ContainingLoop(bb_id);
+ }
+ return false;
+}
+
bool StructuredCFGAnalysis::IsMergeBlock(uint32_t bb_id) {
return merge_blocks_.Get(bb_id);
}
+std::unordered_set<uint32_t>
+StructuredCFGAnalysis::FindFuncsCalledFromContinue() {
+ std::unordered_set<uint32_t> called_from_continue;
+ std::queue<uint32_t> funcs_to_process;
+
+ // First collect the functions that are called directly from a continue
+ // construct.
+ for (Function& func : *context_->module()) {
+ for (auto& bb : func) {
+ if (IsInContainingLoopsContinueConstruct(bb.id())) {
+ for (const Instruction& inst : bb) {
+ if (inst.opcode() == SpvOpFunctionCall) {
+ funcs_to_process.push(inst.GetSingleWordInOperand(0));
+ }
+ }
+ }
+ }
+ }
+
+ // Now collect all of the functions that are indirectly called as well.
+ while (!funcs_to_process.empty()) {
+ uint32_t func_id = funcs_to_process.front();
+ funcs_to_process.pop();
+ Function* func = context_->GetFunction(func_id);
+ if (called_from_continue.insert(func_id).second) {
+ context_->AddCalls(func, &funcs_to_process);
+ }
+ }
+ return called_from_continue;
+}
+
} // namespace opt
} // namespace spvtools
diff --git a/source/opt/struct_cfg_analysis.h b/source/opt/struct_cfg_analysis.h
index f25266a..dfae6d4 100644
--- a/source/opt/struct_cfg_analysis.h
+++ b/source/opt/struct_cfg_analysis.h
@@ -16,6 +16,7 @@
#define SOURCE_OPT_STRUCT_CFG_ANALYSIS_H_
#include <unordered_map>
+#include <unordered_set>
#include "source/opt/function.h"
#include "source/util/bit_vector.h"
@@ -88,21 +89,46 @@
// if no such block exists.
uint32_t SwitchMergeBlock(uint32_t bb_id);
+ // Returns true if |bb_id| is the continue block for a loop.
bool IsContinueBlock(uint32_t bb_id);
+
+ // Returns true if |bb_id| is in the continue construct for its inner most
+ // containing loop.
+ bool IsInContainingLoopsContinueConstruct(uint32_t bb_id);
+
+ // Returns true if |bb_id| is in the continue construct for any loop in its
+ // function.
+ bool IsInContinueConstruct(uint32_t bb_id);
+
+ // Return true if |bb_id| is the merge block for a construct.
bool IsMergeBlock(uint32_t bb_id);
+ // Returns the set of function ids that are called directly or indirectly from
+ // a continue construct.
+ std::unordered_set<uint32_t> FindFuncsCalledFromContinue();
+
private:
// Struct used to hold the information for a basic block.
// |containing_construct| is the header for the innermost containing
// construct, or 0 if no such construct exists. It could be a selection
- // construct or a loop construct. |containing_loop| is the innermost
- // containing loop construct, or 0 if the basic bloc is not in a loop. If the
- // basic block is in a selection construct that is contained in a loop
- // construct, then these two values will not be the same.
+ // construct or a loop construct.
+ //
+ // |containing_loop| is the innermost containing loop construct, or 0 if the
+ // basic bloc is not in a loop. If the basic block is in a selection
+ // construct that is contained in a loop construct, then these two values will
+ // not be the same.
+ //
+ // |containing_switch| is the innermost contain selection construct with an
+ // |OpSwitch| for the branch, as long as there is not intervening loop. This
+ // is used to identify the selection construct from which it can break.
+ //
+ // |in_continue| is true of the block is in the continue construct for its
+ // innermost containing loop.
struct ConstructInfo {
uint32_t containing_construct;
uint32_t containing_loop;
uint32_t containing_switch;
+ bool in_continue;
};
// Populates |bb_to_construct_| with the innermost containing merge and loop
diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp
index d349481..166b828 100644
--- a/source/opt/type_manager.cpp
+++ b/source/opt/type_manager.cpp
@@ -409,6 +409,22 @@
{static_cast<uint32_t>(
type->AsForwardPointer()->storage_class())}}});
break;
+ case Type::kCooperativeMatrixNV: {
+ auto coop_mat = type->AsCooperativeMatrixNV();
+ uint32_t const component_type =
+ GetTypeInstruction(coop_mat->component_type());
+ if (component_type == 0) {
+ return 0;
+ }
+ typeInst = MakeUnique<Instruction>(
+ context(), SpvOpTypeCooperativeMatrixNV, 0, id,
+ std::initializer_list<Operand>{
+ {SPV_OPERAND_TYPE_ID, {component_type}},
+ {SPV_OPERAND_TYPE_SCOPE_ID, {coop_mat->scope_id()}},
+ {SPV_OPERAND_TYPE_ID, {coop_mat->rows_id()}},
+ {SPV_OPERAND_TYPE_ID, {coop_mat->columns_id()}}});
+ break;
+ }
default:
assert(false && "Unexpected type");
break;
@@ -604,6 +620,14 @@
}
break;
}
+ case Type::kCooperativeMatrixNV: {
+ const CooperativeMatrixNV* cm_type = type.AsCooperativeMatrixNV();
+ const Type* component_type = cm_type->component_type();
+ rebuilt_ty = MakeUnique<CooperativeMatrixNV>(
+ RebuildType(*component_type), cm_type->scope_id(), cm_type->rows_id(),
+ cm_type->columns_id());
+ break;
+ }
default:
assert(false && "Unhandled type");
return nullptr;
@@ -832,6 +856,12 @@
case SpvOpTypeAccelerationStructureNV:
type = new AccelerationStructureNV();
break;
+ case SpvOpTypeCooperativeMatrixNV:
+ type = new CooperativeMatrixNV(GetType(inst.GetSingleWordInOperand(0)),
+ inst.GetSingleWordInOperand(1),
+ inst.GetSingleWordInOperand(2),
+ inst.GetSingleWordInOperand(3));
+ break;
default:
SPIRV_UNIMPLEMENTED(consumer_, "unhandled type");
break;
diff --git a/source/opt/types.cpp b/source/opt/types.cpp
index 4f7150f..17f8fe9 100644
--- a/source/opt/types.cpp
+++ b/source/opt/types.cpp
@@ -127,6 +127,7 @@
DeclareKindCase(PipeStorage);
DeclareKindCase(NamedBarrier);
DeclareKindCase(AccelerationStructureNV);
+ DeclareKindCase(CooperativeMatrixNV);
#undef DeclareKindCase
default:
assert(false && "Unhandled type");
@@ -171,6 +172,7 @@
DeclareKindCase(PipeStorage);
DeclareKindCase(NamedBarrier);
DeclareKindCase(AccelerationStructureNV);
+ DeclareKindCase(CooperativeMatrixNV);
#undef DeclareKindCase
default:
assert(false && "Unhandled type");
@@ -220,6 +222,7 @@
DeclareKindCase(PipeStorage);
DeclareKindCase(NamedBarrier);
DeclareKindCase(AccelerationStructureNV);
+ DeclareKindCase(CooperativeMatrixNV);
#undef DeclareKindCase
default:
assert(false && "Unhandled type");
@@ -654,6 +657,44 @@
if (pointer_) pointer_->GetHashWords(words, seen);
}
+CooperativeMatrixNV::CooperativeMatrixNV(const Type* type, const uint32_t scope,
+ const uint32_t rows,
+ const uint32_t columns)
+ : Type(kCooperativeMatrixNV),
+ component_type_(type),
+ scope_id_(scope),
+ rows_id_(rows),
+ columns_id_(columns) {
+ assert(type != nullptr);
+ assert(scope != 0);
+ assert(rows != 0);
+ assert(columns != 0);
+}
+
+std::string CooperativeMatrixNV::str() const {
+ std::ostringstream oss;
+ oss << "<" << component_type_->str() << ", " << scope_id_ << ", " << rows_id_
+ << ", " << columns_id_ << ">";
+ return oss.str();
+}
+
+void CooperativeMatrixNV::GetExtraHashWords(
+ std::vector<uint32_t>* words, std::unordered_set<const Type*>* pSet) const {
+ component_type_->GetHashWords(words, pSet);
+ words->push_back(scope_id_);
+ words->push_back(rows_id_);
+ words->push_back(columns_id_);
+}
+
+bool CooperativeMatrixNV::IsSameImpl(const Type* that,
+ IsSameCache* seen) const {
+ const CooperativeMatrixNV* mt = that->AsCooperativeMatrixNV();
+ if (!mt) return false;
+ return component_type_->IsSameImpl(mt->component_type_, seen) &&
+ scope_id_ == mt->scope_id_ && rows_id_ == mt->rows_id_ &&
+ columns_id_ == mt->columns_id_ && HasSameDecorations(that);
+}
+
} // namespace analysis
} // namespace opt
} // namespace spvtools
diff --git a/source/opt/types.h b/source/opt/types.h
index 57920df..69071ea 100644
--- a/source/opt/types.h
+++ b/source/opt/types.h
@@ -58,6 +58,7 @@
class PipeStorage;
class NamedBarrier;
class AccelerationStructureNV;
+class CooperativeMatrixNV;
// Abstract class for a SPIR-V type. It has a bunch of As<sublcass>() methods,
// which is used as a way to probe the actual <subclass>.
@@ -93,6 +94,7 @@
kPipeStorage,
kNamedBarrier,
kAccelerationStructureNV,
+ kCooperativeMatrixNV
};
Type(Kind k) : kind_(k) {}
@@ -196,6 +198,7 @@
DeclareCastMethod(PipeStorage)
DeclareCastMethod(NamedBarrier)
DeclareCastMethod(AccelerationStructureNV)
+ DeclareCastMethod(CooperativeMatrixNV)
#undef DeclareCastMethod
protected:
@@ -597,6 +600,36 @@
const Pointer* pointer_;
};
+class CooperativeMatrixNV : public Type {
+ public:
+ CooperativeMatrixNV(const Type* type, const uint32_t scope,
+ const uint32_t rows, const uint32_t columns);
+ CooperativeMatrixNV(const CooperativeMatrixNV&) = default;
+
+ std::string str() const override;
+
+ CooperativeMatrixNV* AsCooperativeMatrixNV() override { return this; }
+ const CooperativeMatrixNV* AsCooperativeMatrixNV() const override {
+ return this;
+ }
+
+ void GetExtraHashWords(std::vector<uint32_t>*,
+ std::unordered_set<const Type*>*) const override;
+
+ const Type* component_type() const { return component_type_; }
+ uint32_t scope_id() const { return scope_id_; }
+ uint32_t rows_id() const { return rows_id_; }
+ uint32_t columns_id() const { return columns_id_; }
+
+ private:
+ bool IsSameImpl(const Type* that, IsSameCache*) const override;
+
+ const Type* component_type_;
+ const uint32_t scope_id_;
+ const uint32_t rows_id_;
+ const uint32_t columns_id_;
+};
+
#define DefineParameterlessType(type, name) \
class type : public Type { \
public: \
diff --git a/source/opt/upgrade_memory_model.cpp b/source/opt/upgrade_memory_model.cpp
index f3bee9e..ab25205 100644
--- a/source/opt/upgrade_memory_model.cpp
+++ b/source/opt/upgrade_memory_model.cpp
@@ -429,7 +429,7 @@
} else {
assert(spvOpcodeIsComposite(element_inst->opcode()));
element_inst = context()->get_def_use_mgr()->GetDef(
- element_inst->GetSingleWordInOperand(1u));
+ element_inst->GetSingleWordInOperand(0u));
}
}
diff --git a/source/opt/wrap_opkill.cpp b/source/opt/wrap_opkill.cpp
index d10cdd2..ffd7a10 100644
--- a/source/opt/wrap_opkill.cpp
+++ b/source/opt/wrap_opkill.cpp
@@ -22,8 +22,11 @@
Pass::Status WrapOpKill::Process() {
bool modified = false;
- for (auto& func : *get_module()) {
- bool successful = func.WhileEachInst([this, &modified](Instruction* inst) {
+ auto func_to_process =
+ context()->GetStructuredCFGAnalysis()->FindFuncsCalledFromContinue();
+ for (uint32_t func_id : func_to_process) {
+ Function* func = context()->GetFunction(func_id);
+ bool successful = func->WhileEachInst([this, &modified](Instruction* inst) {
if (inst->opcode() == SpvOpKill) {
modified = true;
if (!ReplaceWithFunctionCall(inst)) {
@@ -59,7 +62,24 @@
if (ir_builder.AddFunctionCall(GetVoidTypeId(), func_id, {}) == nullptr) {
return false;
}
- ir_builder.AddUnreachable();
+
+ Instruction* return_inst = nullptr;
+ uint32_t return_type_id = GetOwningFunctionsReturnType(inst);
+ if (return_type_id != GetVoidTypeId()) {
+ Instruction* undef = ir_builder.AddNullaryOp(return_type_id, SpvOpUndef);
+ if (undef == nullptr) {
+ return false;
+ }
+ return_inst =
+ ir_builder.AddUnaryOp(0, SpvOpReturnValue, undef->result_id());
+ } else {
+ return_inst = ir_builder.AddNullaryOp(0, SpvOpReturn);
+ }
+
+ if (return_inst == nullptr) {
+ return false;
+ }
+
context()->KillInst(inst);
return true;
}
@@ -95,9 +115,14 @@
return 0;
}
+ uint32_t void_type_id = GetVoidTypeId();
+ if (void_type_id == 0) {
+ return 0;
+ }
+
// Generate the function start instruction
std::unique_ptr<Instruction> func_start(new Instruction(
- context(), SpvOpFunction, GetVoidTypeId(), opkill_func_id, {}));
+ context(), SpvOpFunction, void_type_id, opkill_func_id, {}));
func_start->AddOperand({SPV_OPERAND_TYPE_FUNCTION_CONTROL, {0}});
func_start->AddOperand({SPV_OPERAND_TYPE_ID, {GetVoidFunctionTypeId()}});
opkill_function_.reset(new Function(std::move(func_start)));
@@ -142,5 +167,15 @@
return opkill_function_->result_id();
}
+uint32_t WrapOpKill::GetOwningFunctionsReturnType(Instruction* inst) {
+ BasicBlock* bb = context()->get_instr_block(inst);
+ if (bb == nullptr) {
+ return 0;
+ }
+
+ Function* func = bb->GetParent();
+ return func->type_id();
+}
+
} // namespace opt
} // namespace spvtools
diff --git a/source/opt/wrap_opkill.h b/source/opt/wrap_opkill.h
index 8b03281..87a5d69 100644
--- a/source/opt/wrap_opkill.h
+++ b/source/opt/wrap_opkill.h
@@ -56,6 +56,10 @@
// function could not be generated.
uint32_t GetOpKillFuncId();
+ // Returns the id of the return type for the function that contains |inst|.
+ // Returns 0 if |inst| is not in a function.
+ uint32_t GetOwningFunctionsReturnType(Instruction* inst);
+
// The id of the void type. If its value is 0, then the void type has not
// been found or created yet.
uint32_t void_type_id_;
diff --git a/source/print.cpp b/source/print.cpp
index f75e2d4..1d9829d 100644
--- a/source/print.cpp
+++ b/source/print.cpp
@@ -15,7 +15,7 @@
#include "source/print.h"
#if defined(SPIRV_ANDROID) || defined(SPIRV_LINUX) || defined(SPIRV_MAC) || \
- defined(SPIRV_FREEBSD)
+ defined(SPIRV_IOS) || defined(SPIRV_FREEBSD) || defined(SPIRV_EMSCRIPTEN)
namespace spvtools {
clr::reset::operator const char*() { return "\x1b[0m"; }
diff --git a/source/reduce/CMakeLists.txt b/source/reduce/CMakeLists.txt
index 7651e86..51e9b1d 100644
--- a/source/reduce/CMakeLists.txt
+++ b/source/reduce/CMakeLists.txt
@@ -29,8 +29,6 @@
remove_instruction_reduction_opportunity.h
remove_function_reduction_opportunity.h
remove_function_reduction_opportunity_finder.h
- remove_opname_instruction_reduction_opportunity_finder.h
- remove_relaxed_precision_decoration_opportunity_finder.h
remove_selection_reduction_opportunity.h
remove_selection_reduction_opportunity_finder.h
remove_unreferenced_instruction_reduction_opportunity_finder.h
@@ -57,11 +55,9 @@
remove_function_reduction_opportunity.cpp
remove_function_reduction_opportunity_finder.cpp
remove_instruction_reduction_opportunity.cpp
- remove_relaxed_precision_decoration_opportunity_finder.cpp
remove_selection_reduction_opportunity.cpp
remove_selection_reduction_opportunity_finder.cpp
remove_unreferenced_instruction_reduction_opportunity_finder.cpp
- remove_opname_instruction_reduction_opportunity_finder.cpp
structured_loop_to_selection_reduction_opportunity.cpp
structured_loop_to_selection_reduction_opportunity_finder.cpp
conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp
@@ -81,8 +77,10 @@
spvtools_default_compile_options(SPIRV-Tools-reduce)
target_include_directories(SPIRV-Tools-reduce
- PUBLIC ${spirv-tools_SOURCE_DIR}/include
- PUBLIC ${SPIRV_HEADER_INCLUDE_DIR}
+ PUBLIC
+ $<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
+ $<BUILD_INTERFACE:${SPIRV_HEADER_INCLUDE_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
)
# The reducer reuses a lot of functionality from the SPIRV-Tools library.
@@ -94,8 +92,16 @@
spvtools_check_symbol_exports(SPIRV-Tools-reduce)
if(ENABLE_SPIRV_TOOLS_INSTALL)
- install(TARGETS SPIRV-Tools-reduce
+ install(TARGETS SPIRV-Tools-reduce EXPORT SPIRV-Tools-reduceTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ export(EXPORT SPIRV-Tools-reduceTargets FILE SPIRV-Tools-reduceTarget.cmake)
+
+ spvtools_config_package_dir(SPIRV-Tools-reduce PACKAGE_DIR)
+ install(EXPORT SPIRV-Tools-reduceTargets FILE SPIRV-Tools-reduceTarget.cmake
+ DESTINATION ${PACKAGE_DIR})
+
+ spvtools_generate_config_file(SPIRV-Tools-reduce)
+ install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-reduceConfig.cmake DESTINATION ${PACKAGE_DIR})
endif(ENABLE_SPIRV_TOOLS_INSTALL)
diff --git a/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp b/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp
index 2feca4a..0bd93b9 100644
--- a/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp
+++ b/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp
@@ -73,7 +73,7 @@
result.push_back(
MakeUnique<
ConditionalBranchToSimpleConditionalBranchReductionOpportunity>(
- block.terminator(), redirect_to_true));
+ context, block.terminator(), redirect_to_true));
}
}
}
diff --git a/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp b/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp
index 92c621e..d744773 100644
--- a/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp
+++ b/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp
@@ -19,12 +19,15 @@
namespace spvtools {
namespace reduce {
+using opt::IRContext;
using opt::Instruction;
ConditionalBranchToSimpleConditionalBranchReductionOpportunity::
ConditionalBranchToSimpleConditionalBranchReductionOpportunity(
- Instruction* conditional_branch_instruction, bool redirect_to_true)
- : conditional_branch_instruction_(conditional_branch_instruction),
+ IRContext* context, Instruction* conditional_branch_instruction,
+ bool redirect_to_true)
+ : context_(context),
+ conditional_branch_instruction_(conditional_branch_instruction),
redirect_to_true_(redirect_to_true) {}
bool ConditionalBranchToSimpleConditionalBranchReductionOpportunity::
@@ -43,11 +46,24 @@
uint32_t operand_to_copy =
redirect_to_true_ ? kTrueBranchOperandIndex : kFalseBranchOperandIndex;
+ auto old_successor_block_id =
+ conditional_branch_instruction_->GetSingleWordInOperand(
+ operand_to_modify);
+
// Do the branch redirection.
conditional_branch_instruction_->SetInOperand(
operand_to_modify,
{conditional_branch_instruction_->GetSingleWordInOperand(
operand_to_copy)});
+
+ // The old successor block may have phi instructions; these will need to
+ // respect the change in edges.
+ AdaptPhiInstructionsForRemovedEdge(
+ context_->get_instr_block(conditional_branch_instruction_)->id(),
+ context_->cfg()->block(old_successor_block_id));
+
+ // We have changed the CFG.
+ context_->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
}
} // namespace reduce
diff --git a/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h b/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h
index 421906b..1f9cb6d 100644
--- a/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h
+++ b/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h
@@ -31,7 +31,8 @@
// to the true target; otherwise, the true target will be changed to also
// point to the false target.
explicit ConditionalBranchToSimpleConditionalBranchReductionOpportunity(
- opt::Instruction* conditional_branch_instruction, bool redirect_to_true);
+ opt::IRContext* context, opt::Instruction* conditional_branch_instruction,
+ bool redirect_to_true);
bool PreconditionHolds() override;
@@ -39,6 +40,7 @@
void Apply() override;
private:
+ opt::IRContext* context_;
opt::Instruction* conditional_branch_instruction_;
// If true, the false target will be changed to point to the true target;
diff --git a/source/reduce/reducer.cpp b/source/reduce/reducer.cpp
index ebb5d47..bda41ce 100644
--- a/source/reduce/reducer.cpp
+++ b/source/reduce/reducer.cpp
@@ -24,8 +24,6 @@
#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h"
#include "source/reduce/remove_block_reduction_opportunity_finder.h"
#include "source/reduce/remove_function_reduction_opportunity_finder.h"
-#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h"
-#include "source/reduce/remove_relaxed_precision_decoration_opportunity_finder.h"
#include "source/reduce/remove_selection_reduction_opportunity_finder.h"
#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h"
#include "source/reduce/simple_conditional_branch_to_branch_opportunity_finder.h"
@@ -35,41 +33,32 @@
namespace spvtools {
namespace reduce {
-struct Reducer::Impl {
- explicit Impl(spv_target_env env) : target_env(env) {}
-
- bool ReachedStepLimit(uint32_t current_step,
- spv_const_reducer_options options);
-
- const spv_target_env target_env; // Target environment.
- MessageConsumer consumer; // Message consumer.
- InterestingnessFunction interestingness_function;
- std::vector<std::unique_ptr<ReductionPass>> passes;
-};
-
-Reducer::Reducer(spv_target_env env) : impl_(MakeUnique<Impl>(env)) {}
+Reducer::Reducer(spv_target_env target_env) : target_env_(target_env) {}
Reducer::~Reducer() = default;
void Reducer::SetMessageConsumer(MessageConsumer c) {
- for (auto& pass : impl_->passes) {
+ for (auto& pass : passes_) {
pass->SetMessageConsumer(c);
}
- impl_->consumer = std::move(c);
+ for (auto& pass : cleanup_passes_) {
+ pass->SetMessageConsumer(c);
+ }
+ consumer_ = std::move(c);
}
void Reducer::SetInterestingnessFunction(
Reducer::InterestingnessFunction interestingness_function) {
- impl_->interestingness_function = std::move(interestingness_function);
+ interestingness_function_ = std::move(interestingness_function);
}
Reducer::ReductionResultStatus Reducer::Run(
std::vector<uint32_t>&& binary_in, std::vector<uint32_t>* binary_out,
spv_const_reducer_options options,
- spv_validator_options validator_options) const {
+ spv_validator_options validator_options) {
std::vector<uint32_t> current_binary(std::move(binary_in));
- spvtools::SpirvTools tools(impl_->target_env);
+ spvtools::SpirvTools tools(target_env_);
assert(tools.IsValid() && "Failed to create SPIRV-Tools interface");
// Keeps track of how many reduction attempts have been tried. Reduction
@@ -79,105 +68,43 @@
// Initial state should be valid.
if (!tools.Validate(¤t_binary[0], current_binary.size(),
validator_options)) {
- impl_->consumer(SPV_MSG_INFO, nullptr, {},
- "Initial binary is invalid; stopping.");
+ consumer_(SPV_MSG_INFO, nullptr, {},
+ "Initial binary is invalid; stopping.");
return Reducer::ReductionResultStatus::kInitialStateInvalid;
}
// Initial state should be interesting.
- if (!impl_->interestingness_function(current_binary, reductions_applied)) {
- impl_->consumer(SPV_MSG_INFO, nullptr, {},
- "Initial state was not interesting; stopping.");
+ if (!interestingness_function_(current_binary, reductions_applied)) {
+ consumer_(SPV_MSG_INFO, nullptr, {},
+ "Initial state was not interesting; stopping.");
return Reducer::ReductionResultStatus::kInitialStateNotInteresting;
}
- // Determines whether, on completing one round of reduction passes, it is
- // worthwhile trying a further round.
- bool another_round_worthwhile = true;
+ Reducer::ReductionResultStatus result =
+ RunPasses(&passes_, options, validator_options, tools, ¤t_binary,
+ &reductions_applied);
- // Apply round after round of reduction passes until we hit the reduction
- // step limit, or deem that another round is not going to be worthwhile.
- while (!impl_->ReachedStepLimit(reductions_applied, options) &&
- another_round_worthwhile) {
- // At the start of a round of reduction passes, assume another round will
- // not be worthwhile unless we find evidence to the contrary.
- another_round_worthwhile = false;
-
- // Iterate through the available passes
- for (auto& pass : impl_->passes) {
- // If this pass hasn't reached its minimum granularity then it's
- // worth eventually doing another round of reductions, in order to
- // try this pass at a finer granularity.
- another_round_worthwhile |= !pass->ReachedMinimumGranularity();
-
- // Keep applying this pass at its current granularity until it stops
- // working or we hit the reduction step limit.
- impl_->consumer(SPV_MSG_INFO, nullptr, {},
- ("Trying pass " + pass->GetName() + ".").c_str());
- do {
- auto maybe_result = pass->TryApplyReduction(current_binary);
- if (maybe_result.empty()) {
- // For this round, the pass has no more opportunities (chunks) to
- // apply, so move on to the next pass.
- impl_->consumer(
- SPV_MSG_INFO, nullptr, {},
- ("Pass " + pass->GetName() + " did not make a reduction step.")
- .c_str());
- break;
- }
- bool interesting = false;
- std::stringstream stringstream;
- reductions_applied++;
- stringstream << "Pass " << pass->GetName() << " made reduction step "
- << reductions_applied << ".";
- impl_->consumer(SPV_MSG_INFO, nullptr, {},
- (stringstream.str().c_str()));
- if (!tools.Validate(&maybe_result[0], maybe_result.size(),
- validator_options)) {
- // The reduction step went wrong and an invalid binary was produced.
- // By design, this shouldn't happen; this is a safeguard to stop an
- // invalid binary from being regarded as interesting.
- impl_->consumer(SPV_MSG_INFO, nullptr, {},
- "Reduction step produced an invalid binary.");
- if (options->fail_on_validation_error) {
- return Reducer::ReductionResultStatus::kStateInvalid;
- }
- } else if (impl_->interestingness_function(maybe_result,
- reductions_applied)) {
- // Success! The binary produced by this reduction step is
- // interesting, so make it the binary of interest henceforth, and
- // note that it's worth doing another round of reduction passes.
- impl_->consumer(SPV_MSG_INFO, nullptr, {},
- "Reduction step succeeded.");
- current_binary = std::move(maybe_result);
- interesting = true;
- another_round_worthwhile = true;
- }
- // We must call this before the next call to TryApplyReduction.
- pass->NotifyInteresting(interesting);
- // Bail out if the reduction step limit has been reached.
- } while (!impl_->ReachedStepLimit(reductions_applied, options));
- }
+ if (result == Reducer::ReductionResultStatus::kComplete) {
+ // Cleanup passes.
+ result = RunPasses(&cleanup_passes_, options, validator_options, tools,
+ ¤t_binary, &reductions_applied);
}
+ if (result == Reducer::ReductionResultStatus::kComplete) {
+ consumer_(SPV_MSG_INFO, nullptr, {}, "No more to reduce; stopping.");
+ }
+
+ // Even if the reduction has failed by this point (e.g. due to producing an
+ // invalid binary), we still update the output binary for better debugging.
*binary_out = std::move(current_binary);
- // Report whether reduction completed, or bailed out early due to reaching
- // the step limit.
- if (impl_->ReachedStepLimit(reductions_applied, options)) {
- impl_->consumer(SPV_MSG_INFO, nullptr, {},
- "Reached reduction step limit; stopping.");
- return Reducer::ReductionResultStatus::kReachedStepLimit;
- }
- impl_->consumer(SPV_MSG_INFO, nullptr, {}, "No more to reduce; stopping.");
- return Reducer::ReductionResultStatus::kComplete;
+ return result;
}
void Reducer::AddDefaultReductionPasses() {
- AddReductionPass(spvtools::MakeUnique<
- RemoveOpNameInstructionReductionOpportunityFinder>());
- AddReductionPass(spvtools::MakeUnique<
- RemoveRelaxedPrecisionDecorationOpportunityFinder>());
+ AddReductionPass(
+ spvtools::MakeUnique<
+ RemoveUnreferencedInstructionReductionOpportunityFinder>(false));
AddReductionPass(
spvtools::MakeUnique<OperandToUndefReductionOpportunityFinder>());
AddReductionPass(
@@ -185,8 +112,6 @@
AddReductionPass(
spvtools::MakeUnique<OperandToDominatingIdReductionOpportunityFinder>());
AddReductionPass(spvtools::MakeUnique<
- RemoveUnreferencedInstructionReductionOpportunityFinder>());
- AddReductionPass(spvtools::MakeUnique<
StructuredLoopToSelectionReductionOpportunityFinder>());
AddReductionPass(
spvtools::MakeUnique<MergeBlocksReductionOpportunityFinder>());
@@ -201,18 +126,117 @@
ConditionalBranchToSimpleConditionalBranchOpportunityFinder>());
AddReductionPass(
spvtools::MakeUnique<SimpleConditionalBranchToBranchOpportunityFinder>());
+
+ // Cleanup passes.
+
+ AddCleanupReductionPass(
+ spvtools::MakeUnique<
+ RemoveUnreferencedInstructionReductionOpportunityFinder>(true));
}
void Reducer::AddReductionPass(
std::unique_ptr<ReductionOpportunityFinder>&& finder) {
- impl_->passes.push_back(spvtools::MakeUnique<ReductionPass>(
- impl_->target_env, std::move(finder)));
+ passes_.push_back(
+ spvtools::MakeUnique<ReductionPass>(target_env_, std::move(finder)));
}
-bool Reducer::Impl::ReachedStepLimit(uint32_t current_step,
- spv_const_reducer_options options) {
+void Reducer::AddCleanupReductionPass(
+ std::unique_ptr<ReductionOpportunityFinder>&& finder) {
+ cleanup_passes_.push_back(
+ spvtools::MakeUnique<ReductionPass>(target_env_, std::move(finder)));
+}
+
+bool Reducer::ReachedStepLimit(uint32_t current_step,
+ spv_const_reducer_options options) {
return current_step >= options->step_limit;
}
+Reducer::ReductionResultStatus Reducer::RunPasses(
+ std::vector<std::unique_ptr<ReductionPass>>* passes,
+ spv_const_reducer_options options, spv_validator_options validator_options,
+ const SpirvTools& tools, std::vector<uint32_t>* current_binary,
+ uint32_t* const reductions_applied) {
+ // Determines whether, on completing one round of reduction passes, it is
+ // worthwhile trying a further round.
+ bool another_round_worthwhile = true;
+
+ // Apply round after round of reduction passes until we hit the reduction
+ // step limit, or deem that another round is not going to be worthwhile.
+ while (!ReachedStepLimit(*reductions_applied, options) &&
+ another_round_worthwhile) {
+ // At the start of a round of reduction passes, assume another round will
+ // not be worthwhile unless we find evidence to the contrary.
+ another_round_worthwhile = false;
+
+ // Iterate through the available passes.
+ for (auto& pass : *passes) {
+ // If this pass hasn't reached its minimum granularity then it's
+ // worth eventually doing another round of reductions, in order to
+ // try this pass at a finer granularity.
+ another_round_worthwhile |= !pass->ReachedMinimumGranularity();
+
+ // Keep applying this pass at its current granularity until it stops
+ // working or we hit the reduction step limit.
+ consumer_(SPV_MSG_INFO, nullptr, {},
+ ("Trying pass " + pass->GetName() + ".").c_str());
+ do {
+ auto maybe_result = pass->TryApplyReduction(*current_binary);
+ if (maybe_result.empty()) {
+ // For this round, the pass has no more opportunities (chunks) to
+ // apply, so move on to the next pass.
+ consumer_(
+ SPV_MSG_INFO, nullptr, {},
+ ("Pass " + pass->GetName() + " did not make a reduction step.")
+ .c_str());
+ break;
+ }
+ bool interesting = false;
+ std::stringstream stringstream;
+ (*reductions_applied)++;
+ stringstream << "Pass " << pass->GetName() << " made reduction step "
+ << *reductions_applied << ".";
+ consumer_(SPV_MSG_INFO, nullptr, {}, (stringstream.str().c_str()));
+ if (!tools.Validate(&maybe_result[0], maybe_result.size(),
+ validator_options)) {
+ // The reduction step went wrong and an invalid binary was produced.
+ // By design, this shouldn't happen; this is a safeguard to stop an
+ // invalid binary from being regarded as interesting.
+ consumer_(SPV_MSG_INFO, nullptr, {},
+ "Reduction step produced an invalid binary.");
+ if (options->fail_on_validation_error) {
+ // In this mode, we fail, so we update the current binary so it is
+ // output for debugging.
+ *current_binary = std::move(maybe_result);
+ return Reducer::ReductionResultStatus::kStateInvalid;
+ }
+ } else if (interestingness_function_(maybe_result,
+ *reductions_applied)) {
+ // Success! The binary produced by this reduction step is
+ // interesting, so make it the binary of interest henceforth, and
+ // note that it's worth doing another round of reduction passes.
+ consumer_(SPV_MSG_INFO, nullptr, {}, "Reduction step succeeded.");
+ *current_binary = std::move(maybe_result);
+ interesting = true;
+ another_round_worthwhile = true;
+ }
+ // We must call this before the next call to TryApplyReduction.
+ pass->NotifyInteresting(interesting);
+ // Bail out if the reduction step limit has been reached.
+ } while (!ReachedStepLimit(*reductions_applied, options));
+ }
+ }
+
+ // Report whether reduction completed, or bailed out early due to reaching
+ // the step limit.
+ if (ReachedStepLimit(*reductions_applied, options)) {
+ consumer_(SPV_MSG_INFO, nullptr, {},
+ "Reached reduction step limit; stopping.");
+ return Reducer::ReductionResultStatus::kReachedStepLimit;
+ }
+
+ // The passes completed successfully, although we may still run more passes.
+ return Reducer::ReductionResultStatus::kComplete;
+}
+
} // namespace reduce
} // namespace spvtools
diff --git a/source/reduce/reducer.h b/source/reduce/reducer.h
index a9b28c3..864ce75 100644
--- a/source/reduce/reducer.h
+++ b/source/reduce/reducer.h
@@ -50,7 +50,7 @@
using InterestingnessFunction =
std::function<bool(const std::vector<uint32_t>&, uint32_t)>;
- // Constructs an instance with the given target |env|, which is used to
+ // Constructs an instance with the given target |target_env|, which is used to
// decode the binary to be reduced later.
//
// The constructed instance will have an empty message consumer, which just
@@ -59,7 +59,7 @@
//
// The constructed instance also needs to have an interestingness function
// set and some reduction passes added to it in order to be useful.
- explicit Reducer(spv_target_env env);
+ explicit Reducer(spv_target_env target_env);
// Disables copy/move constructor/assignment operations.
Reducer(const Reducer&) = delete;
@@ -86,17 +86,34 @@
// that will be iterated over.
void AddReductionPass(std::unique_ptr<ReductionOpportunityFinder>&& finder);
+ // Adds a cleanup reduction pass based on the given finder to the sequence of
+ // passes that will run after other passes.
+ void AddCleanupReductionPass(
+ std::unique_ptr<ReductionOpportunityFinder>&& finder);
+
// Reduces the given SPIR-V module |binary_out|.
// The reduced binary ends up in |binary_out|.
// A status is returned.
ReductionResultStatus Run(std::vector<uint32_t>&& binary_in,
std::vector<uint32_t>* binary_out,
spv_const_reducer_options options,
- spv_validator_options validator_options) const;
+ spv_validator_options validator_options);
private:
- struct Impl; // Opaque struct for holding internal data.
- std::unique_ptr<Impl> impl_; // Unique pointer to internal data.
+ static bool ReachedStepLimit(uint32_t current_step,
+ spv_const_reducer_options options);
+
+ ReductionResultStatus RunPasses(
+ std::vector<std::unique_ptr<ReductionPass>>* passes,
+ spv_const_reducer_options options,
+ spv_validator_options validator_options, const SpirvTools& tools,
+ std::vector<uint32_t>* current_binary, uint32_t* reductions_applied);
+
+ const spv_target_env target_env_;
+ MessageConsumer consumer_;
+ InterestingnessFunction interestingness_function_;
+ std::vector<std::unique_ptr<ReductionPass>> passes_;
+ std::vector<std::unique_ptr<ReductionPass>> cleanup_passes_;
};
} // namespace reduce
diff --git a/source/reduce/reduction_util.cpp b/source/reduce/reduction_util.cpp
index 2b2b7e6..6f128dc 100644
--- a/source/reduce/reduction_util.cpp
+++ b/source/reduce/reduction_util.cpp
@@ -44,5 +44,22 @@
return undef_id;
}
+void AdaptPhiInstructionsForRemovedEdge(uint32_t from_id,
+ opt::BasicBlock* to_block) {
+ to_block->ForEachPhiInst([&from_id](Instruction* phi_inst) {
+ Instruction::OperandList new_in_operands;
+ // Go through the OpPhi's input operands in (variable, parent) pairs.
+ for (uint32_t index = 0; index < phi_inst->NumInOperands(); index += 2) {
+ // Keep all pairs where the parent is not the block from which the edge
+ // is being removed.
+ if (phi_inst->GetInOperand(index + 1).words[0] != from_id) {
+ new_in_operands.push_back(phi_inst->GetInOperand(index));
+ new_in_operands.push_back(phi_inst->GetInOperand(index + 1));
+ }
+ }
+ phi_inst->SetInOperands(std::move(new_in_operands));
+ });
+}
+
} // namespace reduce
} // namespace spvtools
diff --git a/source/reduce/reduction_util.h b/source/reduce/reduction_util.h
index b8ffb6e..7e7e153 100644
--- a/source/reduce/reduction_util.h
+++ b/source/reduce/reduction_util.h
@@ -30,6 +30,11 @@
// adding one if it does not exist.
uint32_t FindOrCreateGlobalUndef(opt::IRContext* context, uint32_t type_id);
+// Removes any components of |to_block|'s phi instructions relating to
+// |from_id|.
+void AdaptPhiInstructionsForRemovedEdge(uint32_t from_id,
+ opt::BasicBlock* to_block);
+
} // namespace reduce
} // namespace spvtools
diff --git a/source/reduce/remove_opname_instruction_reduction_opportunity_finder.cpp b/source/reduce/remove_opname_instruction_reduction_opportunity_finder.cpp
deleted file mode 100644
index f687d71..0000000
--- a/source/reduce/remove_opname_instruction_reduction_opportunity_finder.cpp
+++ /dev/null
@@ -1,45 +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.
-
-#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h"
-
-#include "source/opcode.h"
-#include "source/opt/instruction.h"
-#include "source/reduce/remove_instruction_reduction_opportunity.h"
-
-namespace spvtools {
-namespace reduce {
-
-using opt::IRContext;
-
-std::vector<std::unique_ptr<ReductionOpportunity>>
-RemoveOpNameInstructionReductionOpportunityFinder::GetAvailableOpportunities(
- IRContext* context) const {
- std::vector<std::unique_ptr<ReductionOpportunity>> result;
-
- for (auto& inst : context->module()->debugs2()) {
- if (inst.opcode() == SpvOpName || inst.opcode() == SpvOpMemberName) {
- result.push_back(
- MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
- }
- }
- return result;
-}
-
-std::string RemoveOpNameInstructionReductionOpportunityFinder::GetName() const {
- return "RemoveOpNameInstructionReductionOpportunityFinder";
-}
-
-} // namespace reduce
-} // namespace spvtools
diff --git a/source/reduce/remove_opname_instruction_reduction_opportunity_finder.h b/source/reduce/remove_opname_instruction_reduction_opportunity_finder.h
deleted file mode 100644
index 8b9fd6f..0000000
--- a/source/reduce/remove_opname_instruction_reduction_opportunity_finder.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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.
-
-#ifndef SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_
-#define SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_
-
-#include "source/reduce/reduction_opportunity_finder.h"
-
-namespace spvtools {
-namespace reduce {
-
-// A finder for opportunities to remove OpName instructions. As well as making
-// the module smaller, removing an OpName instruction may create opportunities
-// for subsequently removing the instructions that create the ids to which the
-// OpName applies.
-class RemoveOpNameInstructionReductionOpportunityFinder
- : public ReductionOpportunityFinder {
- public:
- RemoveOpNameInstructionReductionOpportunityFinder() = default;
-
- ~RemoveOpNameInstructionReductionOpportunityFinder() override = default;
-
- std::string GetName() const final;
-
- std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
- opt::IRContext* context) const final;
-
- private:
-};
-
-} // namespace reduce
-} // namespace spvtools
-
-#endif // SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_
diff --git a/source/reduce/remove_relaxed_precision_decoration_opportunity_finder.cpp b/source/reduce/remove_relaxed_precision_decoration_opportunity_finder.cpp
deleted file mode 100644
index 352cefb..0000000
--- a/source/reduce/remove_relaxed_precision_decoration_opportunity_finder.cpp
+++ /dev/null
@@ -1,49 +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.
-
-#include "source/reduce/remove_relaxed_precision_decoration_opportunity_finder.h"
-
-#include "source/reduce/remove_instruction_reduction_opportunity.h"
-
-namespace spvtools {
-namespace reduce {
-
-std::vector<std::unique_ptr<ReductionOpportunity>>
-RemoveRelaxedPrecisionDecorationOpportunityFinder::GetAvailableOpportunities(
- opt::IRContext* context) const {
- std::vector<std::unique_ptr<ReductionOpportunity>> result;
-
- // Consider all annotation instructions
- for (auto& inst : context->module()->annotations()) {
- // We are interested in removing instructions of the form:
- // SpvOpDecorate %id RelaxedPrecision
- // and
- // SpvOpMemberDecorate %id member RelaxedPrecision
- if ((inst.opcode() == SpvOpDecorate &&
- inst.GetSingleWordInOperand(1) == SpvDecorationRelaxedPrecision) ||
- (inst.opcode() == SpvOpMemberDecorate &&
- inst.GetSingleWordInOperand(2) == SpvDecorationRelaxedPrecision)) {
- result.push_back(
- MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
- }
- }
- return result;
-}
-
-std::string RemoveRelaxedPrecisionDecorationOpportunityFinder::GetName() const {
- return "RemoveRelaxedPrecisionDecorationOpportunityFinder";
-}
-
-} // namespace reduce
-} // namespace spvtools
diff --git a/source/reduce/remove_relaxed_precision_decoration_opportunity_finder.h b/source/reduce/remove_relaxed_precision_decoration_opportunity_finder.h
deleted file mode 100644
index 673049c..0000000
--- a/source/reduce/remove_relaxed_precision_decoration_opportunity_finder.h
+++ /dev/null
@@ -1,36 +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_REDUCE_REMOVE_RELAXED_PRECISION_OPPORTUNITY_FINDER_H_
-#define SOURCE_REDUCE_REMOVE_RELAXED_PRECISION_OPPORTUNITY_FINDER_H_
-
-#include "source/reduce/reduction_opportunity_finder.h"
-
-namespace spvtools {
-namespace reduce {
-
-// A finder for opportunities to remove relaxed precision decorations.
-class RemoveRelaxedPrecisionDecorationOpportunityFinder
- : public ReductionOpportunityFinder {
- public:
- std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
- opt::IRContext* context) const override;
-
- std::string GetName() const override;
-};
-
-} // namespace reduce
-} // namespace spvtools
-
-#endif // SOURCE_REDUCE_REMOVE_RELAXED_PRECISION_OPPORTUNITY_FINDER_H_
diff --git a/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp b/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp
index dabee50..da61c8d 100644
--- a/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp
+++ b/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp
@@ -21,28 +21,109 @@
namespace spvtools {
namespace reduce {
+RemoveUnreferencedInstructionReductionOpportunityFinder::
+ RemoveUnreferencedInstructionReductionOpportunityFinder(
+ bool remove_constants_and_undefs)
+ : remove_constants_and_undefs_(remove_constants_and_undefs) {}
+
std::vector<std::unique_ptr<ReductionOpportunity>>
RemoveUnreferencedInstructionReductionOpportunityFinder::
GetAvailableOpportunities(opt::IRContext* context) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result;
+ for (auto& inst : context->module()->debugs1()) {
+ if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
+ continue;
+ }
+ result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
+ }
+
+ for (auto& inst : context->module()->debugs2()) {
+ if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
+ continue;
+ }
+ result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
+ }
+
+ for (auto& inst : context->module()->debugs3()) {
+ if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
+ continue;
+ }
+ result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
+ }
+
+ for (auto& inst : context->module()->types_values()) {
+ if (context->get_def_use_mgr()->NumUsers(&inst) > 0) {
+ continue;
+ }
+ if (!remove_constants_and_undefs_ &&
+ spvOpcodeIsConstantOrUndef(inst.opcode())) {
+ continue;
+ }
+ result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
+ }
+
+ for (auto& inst : context->module()->annotations()) {
+ if (context->get_def_use_mgr()->NumUsers(&inst) > 0) {
+ continue;
+ }
+
+ uint32_t decoration = SpvDecorationMax;
+ switch (inst.opcode()) {
+ case SpvOpDecorate:
+ case SpvOpDecorateId:
+ case SpvOpDecorateString:
+ decoration = inst.GetSingleWordInOperand(1u);
+ break;
+ case SpvOpMemberDecorate:
+ case SpvOpMemberDecorateString:
+ decoration = inst.GetSingleWordInOperand(2u);
+ break;
+ default:
+ break;
+ }
+
+ // We conservatively only remove specific decorations that we believe will
+ // not change the shader interface, will not make the shader invalid, will
+ // actually be found in practice, etc.
+
+ switch (decoration) {
+ case SpvDecorationRelaxedPrecision:
+ case SpvDecorationNoSignedWrap:
+ case SpvDecorationNoContraction:
+ case SpvDecorationNoUnsignedWrap:
+ case SpvDecorationUserSemantic:
+ break;
+ default:
+ // Give up.
+ continue;
+ }
+
+ result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
+ }
+
for (auto& function : *context->module()) {
for (auto& block : function) {
for (auto& inst : block) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
continue;
}
+ if (!remove_constants_and_undefs_ &&
+ spvOpcodeIsConstantOrUndef(inst.opcode())) {
+ continue;
+ }
if (spvOpcodeIsBlockTerminator(inst.opcode()) ||
inst.opcode() == SpvOpSelectionMerge ||
inst.opcode() == SpvOpLoopMerge) {
- // In this reduction pass we do not want to affect static control
- // flow.
+ // In this reduction pass we do not want to affect static
+ // control flow.
continue;
}
- // Given that we're in a block, we should only get here if the
- // instruction is not directly related to control flow; i.e., it's
- // some straightforward instruction with an unused result, like an
- // arithmetic operation or function call.
+ // Given that we're in a block, we should only get here if
+ // the instruction is not directly related to control flow;
+ // i.e., it's some straightforward instruction with an
+ // unused result, like an arithmetic operation or function
+ // call.
result.push_back(
MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
diff --git a/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h b/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h
index 30f460b..bc4f137 100644
--- a/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h
+++ b/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h
@@ -28,7 +28,8 @@
class RemoveUnreferencedInstructionReductionOpportunityFinder
: public ReductionOpportunityFinder {
public:
- RemoveUnreferencedInstructionReductionOpportunityFinder() = default;
+ explicit RemoveUnreferencedInstructionReductionOpportunityFinder(
+ bool remove_constants_and_undefs);
~RemoveUnreferencedInstructionReductionOpportunityFinder() override = default;
@@ -38,6 +39,7 @@
opt::IRContext* context) const final;
private:
+ bool remove_constants_and_undefs_;
};
} // namespace reduce
diff --git a/source/reduce/structured_loop_to_selection_reduction_opportunity.cpp b/source/reduce/structured_loop_to_selection_reduction_opportunity.cpp
index afc1298..88ea38e 100644
--- a/source/reduce/structured_loop_to_selection_reduction_opportunity.cpp
+++ b/source/reduce/structured_loop_to_selection_reduction_opportunity.cpp
@@ -168,23 +168,6 @@
}
void StructuredLoopToSelectionReductionOpportunity::
- AdaptPhiInstructionsForRemovedEdge(uint32_t from_id, BasicBlock* to_block) {
- to_block->ForEachPhiInst([&from_id](Instruction* phi_inst) {
- Instruction::OperandList new_in_operands;
- // Go through the OpPhi's input operands in (variable, parent) pairs.
- for (uint32_t index = 0; index < phi_inst->NumInOperands(); index += 2) {
- // Keep all pairs where the parent is not the block from which the edge
- // is being removed.
- if (phi_inst->GetInOperand(index + 1).words[0] != from_id) {
- new_in_operands.push_back(phi_inst->GetInOperand(index));
- new_in_operands.push_back(phi_inst->GetInOperand(index + 1));
- }
- }
- phi_inst->SetInOperands(std::move(new_in_operands));
- });
-}
-
-void StructuredLoopToSelectionReductionOpportunity::
AdaptPhiInstructionsForAddedEdge(uint32_t from_id, BasicBlock* to_block) {
to_block->ForEachPhiInst([this, &from_id](Instruction* phi_inst) {
// Add to the phi operand an (undef, from_id) pair to reflect the added
diff --git a/source/reduce/structured_loop_to_selection_reduction_opportunity.h b/source/reduce/structured_loop_to_selection_reduction_opportunity.h
index f6c065b..564811f 100644
--- a/source/reduce/structured_loop_to_selection_reduction_opportunity.h
+++ b/source/reduce/structured_loop_to_selection_reduction_opportunity.h
@@ -62,11 +62,6 @@
void RedirectEdge(uint32_t source_id, uint32_t original_target_id,
uint32_t new_target_id);
- // Removes any components of |to_block|'s phi instructions relating to
- // |from_id|.
- void AdaptPhiInstructionsForRemovedEdge(uint32_t from_id,
- opt::BasicBlock* to_block);
-
// Adds components to |to_block|'s phi instructions to account for a new
// incoming edge from |from_id|.
void AdaptPhiInstructionsForAddedEdge(uint32_t from_id,
diff --git a/source/spirv_fuzzer_options.cpp b/source/spirv_fuzzer_options.cpp
index 9a2cb9f..ab8903e 100644
--- a/source/spirv_fuzzer_options.cpp
+++ b/source/spirv_fuzzer_options.cpp
@@ -22,6 +22,7 @@
spv_fuzzer_options_t::spv_fuzzer_options_t()
: has_random_seed(false),
random_seed(0),
+ replay_validation_enabled(false),
shrinker_step_limit(kDefaultStepLimit) {}
SPIRV_TOOLS_EXPORT spv_fuzzer_options spvFuzzerOptionsCreate() {
@@ -32,6 +33,11 @@
delete options;
}
+SPIRV_TOOLS_EXPORT void spvFuzzerOptionsEnableReplayValidation(
+ spv_fuzzer_options options) {
+ options->replay_validation_enabled = true;
+}
+
SPIRV_TOOLS_EXPORT void spvFuzzerOptionsSetRandomSeed(
spv_fuzzer_options options, uint32_t seed) {
options->has_random_seed = true;
diff --git a/source/spirv_fuzzer_options.h b/source/spirv_fuzzer_options.h
index 3b8e15c..7bb16c7 100644
--- a/source/spirv_fuzzer_options.h
+++ b/source/spirv_fuzzer_options.h
@@ -29,6 +29,9 @@
bool has_random_seed;
uint32_t random_seed;
+ // See spvFuzzerOptionsEnableReplayValidation.
+ bool replay_validation_enabled;
+
// See spvFuzzerOptionsSetShrinkerStepLimit.
uint32_t shrinker_step_limit;
};
diff --git a/source/spirv_target_env.cpp b/source/spirv_target_env.cpp
index 66856a0..86f2c8d 100644
--- a/source/spirv_target_env.cpp
+++ b/source/spirv_target_env.cpp
@@ -66,6 +66,8 @@
return "SPIR-V 1.4";
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
return "SPIR-V 1.4 (under Vulkan 1.1 semantics)";
+ case SPV_ENV_UNIVERSAL_1_5:
+ return "SPIR-V 1.5";
}
return "";
}
@@ -99,6 +101,8 @@
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
return SPV_SPIRV_VERSION_WORD(1, 4);
+ case SPV_ENV_UNIVERSAL_1_5:
+ return SPV_SPIRV_VERSION_WORD(1, 5);
}
return SPV_SPIRV_VERSION_WORD(0, 0);
}
@@ -112,6 +116,7 @@
{"spv1.2", SPV_ENV_UNIVERSAL_1_2},
{"spv1.3", SPV_ENV_UNIVERSAL_1_3},
{"spv1.4", SPV_ENV_UNIVERSAL_1_4},
+ {"spv1.5", SPV_ENV_UNIVERSAL_1_5},
{"opencl1.2embedded", SPV_ENV_OPENCL_EMBEDDED_1_2},
{"opencl1.2", SPV_ENV_OPENCL_1_2},
{"opencl2.0embedded", SPV_ENV_OPENCL_EMBEDDED_2_0},
@@ -165,6 +170,7 @@
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;
case SPV_ENV_VULKAN_1_0:
case SPV_ENV_VULKAN_1_1:
@@ -190,6 +196,7 @@
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:
return false;
case SPV_ENV_OPENCL_1_2:
case SPV_ENV_OPENCL_EMBEDDED_1_2:
@@ -227,6 +234,7 @@
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:
return false;
case SPV_ENV_WEBGPU_0:
return true;
@@ -253,6 +261,7 @@
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:
return false;
case SPV_ENV_OPENGL_4_0:
case SPV_ENV_OPENGL_4_1:
@@ -299,7 +308,8 @@
case SPV_ENV_UNIVERSAL_1_1:
case SPV_ENV_UNIVERSAL_1_2:
case SPV_ENV_UNIVERSAL_1_3:
- case SPV_ENV_UNIVERSAL_1_4: {
+ case SPV_ENV_UNIVERSAL_1_4:
+ case SPV_ENV_UNIVERSAL_1_5: {
return "Universal";
}
}
diff --git a/source/table.cpp b/source/table.cpp
index 7890305..b7a96cc 100644
--- a/source/table.cpp
+++ b/source/table.cpp
@@ -40,6 +40,7 @@
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:
break;
default:
return nullptr;
diff --git a/source/text.cpp b/source/text.cpp
index 9eadf73..d88d4f7 100644
--- a/source/text.cpp
+++ b/source/text.cpp
@@ -546,6 +546,11 @@
<< "Expected <result-id> at the beginning of an instruction, found '"
<< firstWord << "'.";
}
+ if (!opcodeEntry->hasResult && !result_id.empty()) {
+ return context->diagnostic()
+ << "Cannot set ID " << result_id << " because " << opcodeName
+ << " does not produce a result ID.";
+ }
pInst->opcode = opcodeEntry->opcode;
context->setPosition(nextPosition);
// Reserve the first word for the instruction.
@@ -805,7 +810,8 @@
}
void spvTextDestroy(spv_text text) {
- if (!text) return;
- delete[] text->str;
- delete text;
+ if (text) {
+ if (text->str) delete[] text->str;
+ delete text;
+ }
}
diff --git a/source/util/bitutils.h b/source/util/bitutils.h
index 17d61df..9ced2f9 100644
--- a/source/util/bitutils.h
+++ b/source/util/bitutils.h
@@ -15,8 +15,10 @@
#ifndef SOURCE_UTIL_BITUTILS_H_
#define SOURCE_UTIL_BITUTILS_H_
+#include <cassert>
#include <cstdint>
#include <cstring>
+#include <type_traits>
namespace spvtools {
namespace utils {
@@ -31,6 +33,14 @@
return dest;
}
+// Calculates the bit width of the integer type |T|.
+template <typename T>
+struct IntegerBitWidth {
+ static_assert(std::is_integral<T>::value, "Integer type required");
+ static const size_t kBitsPerByte = 8;
+ static const size_t get = sizeof(T) * kBitsPerByte;
+};
+
// SetBits<T, First, Num> returns an integer of type <T> with bits set
// for position <First> through <First + Num - 1>, counting from the least
// significant bit. In particular when Num == 0, no positions are set to 1.
@@ -38,7 +48,7 @@
// a bit that will not fit in the underlying type is set.
template <typename T, size_t First = 0, size_t Num = 0>
struct SetBits {
- static_assert(First < sizeof(T) * 8,
+ static_assert(First < IntegerBitWidth<T>::get,
"Tried to set a bit that is shifted too far.");
const static T get = (T(1) << First) | SetBits<T, First + 1, Num - 1>::get;
};
@@ -49,6 +59,11 @@
};
// This is all compile-time so we can put our tests right here.
+static_assert(IntegerBitWidth<uint32_t>::get == 32, "IntegerBitWidth mismatch");
+static_assert(IntegerBitWidth<int32_t>::get == 32, "IntegerBitWidth mismatch");
+static_assert(IntegerBitWidth<uint64_t>::get == 64, "IntegerBitWidth mismatch");
+static_assert(IntegerBitWidth<uint8_t>::get == 8, "IntegerBitWidth mismatch");
+
static_assert(SetBits<uint32_t, 0, 0>::get == uint32_t(0x00000000),
"SetBits failed");
static_assert(SetBits<uint32_t, 0, 1>::get == uint32_t(0x00000001),
@@ -90,6 +105,82 @@
return count;
}
+// Checks if the bit at the |position| is set to '1'.
+// Bits zero-indexed starting at the least significant bit.
+// |position| must be within the bit width of |T|.
+template <typename T>
+bool IsBitAtPositionSet(T word, size_t position) {
+ static_assert(std::is_integral<T>::value, "Integer type required");
+ static_assert(std::is_unsigned<T>::value, "Unsigned type required");
+ assert(position < IntegerBitWidth<T>::get &&
+ "position must be less than the bit width");
+ return word & T(T(1) << position);
+}
+
+// Returns a value obtained by setting a range of adjacent bits of |word| to
+// |value|. Affected bits are within the range:
+// [first_position, first_position + num_bits_to_mutate),
+// assuming zero-based indexing starting at the least
+// significant bit. Bits to mutate must be within the bit width of |T|.
+template <typename T>
+T MutateBits(T word, size_t first_position, size_t num_bits_to_mutate,
+ bool value) {
+ static_assert(std::is_integral<T>::value, "Integer type required");
+ static_assert(std::is_unsigned<T>::value, "Unsigned type required");
+ static const size_t word_bit_width = IntegerBitWidth<T>::get;
+ assert(first_position < word_bit_width &&
+ "Mutated bits must be within bit width");
+ assert(first_position + num_bits_to_mutate <= word_bit_width &&
+ "Mutated bits must be within bit width");
+ if (num_bits_to_mutate == 0) {
+ return word;
+ }
+
+ const T all_ones = ~T(0);
+ const size_t num_unaffected_low_bits = first_position;
+ const T unaffected_low_mask =
+ T(T(all_ones >> num_unaffected_low_bits) << num_unaffected_low_bits);
+
+ const size_t num_unaffected_high_bits =
+ word_bit_width - (first_position + num_bits_to_mutate);
+ const T unaffected_high_mask =
+ T(T(all_ones << num_unaffected_high_bits) >> num_unaffected_high_bits);
+
+ const T mutation_mask = unaffected_low_mask & unaffected_high_mask;
+ if (value) {
+ return word | mutation_mask;
+ }
+ return word & T(~mutation_mask);
+}
+
+// Returns a value obtained by setting the |num_bits_to_set| highest bits to
+// '1'. |num_bits_to_set| must be not be greater than the bit width of |T|.
+template <typename T>
+T SetHighBits(T word, size_t num_bits_to_set) {
+ if (num_bits_to_set == 0) {
+ return word;
+ }
+ const size_t word_bit_width = IntegerBitWidth<T>::get;
+ assert(num_bits_to_set <= word_bit_width &&
+ "Can't set more bits than bit width");
+ return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set,
+ true);
+}
+
+// Returns a value obtained by setting the |num_bits_to_set| highest bits to
+// '0'. |num_bits_to_set| must be not be greater than the bit width of |T|.
+template <typename T>
+T ClearHighBits(T word, size_t num_bits_to_set) {
+ if (num_bits_to_set == 0) {
+ return word;
+ }
+ const size_t word_bit_width = IntegerBitWidth<T>::get;
+ assert(num_bits_to_set <= word_bit_width &&
+ "Can't clear more bits than bit width");
+ return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set,
+ false);
+}
+
} // namespace utils
} // namespace spvtools
diff --git a/source/val/validate.cpp b/source/val/validate.cpp
index 6f1a26c..7f4b0dc 100644
--- a/source/val/validate.cpp
+++ b/source/val/validate.cpp
@@ -272,6 +272,7 @@
return error;
}
+ std::vector<Instruction*> visited_entry_points;
for (auto& instruction : vstate->ordered_instructions()) {
{
// In order to do this work outside of Process Instruction we need to be
@@ -293,6 +294,24 @@
vstate->RegisterEntryPoint(entry_point, execution_model,
std::move(desc));
+
+ if (visited_entry_points.size() > 0) {
+ for (const Instruction* check_inst : visited_entry_points) {
+ const auto check_execution_model =
+ check_inst->GetOperandAs<SpvExecutionModel>(0);
+ const char* check_str = reinterpret_cast<const char*>(
+ check_inst->words().data() + inst->operand(2).offset);
+ const std::string check_name(check_str);
+
+ if (desc.name == check_name &&
+ execution_model == check_execution_model) {
+ return vstate->diag(SPV_ERROR_INVALID_DATA, inst)
+ << "2 Entry points cannot share the same name and "
+ "ExecutionMode.";
+ }
+ }
+ }
+ visited_entry_points.push_back(inst);
}
if (inst->opcode() == SpvOpFunctionCall) {
if (!vstate->in_function_body()) {
@@ -324,7 +343,6 @@
}
if (auto error = CapabilityPass(*vstate, &instruction)) return error;
- if (auto error = DataRulesPass(*vstate, &instruction)) return error;
if (auto error = ModuleLayoutPass(*vstate, &instruction)) return error;
if (auto error = CfgPass(*vstate, &instruction)) return error;
if (auto error = InstructionPass(*vstate, &instruction)) return error;
@@ -333,6 +351,9 @@
{
Instruction* inst = const_cast<Instruction*>(&instruction);
vstate->RegisterInstruction(inst);
+ if (inst->opcode() == SpvOpTypeForwardPointer) {
+ vstate->RegisterForwardPointer(inst->GetOperandAs<uint32_t>(0));
+ }
}
}
diff --git a/source/val/validate.h b/source/val/validate.h
index b6c4072..31a775b 100644
--- a/source/val/validate.h
+++ b/source/val/validate.h
@@ -123,11 +123,6 @@
/// Performs Id and SSA validation of a module
spv_result_t IdPass(ValidationState_t& _, Instruction* inst);
-/// Performs validation of the Data Rules subsection of 2.16.1 Universal
-/// Validation Rules.
-/// TODO(ehsann): add more comments here as more validation code is added.
-spv_result_t DataRulesPass(ValidationState_t& _, const Instruction* inst);
-
/// Performs instruction validation.
spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst);
@@ -208,7 +203,7 @@
spv_result_t ValidateExecutionLimitations(ValidationState_t& _,
const Instruction* inst);
-/// Validates restricted uses of 8- and 16-bit types.
+/// Validates restricted uses of 8- and 16-bit types.
///
/// Validates shaders that uses 8- or 16-bit storage capabilities, but not full
/// capabilities only have appropriate uses of those types.
diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp
index a9bf716..7623d49 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -2504,20 +2504,20 @@
switch (execution_model) {
case SpvExecutionModelGeometry:
case SpvExecutionModelFragment:
- case SpvExecutionModelMeshNV: {
+ case SpvExecutionModelMeshNV:
// Ok.
break;
- case SpvExecutionModelVertex:
- case SpvExecutionModelTessellationEvaluation:
- if (!_.HasCapability(SpvCapabilityShaderViewportIndexLayerEXT)) {
- return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "Using BuiltIn "
- << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
- decoration.params()[0])
- << " in Vertex or Tessellation execution model requires "
- "the ShaderViewportIndexLayerEXT capability.";
- }
- break;
+ case SpvExecutionModelVertex:
+ case SpvExecutionModelTessellationEvaluation: {
+ if (!_.HasCapability(SpvCapabilityShaderViewportIndexLayerEXT)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
+ << "Using BuiltIn "
+ << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+ decoration.params()[0])
+ << " in Vertex or Tessellation execution model requires "
+ "the ShaderViewportIndexLayerEXT capability.";
+ }
+ break;
}
default: {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
@@ -2901,6 +2901,26 @@
const Decoration& decoration, const Instruction& inst) {
const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
+ // Builtins can only be applied to variables, structures or constants.
+ auto target_opcode = inst.opcode();
+ if (target_opcode != SpvOpTypeStruct && target_opcode != SpvOpVariable &&
+ !spvOpcodeIsConstant(target_opcode)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+ << "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.
+ //
+ // 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.
+ return SPV_SUCCESS;
+ }
+
if (spvIsWebGPUEnv(_.context()->target_env) &&
!IsBuiltInValidForWebGPU(label)) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
@@ -3156,18 +3176,6 @@
// Validates correctness of built-in variables.
spv_result_t ValidateBuiltIns(ValidationState_t& _) {
- if (!spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
- // Early return. All currently implemented rules are based on Vulkan or
- // WebGPU 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.
- return SPV_SUCCESS;
- }
-
BuiltInsValidator validator(_);
return validator.Run();
}
diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp
index 8d8839e..4801fc5 100644
--- a/source/val/validate_cfg.cpp
+++ b/source/val/validate_cfg.cpp
@@ -590,9 +590,68 @@
return SPV_SUCCESS;
}
+// Validates that all CFG divergences (i.e. conditional branch or switch) are
+// structured correctly. Either divergence is preceded by a merge instruction
+// or the divergence introduces at most one unseen label.
+spv_result_t ValidateStructuredSelections(
+ ValidationState_t& _, const std::vector<const BasicBlock*>& postorder) {
+ std::unordered_set<uint32_t> seen;
+ for (auto iter = postorder.rbegin(); iter != postorder.rend(); ++iter) {
+ const auto* block = *iter;
+ const auto* terminator = block->terminator();
+ if (!terminator) continue;
+ const auto index = terminator - &_.ordered_instructions()[0];
+ auto* merge = &_.ordered_instructions()[index - 1];
+ // Marks merges and continues as seen.
+ if (merge->opcode() == SpvOpSelectionMerge) {
+ seen.insert(merge->GetOperandAs<uint32_t>(0));
+ } else if (merge->opcode() == SpvOpLoopMerge) {
+ seen.insert(merge->GetOperandAs<uint32_t>(0));
+ seen.insert(merge->GetOperandAs<uint32_t>(1));
+ } else {
+ // Only track the pointer if it is a merge instruction.
+ merge = nullptr;
+ }
+
+ // Skip unreachable blocks.
+ if (!block->reachable()) continue;
+
+ if (terminator->opcode() == SpvOpBranchConditional) {
+ const auto true_label = terminator->GetOperandAs<uint32_t>(1);
+ const auto false_label = terminator->GetOperandAs<uint32_t>(2);
+ // Mark the upcoming blocks as seen now, but only error out if this block
+ // was missing a merge instruction and both labels hadn't been seen
+ // previously.
+ const bool both_unseen =
+ seen.insert(true_label).second && seen.insert(false_label).second;
+ if (!merge && both_unseen) {
+ return _.diag(SPV_ERROR_INVALID_CFG, terminator)
+ << "Selection must be structured";
+ }
+ } else if (terminator->opcode() == SpvOpSwitch) {
+ uint32_t count = 0;
+ // Mark the targets as seen now, but only error out if this block was
+ // missing a merge instruction and there were multiple unseen labels.
+ for (uint32_t i = 1; i < terminator->operands().size(); i += 2) {
+ const auto target = terminator->GetOperandAs<uint32_t>(i);
+ if (seen.insert(target).second) {
+ count++;
+ }
+ }
+ if (!merge && count > 1) {
+ return _.diag(SPV_ERROR_INVALID_CFG, terminator)
+ << "Selection must be structured";
+ }
+ }
+ }
+
+ return SPV_SUCCESS;
+}
+
spv_result_t StructuredControlFlowChecks(
ValidationState_t& _, Function* function,
- const std::vector<std::pair<uint32_t, uint32_t>>& back_edges) {
+ const std::vector<std::pair<uint32_t, uint32_t>>& back_edges,
+ const std::vector<const BasicBlock*>& postorder) {
/// Check all backedges target only loop headers and have exactly one
/// back-edge branching to it
@@ -709,6 +768,10 @@
}
}
+ if (auto error = ValidateStructuredSelections(_, postorder)) {
+ return error;
+ }
+
return SPV_SUCCESS;
}
@@ -931,7 +994,8 @@
/// Structured control flow checks are only required for shader capabilities
if (_.HasCapability(SpvCapabilityShader)) {
- if (auto error = StructuredControlFlowChecks(_, &function, back_edges))
+ if (auto error =
+ StructuredControlFlowChecks(_, &function, back_edges, postorder))
return error;
}
}
diff --git a/source/val/validate_composites.cpp b/source/val/validate_composites.cpp
index 9b7f592..eb8a324 100644
--- a/source/val/validate_composites.cpp
+++ b/source/val/validate_composites.cpp
@@ -30,8 +30,8 @@
// OpCompositeInsert instruction. The function traverses the hierarchy of
// nested data structures (structs, arrays, vectors, matrices) as directed by
// the sequence of indices in the instruction. May return error if traversal
-// fails (encountered non-composite, out of bounds, nesting too deep).
-// Returns the type of Composite operand if the instruction has no indices.
+// fails (encountered non-composite, out of bounds, no indices, nesting too
+// deep).
spv_result_t GetExtractInsertValueType(ValidationState_t& _,
const Instruction* inst,
uint32_t* member_type) {
@@ -40,10 +40,15 @@
uint32_t word_index = opcode == SpvOpCompositeExtract ? 4 : 5;
const uint32_t num_words = static_cast<uint32_t>(inst->words().size());
const uint32_t composite_id_index = word_index - 1;
-
const uint32_t num_indices = num_words - word_index;
const uint32_t kCompositeExtractInsertMaxNumIndices = 255;
- if (num_indices > kCompositeExtractInsertMaxNumIndices) {
+
+ if (num_indices == 0) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected at least one index to Op"
+ << spvOpcodeString(inst->opcode()) << ", zero found";
+
+ } else if (num_indices > kCompositeExtractInsertMaxNumIndices) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "The number of indexes in Op" << spvOpcodeString(opcode)
<< " may not exceed " << kCompositeExtractInsertMaxNumIndices
@@ -386,20 +391,20 @@
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Cannot extract from a composite of 8- or 16-bit types";
}
+
return SPV_SUCCESS;
}
spv_result_t ValidateCompositeInsert(ValidationState_t& _,
const Instruction* inst) {
- const SpvOp opcode = inst->opcode();
const uint32_t object_type = _.GetOperandTypeId(inst, 2);
const uint32_t composite_type = _.GetOperandTypeId(inst, 3);
const uint32_t result_type = inst->type_id();
if (result_type != composite_type) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "The Result Type must be the same as Composite type in Op"
- << spvOpcodeString(opcode) << " yielding Result Id " << result_type
- << ".";
+ << spvOpcodeString(inst->opcode()) << " yielding Result Id "
+ << result_type << ".";
}
uint32_t member_type = 0;
@@ -421,6 +426,7 @@
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Cannot insert into a composite of 8- or 16-bit types";
}
+
return SPV_SUCCESS;
}
diff --git a/source/val/validate_constants.cpp b/source/val/validate_constants.cpp
index 565518b..dea95c8 100644
--- a/source/val/validate_constants.cpp
+++ b/source/val/validate_constants.cpp
@@ -304,7 +304,6 @@
case SpvOpTypeBool:
case SpvOpTypeInt:
case SpvOpTypeFloat:
- case SpvOpTypePointer:
case SpvOpTypeEvent:
case SpvOpTypeDeviceEvent:
case SpvOpTypeReserveId:
@@ -325,6 +324,11 @@
}
return true;
}
+ case SpvOpTypePointer:
+ if (instruction[2] == SpvStorageClassPhysicalStorageBuffer) {
+ return false;
+ }
+ return true;
default:
return false;
}
@@ -342,6 +346,21 @@
return SPV_SUCCESS;
}
+// Validates that OpSpecConstant specializes to either int or float type.
+spv_result_t ValidateSpecConstant(ValidationState_t& _,
+ const Instruction* inst) {
+ // Operand 0 is the <id> of the type that we're specializing to.
+ auto type_id = inst->GetOperandAs<const uint32_t>(0);
+ auto type_instruction = _.FindDef(type_id);
+ auto type_opcode = type_instruction->opcode();
+ if (type_opcode != SpvOpTypeInt && type_opcode != SpvOpTypeFloat) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Specialization constant "
+ "must be an integer or "
+ "floating-point number.";
+ }
+ return SPV_SUCCESS;
+}
+
spv_result_t ValidateSpecConstantOp(ValidationState_t& _,
const Instruction* inst) {
const auto op = inst->GetOperandAs<SpvOp>(2);
@@ -422,6 +441,9 @@
case SpvOpConstantNull:
if (auto error = ValidateConstantNull(_, inst)) return error;
break;
+ case SpvOpSpecConstant:
+ if (auto error = ValidateSpecConstant(_, inst)) return error;
+ break;
case SpvOpSpecConstantOp:
if (auto error = ValidateSpecConstantOp(_, inst)) return error;
break;
diff --git a/source/val/validate_conversion.cpp b/source/val/validate_conversion.cpp
index f7eb881..0060d0b 100644
--- a/source/val/validate_conversion.cpp
+++ b/source/val/validate_conversion.cpp
@@ -18,6 +18,7 @@
#include "source/diagnostic.h"
#include "source/opcode.h"
+#include "source/spirv_constant.h"
#include "source/val/instruction.h"
#include "source/val/validation_state.h"
@@ -467,15 +468,40 @@
<< "Expected input to be a pointer or int or float vector "
<< "or scalar: " << spvOpcodeString(opcode);
- if (result_is_pointer && !input_is_pointer && !input_is_int_scalar)
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected input to be a pointer or int scalar if Result Type "
- << "is pointer: " << spvOpcodeString(opcode);
+ if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) ||
+ _.HasExtension(kSPV_KHR_physical_storage_buffer)) {
+ const bool result_is_int_vector = _.IsIntVectorType(result_type);
+ const bool result_has_int32 =
+ _.ContainsSizedIntOrFloatType(result_type, SpvOpTypeInt, 32);
+ const bool input_is_int_vector = _.IsIntVectorType(input_type);
+ const bool input_has_int32 =
+ _.ContainsSizedIntOrFloatType(input_type, SpvOpTypeInt, 32);
+ if (result_is_pointer && !input_is_pointer && !input_is_int_scalar &&
+ !(input_is_int_vector && input_has_int32))
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected input to be a pointer, int scalar or 32-bit int "
+ "vector if Result Type is pointer: "
+ << spvOpcodeString(opcode);
- if (input_is_pointer && !result_is_pointer && !result_is_int_scalar)
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Pointer can only be converted to another pointer or int "
- << "scalar: " << spvOpcodeString(opcode);
+ if (input_is_pointer && !result_is_pointer && !result_is_int_scalar &&
+ !(result_is_int_vector && result_has_int32))
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Pointer can only be converted to another pointer, int "
+ "scalar or 32-bit int vector: "
+ << spvOpcodeString(opcode);
+ } else {
+ if (result_is_pointer && !input_is_pointer && !input_is_int_scalar)
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected input to be a pointer or int scalar if Result "
+ "Type is pointer: "
+ << spvOpcodeString(opcode);
+
+ if (input_is_pointer && !result_is_pointer && !result_is_int_scalar)
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Pointer can only be converted to another pointer or int "
+ "scalar: "
+ << spvOpcodeString(opcode);
+ }
if (!result_is_pointer && !input_is_pointer) {
const uint32_t result_size =
diff --git a/source/val/validate_datarules.cpp b/source/val/validate_datarules.cpp
deleted file mode 100644
index 826eb8d..0000000
--- a/source/val/validate_datarules.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright (c) 2016 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Ensures Data Rules are followed according to the specifications.
-
-#include "source/val/validate.h"
-
-#include <cassert>
-#include <sstream>
-#include <string>
-
-#include "source/diagnostic.h"
-#include "source/opcode.h"
-#include "source/operand.h"
-#include "source/val/instruction.h"
-#include "source/val/validation_state.h"
-
-namespace spvtools {
-namespace val {
-namespace {
-
-// Validates that the number of components in the vector is valid.
-// Vector types can only be parameterized as having 2, 3, or 4 components.
-// If the Vector16 capability is added, 8 and 16 components are also allowed.
-spv_result_t ValidateVecNumComponents(ValidationState_t& _,
- const Instruction* inst) {
- // Operand 2 specifies the number of components in the vector.
- auto num_components = inst->GetOperandAs<const uint32_t>(2);
- if (num_components == 2 || num_components == 3 || num_components == 4) {
- return SPV_SUCCESS;
- }
- if (num_components == 8 || num_components == 16) {
- if (_.HasCapability(SpvCapabilityVector16)) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Having " << num_components << " components for "
- << spvOpcodeString(inst->opcode())
- << " requires the Vector16 capability";
- }
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Illegal number of components (" << num_components << ") for "
- << spvOpcodeString(inst->opcode());
-}
-
-// Validates that the number of bits specifed for a float type is valid.
-// Scalar floating-point types can be parameterized only with 32-bits.
-// Float16 capability allows using a 16-bit OpTypeFloat.
-// Float16Buffer capability allows creation of a 16-bit OpTypeFloat.
-// Float64 capability allows using a 64-bit OpTypeFloat.
-spv_result_t ValidateFloatSize(ValidationState_t& _, const Instruction* inst) {
- // Operand 1 is the number of bits for this float
- auto num_bits = inst->GetOperandAs<const uint32_t>(1);
- if (num_bits == 32) {
- return SPV_SUCCESS;
- }
- if (num_bits == 16) {
- if (_.features().declare_float16_type) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Using a 16-bit floating point "
- << "type requires the Float16 or Float16Buffer capability,"
- " or an extension that explicitly enables 16-bit floating point.";
- }
- if (num_bits == 64) {
- if (_.HasCapability(SpvCapabilityFloat64)) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Using a 64-bit floating point "
- << "type requires the Float64 capability.";
- }
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Invalid number of bits (" << num_bits << ") used for OpTypeFloat.";
-}
-
-// Validates that the number of bits specified for an Int type is valid.
-// Scalar integer types can be parameterized only with 32-bits.
-// Int8, Int16, and Int64 capabilities allow using 8-bit, 16-bit, and 64-bit
-// integers, respectively.
-spv_result_t ValidateIntSize(ValidationState_t& _, const Instruction* inst) {
- // Operand 1 is the number of bits for this integer.
- auto num_bits = inst->GetOperandAs<const uint32_t>(1);
- if (num_bits == 32) {
- return SPV_SUCCESS;
- }
- if (num_bits == 8) {
- if (_.features().declare_int8_type) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Using an 8-bit integer type requires the Int8 capability,"
- " or an extension that explicitly enables 8-bit integers.";
- }
- if (num_bits == 16) {
- if (_.features().declare_int16_type) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Using a 16-bit integer type requires the Int16 capability,"
- " or an extension that explicitly enables 16-bit integers.";
- }
- if (num_bits == 64) {
- if (_.HasCapability(SpvCapabilityInt64)) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Using a 64-bit integer type requires the Int64 capability.";
- }
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Invalid number of bits (" << num_bits << ") used for OpTypeInt.";
-}
-
-// Validates that the matrix is parameterized with floating-point types.
-spv_result_t ValidateMatrixColumnType(ValidationState_t& _,
- const Instruction* inst) {
- // Find the component type of matrix columns (must be vector).
- // Operand 1 is the <id> of the type specified for matrix columns.
- auto type_id = inst->GetOperandAs<const uint32_t>(1);
- auto col_type_instr = _.FindDef(type_id);
- if (col_type_instr->opcode() != SpvOpTypeVector) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "Columns in a matrix must be of type vector.";
- }
-
- // Trace back once more to find out the type of components in the vector.
- // Operand 1 is the <id> of the type of data in the vector.
- auto comp_type_id =
- col_type_instr->words()[col_type_instr->operands()[1].offset];
- auto comp_type_instruction = _.FindDef(comp_type_id);
- if (comp_type_instruction->opcode() != SpvOpTypeFloat) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Matrix types can only be "
- "parameterized with "
- "floating-point types.";
- }
- return SPV_SUCCESS;
-}
-
-// Validates that the matrix has 2,3, or 4 columns.
-spv_result_t ValidateMatrixNumCols(ValidationState_t& _,
- const Instruction* inst) {
- // Operand 2 is the number of columns in the matrix.
- auto num_cols = inst->GetOperandAs<const uint32_t>(2);
- if (num_cols != 2 && num_cols != 3 && num_cols != 4) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Matrix types can only be "
- "parameterized as having "
- "only 2, 3, or 4 columns.";
- }
- return SPV_SUCCESS;
-}
-
-// Validates that OpSpecConstant specializes to either int or float type.
-spv_result_t ValidateSpecConstNumerical(ValidationState_t& _,
- const Instruction* inst) {
- // Operand 0 is the <id> of the type that we're specializing to.
- auto type_id = inst->GetOperandAs<const uint32_t>(0);
- auto type_instruction = _.FindDef(type_id);
- auto type_opcode = type_instruction->opcode();
- if (type_opcode != SpvOpTypeInt && type_opcode != SpvOpTypeFloat) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Specialization constant "
- "must be an integer or "
- "floating-point number.";
- }
- return SPV_SUCCESS;
-}
-
-// Validates that OpSpecConstantTrue and OpSpecConstantFalse specialize to bool.
-spv_result_t ValidateSpecConstBoolean(ValidationState_t& _,
- const Instruction* inst) {
- // Find out the type that we're specializing to.
- auto type_instruction = _.FindDef(inst->type_id());
- if (type_instruction->opcode() != SpvOpTypeBool) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "Specialization constant must be a boolean type.";
- }
- return SPV_SUCCESS;
-}
-
-// Records the <id> of the forward pointer to be used for validation.
-spv_result_t ValidateForwardPointer(ValidationState_t& _,
- const Instruction* inst) {
- // Record the <id> (which is operand 0) to ensure it's used properly.
- // OpTypeStruct can only include undefined pointers that are
- // previously declared as a ForwardPointer
- return (_.RegisterForwardPointer(inst->GetOperandAs<uint32_t>(0)));
-}
-
-// Validates that any undefined component of the struct is a forward pointer.
-// It is valid to declare a forward pointer, and use its <id> as one of the
-// components of a struct.
-spv_result_t ValidateStruct(ValidationState_t& _, const Instruction* inst) {
- // Struct components are operands 1, 2, etc.
- for (unsigned i = 1; i < inst->operands().size(); i++) {
- auto type_id = inst->GetOperandAs<const uint32_t>(i);
- auto type_instruction = _.FindDef(type_id);
- if (type_instruction == nullptr && !_.IsForwardPointer(type_id)) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "Forward reference operands in an OpTypeStruct must first be "
- "declared using OpTypeForwardPointer.";
- }
- }
- return SPV_SUCCESS;
-}
-
-// Validates that any undefined type of the array is a forward pointer.
-// It is valid to declare a forward pointer, and use its <id> as the element
-// type of the array.
-spv_result_t ValidateArray(ValidationState_t& _, const Instruction* inst) {
- auto element_type_id = inst->GetOperandAs<const uint32_t>(1);
- auto element_type_instruction = _.FindDef(element_type_id);
- if (element_type_instruction == nullptr &&
- !_.IsForwardPointer(element_type_id)) {
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "Forward reference operands in an OpTypeArray must first be "
- "declared using OpTypeForwardPointer.";
- }
- return SPV_SUCCESS;
-}
-
-} // namespace
-
-// Validates that Data Rules are followed according to the specifications.
-// (Data Rules subsection of 2.16.1 Universal Validation Rules)
-spv_result_t DataRulesPass(ValidationState_t& _, const Instruction* inst) {
- switch (inst->opcode()) {
- case SpvOpTypeVector: {
- if (auto error = ValidateVecNumComponents(_, inst)) return error;
- break;
- }
- case SpvOpTypeFloat: {
- if (auto error = ValidateFloatSize(_, inst)) return error;
- break;
- }
- case SpvOpTypeInt: {
- if (auto error = ValidateIntSize(_, inst)) return error;
- break;
- }
- case SpvOpTypeMatrix: {
- if (auto error = ValidateMatrixColumnType(_, inst)) return error;
- if (auto error = ValidateMatrixNumCols(_, inst)) return error;
- break;
- }
- // TODO(ehsan): Add OpSpecConstantComposite validation code.
- // TODO(ehsan): Add OpSpecConstantOp validation code (if any).
- case SpvOpSpecConstant: {
- if (auto error = ValidateSpecConstNumerical(_, inst)) return error;
- break;
- }
- case SpvOpSpecConstantFalse:
- case SpvOpSpecConstantTrue: {
- if (auto error = ValidateSpecConstBoolean(_, inst)) return error;
- break;
- }
- case SpvOpTypeForwardPointer: {
- if (auto error = ValidateForwardPointer(_, inst)) return error;
- break;
- }
- case SpvOpTypeStruct: {
- if (auto error = ValidateStruct(_, inst)) return error;
- break;
- }
- case SpvOpTypeArray: {
- if (auto error = ValidateArray(_, inst)) return error;
- break;
- }
- // TODO(ehsan): add more data rules validation here.
- default: { break; }
- }
-
- return SPV_SUCCESS;
-}
-
-} // namespace val
-} // namespace spvtools
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index 3323961..d513a25 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -522,10 +522,13 @@
const auto typeId = array_inst->word(2);
const auto element_inst = vstate.FindDef(typeId);
// Check array stride.
- auto array_stride = 0;
+ uint32_t array_stride = 0;
for (auto& decoration : vstate.id_decorations(array_inst->id())) {
if (SpvDecorationArrayStride == decoration.dec_type()) {
array_stride = decoration.params()[0];
+ if (array_stride == 0) {
+ return fail(memberIdx) << "contains an array with stride 0";
+ }
if (!IsAlignedTo(array_stride, array_alignment))
return fail(memberIdx)
<< "contains an array with stride " << decoration.params()[0]
@@ -563,6 +566,14 @@
? getScalarAlignment(array_inst->id(), vstate)
: getBaseAlignment(array_inst->id(), blockRules,
constraint, constraints, vstate);
+
+ const auto element_size =
+ getSize(element_inst->id(), constraint, constraints, vstate);
+ if (element_size > array_stride) {
+ return fail(memberIdx)
+ << "contains an array with stride " << array_stride
+ << ", but with an element size of " << element_size;
+ }
}
nextValidOffset = offset + size;
if (!scalar_block_layout && blockRules &&
@@ -942,6 +953,7 @@
id = id_inst->GetOperandAs<uint32_t>(1u);
id_inst = vstate.FindDef(id);
}
+ // Struct requirement is checked on variables so just move on here.
if (SpvOpTypeStruct != id_inst->opcode()) continue;
MemberConstraints constraints;
ComputeMemberConstraintsForStruct(&constraints, id, LayoutConstraints(),
@@ -952,15 +964,18 @@
: (push_constant ? "PushConstant" : "StorageBuffer");
if (spvIsVulkanEnv(vstate.context()->target_env)) {
- if (storage_buffer &&
- hasDecoration(id, SpvDecorationBufferBlock, vstate)) {
+ const bool block = hasDecoration(id, SpvDecorationBlock, vstate);
+ const bool buffer_block =
+ hasDecoration(id, SpvDecorationBufferBlock, vstate);
+ if (storage_buffer && buffer_block) {
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
<< "Storage buffer id '" << var_id
<< " In Vulkan, BufferBlock is disallowed on variables in "
"the StorageBuffer storage class";
}
- // Vulkan 14.5.1: Check Block decoration for PushConstant variables.
- if (push_constant && !hasDecoration(id, SpvDecorationBlock, vstate)) {
+ // Vulkan 14.5.1/2: Check Block decoration for PushConstant, Uniform
+ // and StorageBuffer variables. Uniform can also use BufferBlock.
+ if (push_constant && !block) {
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
<< "PushConstant id '" << id
<< "' is missing Block decoration.\n"
@@ -968,6 +983,22 @@
<< "Such variables must be identified with a Block "
"decoration";
}
+ if (storage_buffer && !block) {
+ return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
+ << "StorageBuffer id '" << id
+ << "' is missing Block decoration.\n"
+ << "From Vulkan spec, section 14.5.2:\n"
+ << "Such variables must be identified with a Block "
+ "decoration";
+ }
+ if (uniform && !block && !buffer_block) {
+ return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
+ << "Uniform id '" << id
+ << "' is missing Block or BufferBlock decoration.\n"
+ << "From Vulkan spec, section 14.5.2:\n"
+ << "Such variables must be identified with a Block or "
+ "BufferBlock decoration";
+ }
// Vulkan 14.5.2: Check DescriptorSet and Binding decoration for
// Uniform and StorageBuffer variables.
if (uniform || storage_buffer) {
diff --git a/source/val/validate_derivatives.cpp b/source/val/validate_derivatives.cpp
index b3f046a..067cc96 100644
--- a/source/val/validate_derivatives.cpp
+++ b/source/val/validate_derivatives.cpp
@@ -46,6 +46,10 @@
<< "Expected Result Type to be float scalar or vector type: "
<< spvOpcodeString(opcode);
}
+ if (!_.ContainsSizedIntOrFloatType(result_type, SpvOpTypeFloat, 32)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Result type component width must be 32 bits";
+ }
const uint32_t p_type = _.GetOperandTypeId(inst, 2);
if (p_type != result_type) {
diff --git a/source/val/validate_id.cpp b/source/val/validate_id.cpp
index cb18e13..d80e1b8 100644
--- a/source/val/validate_id.cpp
+++ b/source/val/validate_id.cpp
@@ -191,7 +191,14 @@
ret = SPV_SUCCESS;
}
} else if (can_have_forward_declared_ids(i)) {
- ret = _.ForwardDeclareId(operand_word);
+ if (inst->opcode() == SpvOpTypeStruct &&
+ !_.IsForwardPointer(operand_word)) {
+ ret = _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "Operand " << _.getIdName(operand_word)
+ << " requires a previous definition";
+ } else {
+ ret = _.ForwardDeclareId(operand_word);
+ }
} else {
ret = _.diag(SPV_ERROR_INVALID_ID, inst)
<< "ID " << _.getIdName(operand_word)
diff --git a/source/val/validate_instruction.cpp b/source/val/validate_instruction.cpp
index b74b535..6478b3c 100644
--- a/source/val/validate_instruction.cpp
+++ b/source/val/validate_instruction.cpp
@@ -55,18 +55,6 @@
return ss.str();
}
-bool IsValidWebGPUStorageClass(SpvStorageClass storage_class) {
- return storage_class == SpvStorageClassUniformConstant ||
- storage_class == SpvStorageClassUniform ||
- storage_class == SpvStorageClassStorageBuffer ||
- storage_class == SpvStorageClassInput ||
- storage_class == SpvStorageClassOutput ||
- storage_class == SpvStorageClassImage ||
- storage_class == SpvStorageClassWorkgroup ||
- storage_class == SpvStorageClassPrivate ||
- storage_class == SpvStorageClassFunction;
-}
-
// Returns capabilities that enable an opcode. An empty result is interpreted
// as no prohibition of use of the opcode. If the result is non-empty, then
// the opcode may only be used if at least one of the capabilities is specified
@@ -205,17 +193,24 @@
operand_desc->capabilities, operand_desc->numCapabilities);
}
- if (!state.HasAnyOfCapabilities(enabling_capabilities)) {
- return state.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
- << "Operand " << which_operand << " of "
- << spvOpcodeString(inst->opcode())
- << " requires one of these capabilities: "
- << ToString(enabling_capabilities, state.grammar());
+ // When encountering an OpCapability instruction, the instruction pass
+ // registers a capability with the module *before* checking capabilities.
+ // So in the case of an OpCapability instruction, don't bother checking
+ // enablement by another capability.
+ if (inst->opcode() != SpvOpCapability) {
+ const bool enabled_by_cap =
+ state.HasAnyOfCapabilities(enabling_capabilities);
+ if (!enabling_capabilities.IsEmpty() && !enabled_by_cap) {
+ return state.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
+ << "Operand " << which_operand << " of "
+ << spvOpcodeString(inst->opcode())
+ << " requires one of these capabilities: "
+ << ToString(enabling_capabilities, state.grammar());
+ }
}
return OperandVersionExtensionCheck(state, inst, which_operand,
*operand_desc, word);
}
-
return SPV_SUCCESS;
}
@@ -242,23 +237,6 @@
return SPV_SUCCESS;
}
-// Returns SPV_ERROR_INVALID_BINARY and emits a diagnostic if the instruction
-// is invalid because of an execution environment constraint.
-spv_result_t EnvironmentCheck(ValidationState_t& _, const Instruction* inst) {
- const SpvOp opcode = inst->opcode();
- switch (opcode) {
- case SpvOpUndef:
- if (_.features().bans_op_undef) {
- return _.diag(SPV_ERROR_INVALID_BINARY, inst)
- << "OpUndef is disallowed";
- }
- break;
- default:
- break;
- }
- return SPV_SUCCESS;
-}
-
// Returns SPV_ERROR_INVALID_CAPABILITY and emits a diagnostic if the
// instruction is invalid because the required capability isn't declared
// in the module.
@@ -492,38 +470,6 @@
}
_.set_addressing_model(inst->GetOperandAs<SpvAddressingModel>(0));
_.set_memory_model(inst->GetOperandAs<SpvMemoryModel>(1));
-
- if (_.memory_model() != SpvMemoryModelVulkanKHR &&
- _.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "VulkanMemoryModelKHR capability must only be specified if "
- "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 (_.memory_model() != SpvMemoryModelVulkanKHR) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Memory model must be VulkanKHR for WebGPU environment.";
- }
- }
-
- if (spvIsOpenCLEnv(_.context()->target_env)) {
- if ((_.addressing_model() != SpvAddressingModelPhysical32) &&
- (_.addressing_model() != SpvAddressingModelPhysical64)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Addressing model must be Physical32 or Physical64 "
- << "in the OpenCL environment.";
- }
- if (_.memory_model() != SpvMemoryModelOpenCL) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Memory model must be OpenCL in the OpenCL environment.";
- }
- }
} else if (opcode == SpvOpExecutionMode) {
const uint32_t entry_point = inst->word(1);
_.RegisterExecutionModeForEntryPoint(entry_point,
@@ -533,61 +479,9 @@
if (auto error = LimitCheckNumVars(_, inst->id(), storage_class)) {
return error;
}
-
- if (spvIsWebGPUEnv(_.context()->target_env) &&
- !IsValidWebGPUStorageClass(storage_class)) {
- return _.diag(SPV_ERROR_INVALID_BINARY, inst)
- << "For WebGPU, OpVariable storage class must be one of "
- "UniformConstant, Uniform, StorageBuffer, Input, Output, "
- "Image, Workgroup, Private, Function for WebGPU";
- }
-
- if (storage_class == SpvStorageClassGeneric)
- return _.diag(SPV_ERROR_INVALID_BINARY, inst)
- << "OpVariable storage class cannot be Generic";
- if (_.current_layout_section() == kLayoutFunctionDefinitions) {
- if (storage_class != SpvStorageClassFunction) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Variables must have a function[7] storage class inside"
- " of a function";
- }
- if (_.current_function().IsFirstBlock(
- _.current_function().current_block()->id()) == false) {
- return _.diag(SPV_ERROR_INVALID_CFG, inst)
- << "Variables can only be defined "
- "in the first block of a "
- "function";
- }
- } else {
- if (storage_class == SpvStorageClassFunction) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Variables can not have a function[7] storage class "
- "outside of a function";
- }
- }
- } else if (opcode == SpvOpTypePointer) {
- const auto storage_class = inst->GetOperandAs<SpvStorageClass>(1);
- if (spvIsWebGPUEnv(_.context()->target_env) &&
- !IsValidWebGPUStorageClass(storage_class)) {
- return _.diag(SPV_ERROR_INVALID_BINARY, inst)
- << "For WebGPU, OpTypePointer storage class must be one of "
- "UniformConstant, Uniform, StorageBuffer, Input, Output, "
- "Image, Workgroup, Private, Function";
- }
- }
-
- // SPIR-V Spec 2.16.3: Validation Rules for Kernel Capabilities: The
- // Signedness in OpTypeInt must always be 0.
- if (SpvOpTypeInt == inst->opcode() && _.HasCapability(SpvCapabilityKernel) &&
- inst->GetOperandAs<uint32_t>(2) != 0u) {
- return _.diag(SPV_ERROR_INVALID_BINARY, inst)
- << "The Signedness in OpTypeInt "
- "must always be 0 when Kernel "
- "capability is used.";
}
if (auto error = ReservedCheck(_, inst)) return error;
- if (auto error = EnvironmentCheck(_, inst)) return error;
if (auto error = CapabilityCheck(_, inst)) return error;
if (auto error = LimitCheckIdBound(_, inst)) return error;
if (auto error = LimitCheckStruct(_, inst)) return error;
diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp
index f31c5a0..bff8b20 100644
--- a/source/val/validate_memory.cpp
+++ b/source/val/validate_memory.cpp
@@ -461,6 +461,28 @@
}
}
+ if (!_.IsValidStorageClass(storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_BINARY, inst)
+ << "Invalid storage class for target environment";
+ }
+
+ if (storage_class == SpvStorageClassGeneric) {
+ return _.diag(SPV_ERROR_INVALID_BINARY, inst)
+ << "OpVariable storage class cannot be Generic";
+ }
+
+ if (inst->function() && storage_class != SpvStorageClassFunction) {
+ return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
+ << "Variables must have a function[7] storage class inside"
+ " of a function";
+ }
+
+ if (!inst->function() && storage_class == SpvStorageClassFunction) {
+ return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
+ << "Variables can not have a function[7] storage class "
+ "outside of a function";
+ }
+
// SPIR-V 3.32.8: Check that pointer type and variable type have the same
// storage class.
const auto result_storage_class_index = 1;
@@ -536,6 +558,19 @@
<< "this type";
}
}
+
+ if (storage_class == SpvStorageClassStorageBuffer) {
+ if (!IsAllowedTypeOrArrayOfSame(_, pointee, {SpvOpTypeStruct})) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "StorageBuffer OpVariable <id> '" << _.getIdName(inst->id())
+ << "' has illegal type.\n"
+ << "From Vulkan spec, section 14.5.2:\n"
+ << "Variables identified with the StorageBuffer storage class "
+ "are used to access transparent buffer backed resources. "
+ "Such variables must be typed as OpTypeStruct, or an array "
+ "of this type";
+ }
+ }
}
// WebGPU & Vulkan Appendix A: Check that if contains initializer, then
@@ -1555,8 +1590,8 @@
<< "Operand type must be a pointer";
}
+ SpvStorageClass sc = op1_type->GetOperandAs<SpvStorageClass>(1u);
if (_.addressing_model() == SpvAddressingModelLogical) {
- SpvStorageClass sc = op1_type->GetOperandAs<SpvStorageClass>(1u);
if (sc != SpvStorageClassWorkgroup && sc != SpvStorageClassStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Invalid pointer storage class";
@@ -1567,6 +1602,9 @@
<< "Workgroup storage class pointer requires VariablePointers "
"capability to be specified";
}
+ } else if (sc == SpvStorageClassPhysicalStorageBuffer) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "Cannot use a pointer in the PhysicalStorageBuffer storage class";
}
return SPV_SUCCESS;
diff --git a/source/val/validate_misc.cpp b/source/val/validate_misc.cpp
index 28e3fc6..f0deedf 100644
--- a/source/val/validate_misc.cpp
+++ b/source/val/validate_misc.cpp
@@ -18,6 +18,7 @@
#include "source/opcode.h"
#include "source/spirv_target_env.h"
#include "source/val/instruction.h"
+#include "source/val/validate_scopes.h"
#include "source/val/validation_state.h"
namespace spvtools {
@@ -32,6 +33,42 @@
<< "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;
+}
+
+spv_result_t ValidateShaderClock(ValidationState_t& _,
+ const Instruction* inst) {
+ const uint32_t scope = inst->GetOperandAs<uint32_t>(2);
+ if (auto error = ValidateScope(_, inst, scope)) {
+ return error;
+ }
+
+ bool is_int32 = false, is_const_int32 = false;
+ uint32_t value = 0;
+ 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";
+ }
+
+ // Result Type must be a 64 - bit unsigned integer type or
+ // a vector of two - components of 32 -
+ // bit unsigned integer type
+ const uint32_t result_type = inst->type_id();
+ if (!(_.IsUnsignedIntScalarType(result_type) &&
+ _.GetBitWidth(result_type) == 64) &&
+ !(_.IsUnsignedIntVectorType(result_type) &&
+ _.GetDimension(result_type) == 2 && _.GetBitWidth(result_type) == 32)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Value to be a "
+ "vector of two components"
+ " of unsigned integer"
+ " or 64bit unsigned integer";
+ }
+
return SPV_SUCCESS;
}
@@ -110,6 +147,11 @@
<< spvOpcodeString(inst->opcode());
break;
}
+ case SpvOpReadClockKHR:
+ if (auto error = ValidateShaderClock(_, inst)) {
+ return error;
+ }
+ break;
default:
break;
}
diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp
index cbcf11a..e020f5a 100644
--- a/source/val/validate_mode_setting.cpp
+++ b/source/val/validate_mode_setting.cpp
@@ -485,6 +485,44 @@
return SPV_SUCCESS;
}
+spv_result_t ValidateMemoryModel(ValidationState_t& _,
+ const Instruction* inst) {
+ // Already produced an error if multiple memory model instructions are
+ // present.
+ if (_.memory_model() != SpvMemoryModelVulkanKHR &&
+ _.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "VulkanMemoryModelKHR capability must only be specified if "
+ "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 (_.memory_model() != SpvMemoryModelVulkanKHR) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Memory model must be VulkanKHR for WebGPU environment.";
+ }
+ }
+
+ if (spvIsOpenCLEnv(_.context()->target_env)) {
+ if ((_.addressing_model() != SpvAddressingModelPhysical32) &&
+ (_.addressing_model() != SpvAddressingModelPhysical64)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Addressing model must be Physical32 or Physical64 "
+ << "in the OpenCL environment.";
+ }
+ if (_.memory_model() != SpvMemoryModelOpenCL) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Memory model must be OpenCL in the OpenCL environment.";
+ }
+ }
+
+ return SPV_SUCCESS;
+}
+
} // namespace
spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) {
@@ -496,6 +534,9 @@
case SpvOpExecutionModeId:
if (auto error = ValidateExecutionMode(_, inst)) return error;
break;
+ case SpvOpMemoryModel:
+ if (auto error = ValidateMemoryModel(_, inst)) return error;
+ break;
default:
break;
}
diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp
index 70a65f7..1b98786 100644
--- a/source/val/validate_scopes.cpp
+++ b/source/val/validate_scopes.cpp
@@ -39,8 +39,8 @@
return false;
}
-spv_result_t ValidateExecutionScope(ValidationState_t& _,
- const Instruction* inst, uint32_t scope) {
+spv_result_t ValidateScope(ValidationState_t& _, const Instruction* inst,
+ uint32_t scope) {
SpvOp opcode = inst->opcode();
bool is_int32 = false, is_const_int32 = false;
uint32_t value = 0;
@@ -48,8 +48,7 @@
if (!is_int32) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
- << ": expected Execution Scope to be a 32-bit int";
+ << spvOpcodeString(opcode) << ": expected scope to be a 32-bit int";
}
if (!is_const_int32) {
@@ -66,7 +65,6 @@
<< "Scope ids must be constant or specialization constant when "
<< "CooperativeMatrixNV capability is present";
}
- return SPV_SUCCESS;
}
if (is_const_int32 && !IsValidScope(value)) {
@@ -74,6 +72,24 @@
<< "Invalid scope value:\n " << _.Disassemble(*_.FindDef(scope));
}
+ return SPV_SUCCESS;
+}
+
+spv_result_t ValidateExecutionScope(ValidationState_t& _,
+ const Instruction* inst, uint32_t scope) {
+ SpvOp opcode = inst->opcode();
+ bool is_int32 = false, is_const_int32 = false;
+ uint32_t value = 0;
+ std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope);
+
+ if (auto error = ValidateScope(_, inst, scope)) {
+ return error;
+ }
+
+ if (!is_const_int32) {
+ return SPV_SUCCESS;
+ }
+
// Vulkan specific rules
if (spvIsVulkanEnv(_.context()->target_env)) {
// Vulkan 1.1 specific rules
@@ -152,34 +168,14 @@
uint32_t value = 0;
std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope);
- if (!is_int32) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
- << ": expected Memory Scope to be a 32-bit int";
+ if (auto error = ValidateScope(_, inst, scope)) {
+ return error;
}
if (!is_const_int32) {
- if (_.HasCapability(SpvCapabilityShader) &&
- !_.HasCapability(SpvCapabilityCooperativeMatrixNV)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Scope ids must be OpConstant when Shader capability is "
- << "present";
- }
- if (_.HasCapability(SpvCapabilityShader) &&
- _.HasCapability(SpvCapabilityCooperativeMatrixNV) &&
- !spvOpcodeIsConstant(_.GetIdOpcode(scope))) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Scope ids must be constant or specialization constant when "
- << "CooperativeMatrixNV capability is present";
- }
return SPV_SUCCESS;
}
- if (is_const_int32 && !IsValidScope(value)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Invalid scope value:\n " << _.Disassemble(*_.FindDef(scope));
- }
-
if (value == SpvScopeQueueFamilyKHR) {
if (_.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) {
return SPV_SUCCESS;
diff --git a/source/val/validate_scopes.h b/source/val/validate_scopes.h
index 311ca7f..ba8b301 100644
--- a/source/val/validate_scopes.h
+++ b/source/val/validate_scopes.h
@@ -20,6 +20,9 @@
namespace spvtools {
namespace val {
+spv_result_t ValidateScope(ValidationState_t& _, const Instruction* inst,
+ uint32_t scope);
+
spv_result_t ValidateExecutionScope(ValidationState_t& _,
const Instruction* inst, uint32_t scope);
diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp
index afc0656..4d673b4 100644
--- a/source/val/validate_type.cpp
+++ b/source/val/validate_type.cpp
@@ -67,15 +67,89 @@
}
spv_result_t ValidateTypeInt(ValidationState_t& _, const Instruction* inst) {
+ // Validates that the number of bits specified for an Int type is valid.
+ // Scalar integer types can be parameterized only with 32-bits.
+ // Int8, Int16, and Int64 capabilities allow using 8-bit, 16-bit, and 64-bit
+ // integers, respectively.
+ auto num_bits = inst->GetOperandAs<const uint32_t>(1);
+ if (num_bits != 32) {
+ if (num_bits == 8) {
+ if (_.features().declare_int8_type) {
+ return SPV_SUCCESS;
+ }
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Using an 8-bit integer type requires the Int8 capability,"
+ " or an extension that explicitly enables 8-bit integers.";
+ } else if (num_bits == 16) {
+ if (_.features().declare_int16_type) {
+ return SPV_SUCCESS;
+ }
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Using a 16-bit integer type requires the Int16 capability,"
+ " or an extension that explicitly enables 16-bit integers.";
+ } else if (num_bits == 64) {
+ if (_.HasCapability(SpvCapabilityInt64)) {
+ return SPV_SUCCESS;
+ }
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Using a 64-bit integer type requires the Int64 capability.";
+ } else {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Invalid number of bits (" << num_bits
+ << ") used for OpTypeInt.";
+ }
+ }
+
const auto signedness_index = 2;
const auto signedness = inst->GetOperandAs<uint32_t>(signedness_index);
if (signedness != 0 && signedness != 1) {
return _.diag(SPV_ERROR_INVALID_VALUE, inst)
<< "OpTypeInt has invalid signedness:";
}
+
+ // SPIR-V Spec 2.16.3: Validation Rules for Kernel Capabilities: The
+ // Signedness in OpTypeInt must always be 0.
+ if (SpvOpTypeInt == inst->opcode() && _.HasCapability(SpvCapabilityKernel) &&
+ inst->GetOperandAs<uint32_t>(2) != 0u) {
+ return _.diag(SPV_ERROR_INVALID_BINARY, inst)
+ << "The Signedness in OpTypeInt "
+ "must always be 0 when Kernel "
+ "capability is used.";
+ }
+
return SPV_SUCCESS;
}
+spv_result_t ValidateTypeFloat(ValidationState_t& _, const Instruction* inst) {
+ // Validates that the number of bits specified for an Int type is valid.
+ // Scalar integer types can be parameterized only with 32-bits.
+ // Int8, Int16, and Int64 capabilities allow using 8-bit, 16-bit, and 64-bit
+ // integers, respectively.
+ auto num_bits = inst->GetOperandAs<const uint32_t>(1);
+ if (num_bits == 32) {
+ return SPV_SUCCESS;
+ }
+ if (num_bits == 16) {
+ if (_.features().declare_float16_type) {
+ return SPV_SUCCESS;
+ }
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Using a 16-bit floating point "
+ << "type requires the Float16 or Float16Buffer capability,"
+ " or an extension that explicitly enables 16-bit floating point.";
+ }
+ if (num_bits == 64) {
+ if (_.HasCapability(SpvCapabilityFloat64)) {
+ return SPV_SUCCESS;
+ }
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Using a 64-bit floating point "
+ << "type requires the Float64 capability.";
+ }
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Invalid number of bits (" << num_bits << ") used for OpTypeFloat.";
+}
+
spv_result_t ValidateTypeVector(ValidationState_t& _, const Instruction* inst) {
const auto component_index = 1;
const auto component_id = inst->GetOperandAs<uint32_t>(component_index);
@@ -85,6 +159,27 @@
<< "OpTypeVector Component Type <id> '" << _.getIdName(component_id)
<< "' is not a scalar type.";
}
+
+ // Validates that the number of components in the vector is valid.
+ // Vector types can only be parameterized as having 2, 3, or 4 components.
+ // If the Vector16 capability is added, 8 and 16 components are also allowed.
+ auto num_components = inst->GetOperandAs<const uint32_t>(2);
+ if (num_components == 2 || num_components == 3 || num_components == 4) {
+ return SPV_SUCCESS;
+ } else if (num_components == 8 || num_components == 16) {
+ if (_.HasCapability(SpvCapabilityVector16)) {
+ return SPV_SUCCESS;
+ }
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Having " << num_components << " components for "
+ << spvOpcodeString(inst->opcode())
+ << " requires the Vector16 capability";
+ } else {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Illegal number of components (" << num_components << ") for "
+ << spvOpcodeString(inst->opcode());
+ }
+
return SPV_SUCCESS;
}
@@ -94,9 +189,27 @@
const auto column_type = _.FindDef(column_type_id);
if (!column_type || SpvOpTypeVector != column_type->opcode()) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpTypeMatrix Column Type <id> '" << _.getIdName(column_type_id)
- << "' is not a vector.";
+ << "Columns in a matrix must be of type vector.";
}
+
+ // Trace back once more to find out the type of components in the vector.
+ // Operand 1 is the <id> of the type of data in the vector.
+ const auto comp_type_id = column_type->GetOperandAs<uint32_t>(1);
+ auto comp_type_instruction = _.FindDef(comp_type_id);
+ if (comp_type_instruction->opcode() != SpvOpTypeFloat) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Matrix types can only be "
+ "parameterized with "
+ "floating-point types.";
+ }
+
+ // Validates that the matrix has 2,3, or 4 columns.
+ auto num_cols = inst->GetOperandAs<const uint32_t>(2);
+ if (num_cols != 2 && num_cols != 3 && num_cols != 4) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Matrix types can only be "
+ "parameterized as having "
+ "only 2, 3, or 4 columns.";
+ }
+
return SPV_SUCCESS;
}
@@ -224,6 +337,11 @@
for (size_t member_type_index = 1;
member_type_index < inst->operands().size(); ++member_type_index) {
auto member_type_id = inst->GetOperandAs<uint32_t>(member_type_index);
+ if (member_type_id == inst->id()) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "Structure members may not be self references";
+ }
+
auto member_type = _.FindDef(member_type_id);
if (!member_type || !spvOpcodeGeneratesType(member_type->opcode())) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
@@ -245,22 +363,6 @@
<< " contains structure <id> " << _.getIdName(member_type_id)
<< ".";
}
- if (_.IsForwardPointer(member_type_id)) {
- // If we're dealing with a forward pointer:
- // Find out the type that the pointer is pointing to (must be struct)
- // word 3 is the <id> of the type being pointed to.
- auto type_pointing_to = _.FindDef(member_type->words()[3]);
- if (type_pointing_to && type_pointing_to->opcode() != SpvOpTypeStruct) {
- // Forward declared operands of a struct may only point to a struct.
- return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "A forward reference operand in an OpTypeStruct must be an "
- "OpTypePointer that points to an OpTypeStruct. "
- "Found OpTypePointer that points to Op"
- << spvOpcodeString(
- static_cast<SpvOp>(type_pointing_to->opcode()))
- << ".";
- }
- }
if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) &&
member_type->opcode() == SpvOpTypeRuntimeArray) {
@@ -354,9 +456,14 @@
if (sampled == 2) _.RegisterPointerToStorageImage(inst->id());
}
}
+
+ if (!_.IsValidStorageClass(storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_BINARY, inst)
+ << "Invalid storage class for target environment";
+ }
+
return SPV_SUCCESS;
}
-} // namespace
spv_result_t ValidateTypeFunction(ValidationState_t& _,
const Instruction* inst) {
@@ -425,6 +532,13 @@
<< "pointer definition.";
}
+ const auto pointee_type_id = pointer_type_inst->GetOperandAs<uint32_t>(2);
+ const auto pointee_type = _.FindDef(pointee_type_id);
+ if (!pointee_type || pointee_type->opcode() != SpvOpTypeStruct) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "Forward pointers must point to a structure";
+ }
+
return SPV_SUCCESS;
}
@@ -474,6 +588,7 @@
return SPV_SUCCESS;
}
+} // namespace
spv_result_t TypePass(ValidationState_t& _, const Instruction* inst) {
if (!spvOpcodeGeneratesType(inst->opcode()) &&
@@ -487,6 +602,9 @@
case SpvOpTypeInt:
if (auto error = ValidateTypeInt(_, inst)) return error;
break;
+ case SpvOpTypeFloat:
+ if (auto error = ValidateTypeFloat(_, inst)) return error;
+ break;
case SpvOpTypeVector:
if (auto error = ValidateTypeVector(_, inst)) return error;
break;
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 794d0f7..20eaf88 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -212,14 +212,6 @@
}
}
- switch (env) {
- case SPV_ENV_WEBGPU_0:
- features_.bans_op_undef = true;
- break;
- default:
- break;
- }
-
// Only attempt to count if we have words, otherwise let the other validation
// fail and generate an error.
if (num_words > 0) {
@@ -1277,5 +1269,52 @@
return false;
}
+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:
+ case SpvStorageClassUniform:
+ case SpvStorageClassStorageBuffer:
+ case SpvStorageClassInput:
+ case SpvStorageClassOutput:
+ case SpvStorageClassImage:
+ case SpvStorageClassWorkgroup:
+ case SpvStorageClassPrivate:
+ case SpvStorageClassFunction:
+ case SpvStorageClassPushConstant:
+ case SpvStorageClassPhysicalStorageBuffer:
+ case SpvStorageClassRayPayloadNV:
+ case SpvStorageClassIncomingRayPayloadNV:
+ case SpvStorageClassHitAttributeNV:
+ case SpvStorageClassCallableDataNV:
+ case SpvStorageClassIncomingCallableDataNV:
+ case SpvStorageClassShaderRecordBufferNV:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // namespace val
} // namespace spvtools
diff --git a/source/val/validation_state.h b/source/val/validation_state.h
index ad16bcb..e5d31ac 100644
--- a/source/val/validation_state.h
+++ b/source/val/validation_state.h
@@ -79,9 +79,6 @@
// Permit group oerations Reduce, InclusiveScan, ExclusiveScan
bool group_ops_reduce_and_scans = false;
- // Disallows the use of OpUndef
- bool bans_op_undef = false;
-
// Allow OpTypeInt with 8 bit width?
bool declare_int8_type = false;
@@ -330,6 +327,12 @@
return module_capabilities_.Contains(cap);
}
+ /// Returns a reference to the set of capabilities in the module.
+ /// This is provided for debuggability.
+ const CapabilitySet& module_capabilities() const {
+ return module_capabilities_;
+ }
+
/// Returns true if the extension is enabled in the module.
bool HasExtension(Extension ext) const {
return module_extensions_.Contains(ext);
@@ -380,7 +383,11 @@
/// Registers the decoration for the given <id>
void RegisterDecorationForId(uint32_t id, const Decoration& dec) {
- id_decorations_[id].push_back(dec);
+ auto& dec_list = id_decorations_[id];
+ auto lb = std::find(dec_list.begin(), dec_list.end(), dec);
+ if (lb == dec_list.end()) {
+ dec_list.push_back(dec);
+ }
}
/// Registers the list of decorations for the given <id>
@@ -697,6 +704,9 @@
// * OpCopyObject
const Instruction* TracePointer(const Instruction* inst) const;
+ // Validates the storage class for the target environment.
+ bool IsValidStorageClass(SpvStorageClass storage_class) const;
+
private:
ValidationState_t(const ValidationState_t&);
diff --git a/test/assembly_format_test.cpp b/test/assembly_format_test.cpp
index 59e500b..718e6d3 100644
--- a/test/assembly_format_test.cpp
+++ b/test/assembly_format_test.cpp
@@ -20,7 +20,7 @@
using spvtest::ScopedContext;
using spvtest::TextToBinaryTest;
-TEST_F(TextToBinaryTest, NotPlacingResultIDAtTheBeginning) {
+TEST_F(TextToBinaryTest, InstOpcodeProducesResultIDButNoIDDefinedFails) {
SetText("OpTypeMatrix %1 %2 1000");
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
spvTextToBinary(ScopedContext().context, text.str, text.length,
@@ -33,5 +33,18 @@
EXPECT_EQ(0u, diagnostic->position.line);
}
+TEST_F(TextToBinaryTest,
+ InstDefinesResultIDButOpcodeDoesNotProduceAResultFails) {
+ SetText("\n\n%foo = OpName %1 \"bar\"");
+ EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
+ spvTextToBinary(ScopedContext().context, text.str, text.length,
+ &binary, &diagnostic));
+ ASSERT_NE(nullptr, diagnostic);
+ EXPECT_STREQ(
+ "Cannot set ID %foo because OpName does not produce a result ID.",
+ diagnostic->error);
+ EXPECT_EQ(2u, diagnostic->position.line);
+}
+
} // namespace
} // namespace svptools
diff --git a/test/binary_header_get_test.cpp b/test/binary_header_get_test.cpp
index dcaf992..f8f6bdb 100644
--- a/test/binary_header_get_test.cpp
+++ b/test/binary_header_get_test.cpp
@@ -51,7 +51,8 @@
ASSERT_EQ(SPV_SUCCESS, spvBinaryHeaderGet(&const_bin, endian, &header));
ASSERT_EQ(static_cast<uint32_t>(SpvMagicNumber), header.magic);
- ASSERT_EQ(0x00010400u, header.version);
+ // Expect SPIRV-Headers updated to SPIR-V 1.5.
+ ASSERT_EQ(0x00010500u, header.version);
ASSERT_EQ(static_cast<uint32_t>(SPV_GENERATOR_CODEPLAY), header.generator);
ASSERT_EQ(1u, header.bound);
ASSERT_EQ(0u, header.schema);
diff --git a/test/c_interface_test.cpp b/test/c_interface_test.cpp
index c644fb9..841bb2c 100644
--- a/test/c_interface_test.cpp
+++ b/test/c_interface_test.cpp
@@ -107,7 +107,7 @@
}
TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) {
- const char input_text[] = "%1 = OpName\n";
+ const char input_text[] = " OpName\n";
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
int invocation = 0;
@@ -213,7 +213,7 @@
// When having both a consumer and an diagnostic object, the diagnostic object
// should take priority.
TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForAssembling) {
- const char input_text[] = "%1 = OpName";
+ const char input_text[] = " OpName";
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
int invocation = 0;
diff --git a/test/fuzz/CMakeLists.txt b/test/fuzz/CMakeLists.txt
index 6a101dd..b38f35e 100644
--- a/test/fuzz/CMakeLists.txt
+++ b/test/fuzz/CMakeLists.txt
@@ -17,26 +17,47 @@
set(SOURCES
fuzz_test_util.h
- fuzzer_replayer_test.cpp
- fuzzer_shrinker_test.cpp
+ data_synonym_transformation_test.cpp
+ equivalence_relation_test.cpp
fact_manager_test.cpp
fuzz_test_util.cpp
fuzzer_pass_add_useful_constructs_test.cpp
+ instruction_descriptor_test.cpp
transformation_add_constant_boolean_test.cpp
transformation_add_constant_scalar_test.cpp
transformation_add_dead_break_test.cpp
transformation_add_dead_continue_test.cpp
+ transformation_add_no_contraction_decoration_test.cpp
transformation_add_type_boolean_test.cpp
transformation_add_type_float_test.cpp
transformation_add_type_int_test.cpp
transformation_add_type_pointer_test.cpp
+ transformation_composite_construct_test.cpp
+ transformation_composite_extract_test.cpp
transformation_copy_object_test.cpp
transformation_move_block_down_test.cpp
transformation_replace_boolean_constant_with_constant_binary_test.cpp
transformation_replace_constant_with_uniform_test.cpp
+ transformation_replace_id_with_synonym_test.cpp
+ transformation_set_function_control_test.cpp
+ transformation_set_loop_control_test.cpp
+ transformation_set_memory_operands_mask_test.cpp
+ transformation_set_selection_control_test.cpp
transformation_split_block_test.cpp
+ transformation_vector_shuffle_test.cpp
uniform_buffer_element_descriptor_test.cpp)
+ if (${SPIRV_ENABLE_LONG_FUZZER_TESTS})
+ # These are long-running tests that depend on random seeds. We do not want
+ # to run them during regular whole-project CI because they may reveal
+ # spirv-fuzz bugs in changes that are totally unrelated to spirv-fuzz,
+ # which would be counfounding. Instead, they should be run regularly but
+ # separately.
+ set(SOURCES ${SOURCES}
+ fuzzer_replayer_test.cpp
+ fuzzer_shrinker_test.cpp)
+ endif()
+
add_spvtools_unittest(TARGET fuzz
SRCS ${SOURCES}
LIBS SPIRV-Tools-fuzz
diff --git a/test/fuzz/data_synonym_transformation_test.cpp b/test/fuzz/data_synonym_transformation_test.cpp
new file mode 100644
index 0000000..21ea068
--- /dev/null
+++ b/test/fuzz/data_synonym_transformation_test.cpp
@@ -0,0 +1,1122 @@
+// 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/fuzz/data_descriptor.h"
+#include "source/fuzz/id_use_descriptor.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/transformation_composite_extract.h"
+#include "source/fuzz/transformation_replace_id_with_synonym.h"
+#include "source/fuzz/transformation_vector_shuffle.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+// This file captures tests that check correctness of the collective use of a
+// number of transformations that relate to data synonyms.
+
+protobufs::Fact MakeSynonymFact(uint32_t first_id,
+ std::vector<uint32_t>&& first_indices,
+ uint32_t second_id,
+ std::vector<uint32_t>&& second_indices) {
+ protobufs::FactDataSynonym data_synonym_fact;
+ *data_synonym_fact.mutable_data1() =
+ MakeDataDescriptor(first_id, std::move(first_indices));
+ *data_synonym_fact.mutable_data2() =
+ MakeDataDescriptor(second_id, std::move(second_indices));
+ protobufs::Fact result;
+ *result.mutable_data_synonym_fact() = data_synonym_fact;
+ return result;
+}
+
+TEST(DataSynonymTransformationTest, ArrayCompositeSynonyms) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %11 "A"
+ OpName %20 "B"
+ OpName %31 "g"
+ OpName %35 "h"
+ OpDecorate %11 RelaxedPrecision
+ OpDecorate %22 RelaxedPrecision
+ OpDecorate %27 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %40 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 3
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpConstant %6 0
+ %13 = OpConstant %6 3
+ %14 = OpTypePointer Function %6
+ %16 = OpTypeFloat 32
+ %17 = OpConstant %7 4
+ %18 = OpTypeArray %16 %17
+ %19 = OpTypePointer Function %18
+ %24 = OpTypePointer Function %16
+ %28 = OpConstant %16 42
+ %30 = OpConstant %6 2
+ %34 = OpConstant %6 1
+ %38 = OpConstant %6 42
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %20 = OpVariable %19 Function
+ %31 = OpVariable %24 Function
+ %35 = OpVariable %14 Function
+ %15 = OpAccessChain %14 %11 %12
+ %21 = OpAccessChain %14 %11 %12
+ %22 = OpLoad %6 %21
+ %100 = OpCompositeConstruct %9 %12 %13 %22
+ OpStore %15 %13
+ %23 = OpConvertSToF %16 %22
+ %25 = OpAccessChain %24 %20 %12
+ OpStore %25 %23
+ %26 = OpAccessChain %14 %11 %12
+ %27 = OpLoad %6 %26
+ %29 = OpAccessChain %24 %20 %27
+ OpStore %29 %28
+ %32 = OpLoad %16 %31
+ %101 = OpCompositeConstruct %18 %28 %23 %32 %23
+ %50 = OpCopyObject %16 %23
+ %51 = OpCopyObject %16 %23
+ %33 = OpAccessChain %24 %20 %30
+ OpStore %33 %28
+ OpStore %33 %32
+ %36 = OpLoad %6 %35
+ %37 = OpAccessChain %14 %11 %34
+ OpStore %37 %36
+ %39 = OpAccessChain %14 %11 %12
+ %40 = OpLoad %6 %39
+ %41 = OpIAdd %6 %38 %40
+ %42 = OpAccessChain %14 %11 %30
+ OpStore %42 %41
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+ fact_manager.AddFact(MakeSynonymFact(12, {}, 100, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(13, {}, 100, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(22, {}, 100, {2}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(28, {}, 101, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(23, {}, 101, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(32, {}, 101, {2}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(23, {}, 101, {3}), context.get());
+
+ // Replace %12 with %100[0] in '%25 = OpAccessChain %24 %20 %12'
+ auto instruction_descriptor_1 =
+ MakeInstructionDescriptor(25, SpvOpAccessChain, 0);
+ auto good_extract_1 =
+ TransformationCompositeExtract(instruction_descriptor_1, 102, 100, {0});
+ // Bad: id already in use
+ auto bad_extract_1 = TransformationCompositeExtract(
+ MakeInstructionDescriptor(25, SpvOpAccessChain, 0), 25, 100, {0});
+ ASSERT_TRUE(good_extract_1.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(bad_extract_1.IsApplicable(context.get(), fact_manager));
+ good_extract_1.Apply(context.get(), &fact_manager);
+ auto replacement_1 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(12, instruction_descriptor_1, 1), 102);
+ ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager));
+ replacement_1.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %13 with %100[1] in 'OpStore %15 %13'
+ auto instruction_descriptor_2 = MakeInstructionDescriptor(100, SpvOpStore, 0);
+ auto good_extract_2 =
+ TransformationCompositeExtract(instruction_descriptor_2, 103, 100, {1});
+ // No bad example provided here.
+ ASSERT_TRUE(good_extract_2.IsApplicable(context.get(), fact_manager));
+ good_extract_2.Apply(context.get(), &fact_manager);
+ auto replacement_2 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(13, instruction_descriptor_2, 1), 103);
+ ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager));
+ replacement_2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %22 with %100[2] in '%23 = OpConvertSToF %16 %22'
+ auto instruction_descriptor_3 =
+ MakeInstructionDescriptor(23, SpvOpConvertSToF, 0);
+ auto good_extract_3 =
+ TransformationCompositeExtract(instruction_descriptor_3, 104, 100, {2});
+ ASSERT_TRUE(good_extract_3.IsApplicable(context.get(), fact_manager));
+ good_extract_3.Apply(context.get(), &fact_manager);
+ auto replacement_3 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(22, instruction_descriptor_3, 0), 104);
+ // Bad: wrong input operand index
+ auto bad_replacement_3 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(22, instruction_descriptor_3, 1), 104);
+ ASSERT_TRUE(replacement_3.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(bad_replacement_3.IsApplicable(context.get(), fact_manager));
+ replacement_3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %28 with %101[0] in 'OpStore %33 %28'
+ auto instruction_descriptor_4 = MakeInstructionDescriptor(33, SpvOpStore, 0);
+ auto good_extract_4 =
+ TransformationCompositeExtract(instruction_descriptor_4, 105, 101, {0});
+ // Bad: instruction descriptor does not identify an appropriate instruction
+ auto bad_extract_4 = TransformationCompositeExtract(
+ MakeInstructionDescriptor(33, SpvOpCopyObject, 0), 105, 101, {0});
+ ASSERT_TRUE(good_extract_4.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(bad_extract_4.IsApplicable(context.get(), fact_manager));
+ good_extract_4.Apply(context.get(), &fact_manager);
+ auto replacement_4 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(28, instruction_descriptor_4, 1), 105);
+ ASSERT_TRUE(replacement_4.IsApplicable(context.get(), fact_manager));
+ replacement_4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %23 with %101[1] in '%50 = OpCopyObject %16 %23'
+ auto instruction_descriptor_5 =
+ MakeInstructionDescriptor(50, SpvOpCopyObject, 0);
+ auto good_extract_5 =
+ TransformationCompositeExtract(instruction_descriptor_5, 106, 101, {1});
+ ASSERT_TRUE(good_extract_5.IsApplicable(context.get(), fact_manager));
+ good_extract_5.Apply(context.get(), &fact_manager);
+ auto replacement_5 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(23, instruction_descriptor_5, 0), 106);
+ // Bad: wrong synonym fact being used
+ auto bad_replacement_5 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(23, instruction_descriptor_5, 0), 105);
+ ASSERT_TRUE(replacement_5.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(bad_replacement_5.IsApplicable(context.get(), fact_manager));
+ replacement_5.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %32 with %101[2] in 'OpStore %33 %32'
+ auto instruction_descriptor_6 = MakeInstructionDescriptor(33, SpvOpStore, 1);
+ auto good_extract_6 =
+ TransformationCompositeExtract(instruction_descriptor_6, 107, 101, {2});
+ // Bad: id 1001 does not exist
+ auto bad_extract_6 =
+ TransformationCompositeExtract(instruction_descriptor_6, 107, 1001, {2});
+ ASSERT_TRUE(good_extract_6.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(bad_extract_6.IsApplicable(context.get(), fact_manager));
+ good_extract_6.Apply(context.get(), &fact_manager);
+ auto replacement_6 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(32, instruction_descriptor_6, 1), 107);
+ ASSERT_TRUE(replacement_6.IsApplicable(context.get(), fact_manager));
+ replacement_6.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %23 with %101[3] in '%51 = OpCopyObject %16 %23'
+ auto instruction_descriptor_7 =
+ MakeInstructionDescriptor(51, SpvOpCopyObject, 0);
+ auto good_extract_7 =
+ TransformationCompositeExtract(instruction_descriptor_7, 108, 101, {3});
+ ASSERT_TRUE(good_extract_7.IsApplicable(context.get(), fact_manager));
+ good_extract_7.Apply(context.get(), &fact_manager);
+ auto replacement_7 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(23, instruction_descriptor_7, 0), 108);
+ // Bad: use id 0 is invalid
+ auto bad_replacement_7 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(0, instruction_descriptor_7, 0), 108);
+ ASSERT_TRUE(replacement_7.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(bad_replacement_7.IsApplicable(context.get(), fact_manager));
+ replacement_7.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ const std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %11 "A"
+ OpName %20 "B"
+ OpName %31 "g"
+ OpName %35 "h"
+ OpDecorate %11 RelaxedPrecision
+ OpDecorate %22 RelaxedPrecision
+ OpDecorate %27 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %40 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 3
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpConstant %6 0
+ %13 = OpConstant %6 3
+ %14 = OpTypePointer Function %6
+ %16 = OpTypeFloat 32
+ %17 = OpConstant %7 4
+ %18 = OpTypeArray %16 %17
+ %19 = OpTypePointer Function %18
+ %24 = OpTypePointer Function %16
+ %28 = OpConstant %16 42
+ %30 = OpConstant %6 2
+ %34 = OpConstant %6 1
+ %38 = OpConstant %6 42
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %20 = OpVariable %19 Function
+ %31 = OpVariable %24 Function
+ %35 = OpVariable %14 Function
+ %15 = OpAccessChain %14 %11 %12
+ %21 = OpAccessChain %14 %11 %12
+ %22 = OpLoad %6 %21
+ %100 = OpCompositeConstruct %9 %12 %13 %22
+ %103 = OpCompositeExtract %6 %100 1
+ OpStore %15 %103
+ %104 = OpCompositeExtract %6 %100 2
+ %23 = OpConvertSToF %16 %104
+ %102 = OpCompositeExtract %6 %100 0
+ %25 = OpAccessChain %24 %20 %102
+ OpStore %25 %23
+ %26 = OpAccessChain %14 %11 %12
+ %27 = OpLoad %6 %26
+ %29 = OpAccessChain %24 %20 %27
+ OpStore %29 %28
+ %32 = OpLoad %16 %31
+ %101 = OpCompositeConstruct %18 %28 %23 %32 %23
+ %106 = OpCompositeExtract %16 %101 1
+ %50 = OpCopyObject %16 %106
+ %108 = OpCompositeExtract %16 %101 3
+ %51 = OpCopyObject %16 %108
+ %33 = OpAccessChain %24 %20 %30
+ %105 = OpCompositeExtract %16 %101 0
+ OpStore %33 %105
+ %107 = OpCompositeExtract %16 %101 2
+ OpStore %33 %107
+ %36 = OpLoad %6 %35
+ %37 = OpAccessChain %14 %11 %34
+ OpStore %37 %36
+ %39 = OpAccessChain %14 %11 %12
+ %40 = OpLoad %6 %39
+ %41 = OpIAdd %6 %38 %40
+ %42 = OpAccessChain %14 %11 %30
+ OpStore %42 %41
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(DataSynonymTransformationTest, MatrixCompositeSynonyms) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %10 "m"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 4
+ %50 = OpUndef %7
+ %8 = OpTypeMatrix %7 3
+ %9 = OpTypePointer Function %8
+ %11 = OpTypeInt 32 1
+ %12 = OpConstant %11 0
+ %13 = OpConstant %6 1
+ %14 = OpConstantComposite %7 %13 %13 %13 %13
+ %15 = OpTypePointer Function %7
+ %17 = OpConstant %11 1
+ %18 = OpConstant %6 2
+ %19 = OpConstantComposite %7 %18 %18 %18 %18
+ %21 = OpConstant %11 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %10 = OpVariable %9 Function
+ %16 = OpAccessChain %15 %10 %12
+ OpStore %16 %14
+ %20 = OpAccessChain %15 %10 %17
+ OpStore %20 %19
+ %22 = OpAccessChain %15 %10 %12
+ %23 = OpLoad %7 %22
+ %24 = OpAccessChain %15 %10 %17
+ %25 = OpLoad %7 %24
+ %100 = OpCompositeConstruct %8 %23 %25 %50
+ %26 = OpFAdd %7 %23 %25
+ %27 = OpAccessChain %15 %10 %21
+ OpStore %27 %26
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+ fact_manager.AddFact(MakeSynonymFact(23, {}, 100, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(25, {}, 100, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(50, {}, 100, {2}), context.get());
+
+ // Replace %23 with %100[0] in '%26 = OpFAdd %7 %23 %25'
+ auto instruction_descriptor_1 = MakeInstructionDescriptor(26, SpvOpFAdd, 0);
+ auto extract_1 =
+ TransformationCompositeExtract(instruction_descriptor_1, 101, 100, {0});
+ ASSERT_TRUE(extract_1.IsApplicable(context.get(), fact_manager));
+ extract_1.Apply(context.get(), &fact_manager);
+ auto replacement_1 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(23, instruction_descriptor_1, 0), 101);
+ ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager));
+ replacement_1.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %25 with %100[1] in '%26 = OpFAdd %7 %23 %25'
+ auto instruction_descriptor_2 = MakeInstructionDescriptor(26, SpvOpFAdd, 0);
+ auto extract_2 =
+ TransformationCompositeExtract(instruction_descriptor_2, 102, 100, {1});
+ ASSERT_TRUE(extract_2.IsApplicable(context.get(), fact_manager));
+ extract_2.Apply(context.get(), &fact_manager);
+ auto replacement_2 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(25, instruction_descriptor_2, 1), 102);
+ ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager));
+ replacement_2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ const std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %10 "m"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 4
+ %50 = OpUndef %7
+ %8 = OpTypeMatrix %7 3
+ %9 = OpTypePointer Function %8
+ %11 = OpTypeInt 32 1
+ %12 = OpConstant %11 0
+ %13 = OpConstant %6 1
+ %14 = OpConstantComposite %7 %13 %13 %13 %13
+ %15 = OpTypePointer Function %7
+ %17 = OpConstant %11 1
+ %18 = OpConstant %6 2
+ %19 = OpConstantComposite %7 %18 %18 %18 %18
+ %21 = OpConstant %11 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %10 = OpVariable %9 Function
+ %16 = OpAccessChain %15 %10 %12
+ OpStore %16 %14
+ %20 = OpAccessChain %15 %10 %17
+ OpStore %20 %19
+ %22 = OpAccessChain %15 %10 %12
+ %23 = OpLoad %7 %22
+ %24 = OpAccessChain %15 %10 %17
+ %25 = OpLoad %7 %24
+ %100 = OpCompositeConstruct %8 %23 %25 %50
+ %101 = OpCompositeExtract %7 %100 0
+ %102 = OpCompositeExtract %7 %100 1
+ %26 = OpFAdd %7 %101 %102
+ %27 = OpAccessChain %15 %10 %21
+ OpStore %27 %26
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(DataSynonymTransformationTest, StructCompositeSynonyms) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "Inner"
+ OpMemberName %9 0 "a"
+ OpMemberName %9 1 "b"
+ OpName %11 "i1"
+ OpName %17 "i2"
+ OpName %31 "Point"
+ OpMemberName %31 0 "x"
+ OpMemberName %31 1 "y"
+ OpMemberName %31 2 "z"
+ OpName %32 "Outer"
+ OpMemberName %32 0 "c"
+ OpMemberName %32 1 "d"
+ OpName %34 "o1"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeFloat 32
+ %8 = OpTypeVector %7 2
+ %9 = OpTypeStruct %6 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpConstant %6 1
+ %13 = OpConstant %7 2
+ %14 = OpConstant %7 3
+ %15 = OpConstantComposite %8 %13 %14
+ %16 = OpConstantComposite %9 %12 %15
+ %18 = OpConstant %6 0
+ %19 = OpTypePointer Function %6
+ %24 = OpTypePointer Function %8
+ %27 = OpConstant %7 4
+ %31 = OpTypeStruct %7 %7 %7
+ %32 = OpTypeStruct %9 %31
+ %33 = OpTypePointer Function %32
+ %36 = OpConstant %7 10
+ %37 = OpTypeInt 32 0
+ %38 = OpConstant %37 0
+ %39 = OpTypePointer Function %7
+ %42 = OpConstant %37 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %17 = OpVariable %10 Function
+ %34 = OpVariable %33 Function
+ %101 = OpCompositeConstruct %31 %27 %36 %27
+ OpStore %11 %16
+ %20 = OpAccessChain %19 %11 %18
+ %21 = OpLoad %6 %20
+ %22 = OpIAdd %6 %21 %12
+ %102 = OpCompositeConstruct %9 %22 %15
+ %23 = OpAccessChain %19 %17 %18
+ OpStore %23 %22
+ %25 = OpAccessChain %24 %17 %12
+ %26 = OpLoad %8 %25
+ %28 = OpCompositeConstruct %8 %27 %27
+ %29 = OpFAdd %8 %26 %28
+ %30 = OpAccessChain %24 %17 %12
+ OpStore %30 %29
+ %35 = OpLoad %9 %11
+ %40 = OpAccessChain %39 %11 %12 %38
+ %41 = OpLoad %7 %40
+ %43 = OpAccessChain %39 %11 %12 %42
+ %44 = OpLoad %7 %43
+ %45 = OpCompositeConstruct %31 %36 %41 %44
+ %100 = OpCompositeConstruct %32 %16 %45
+ %46 = OpCompositeConstruct %32 %35 %45
+ OpStore %34 %46
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ fact_manager.AddFact(MakeSynonymFact(16, {}, 100, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(45, {}, 100, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(27, {}, 101, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(36, {}, 101, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(27, {}, 101, {2}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(22, {}, 102, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(15, {}, 102, {1}), context.get());
+
+ // Replace %45 with %100[1] in '%46 = OpCompositeConstruct %32 %35 %45'
+ auto instruction_descriptor_1 =
+ MakeInstructionDescriptor(46, SpvOpCompositeConstruct, 0);
+ auto extract_1 =
+ TransformationCompositeExtract(instruction_descriptor_1, 201, 100, {1});
+ ASSERT_TRUE(extract_1.IsApplicable(context.get(), fact_manager));
+ extract_1.Apply(context.get(), &fact_manager);
+ auto replacement_1 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(45, instruction_descriptor_1, 1), 201);
+ ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager));
+ replacement_1.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace second occurrence of %27 with %101[0] in '%28 =
+ // OpCompositeConstruct %8 %27 %27'
+ auto instruction_descriptor_2 =
+ MakeInstructionDescriptor(28, SpvOpCompositeConstruct, 0);
+ auto extract_2 =
+ TransformationCompositeExtract(instruction_descriptor_2, 202, 101, {0});
+ ASSERT_TRUE(extract_2.IsApplicable(context.get(), fact_manager));
+ extract_2.Apply(context.get(), &fact_manager);
+ auto replacement_2 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(27, instruction_descriptor_2, 1), 202);
+ ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager));
+ replacement_2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %36 with %101[1] in '%45 = OpCompositeConstruct %31 %36 %41 %44'
+ auto instruction_descriptor_3 =
+ MakeInstructionDescriptor(45, SpvOpCompositeConstruct, 0);
+ auto extract_3 =
+ TransformationCompositeExtract(instruction_descriptor_3, 203, 101, {1});
+ ASSERT_TRUE(extract_3.IsApplicable(context.get(), fact_manager));
+ extract_3.Apply(context.get(), &fact_manager);
+ auto replacement_3 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(36, instruction_descriptor_3, 0), 203);
+ ASSERT_TRUE(replacement_3.IsApplicable(context.get(), fact_manager));
+ replacement_3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace first occurrence of %27 with %101[2] in '%28 = OpCompositeConstruct
+ // %8 %27 %27'
+ auto instruction_descriptor_4 =
+ MakeInstructionDescriptor(28, SpvOpCompositeConstruct, 0);
+ auto extract_4 =
+ TransformationCompositeExtract(instruction_descriptor_4, 204, 101, {2});
+ ASSERT_TRUE(extract_4.IsApplicable(context.get(), fact_manager));
+ extract_4.Apply(context.get(), &fact_manager);
+ auto replacement_4 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(27, instruction_descriptor_4, 0), 204);
+ ASSERT_TRUE(replacement_4.IsApplicable(context.get(), fact_manager));
+ replacement_4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %22 with %102[0] in 'OpStore %23 %22'
+ auto instruction_descriptor_5 = MakeInstructionDescriptor(23, SpvOpStore, 0);
+ auto extract_5 =
+ TransformationCompositeExtract(instruction_descriptor_5, 205, 102, {0});
+ ASSERT_TRUE(extract_5.IsApplicable(context.get(), fact_manager));
+ extract_5.Apply(context.get(), &fact_manager);
+ auto replacement_5 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(22, instruction_descriptor_5, 1), 205);
+ ASSERT_TRUE(replacement_5.IsApplicable(context.get(), fact_manager));
+ replacement_5.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ const std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "Inner"
+ OpMemberName %9 0 "a"
+ OpMemberName %9 1 "b"
+ OpName %11 "i1"
+ OpName %17 "i2"
+ OpName %31 "Point"
+ OpMemberName %31 0 "x"
+ OpMemberName %31 1 "y"
+ OpMemberName %31 2 "z"
+ OpName %32 "Outer"
+ OpMemberName %32 0 "c"
+ OpMemberName %32 1 "d"
+ OpName %34 "o1"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeFloat 32
+ %8 = OpTypeVector %7 2
+ %9 = OpTypeStruct %6 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpConstant %6 1
+ %13 = OpConstant %7 2
+ %14 = OpConstant %7 3
+ %15 = OpConstantComposite %8 %13 %14
+ %16 = OpConstantComposite %9 %12 %15
+ %18 = OpConstant %6 0
+ %19 = OpTypePointer Function %6
+ %24 = OpTypePointer Function %8
+ %27 = OpConstant %7 4
+ %31 = OpTypeStruct %7 %7 %7
+ %32 = OpTypeStruct %9 %31
+ %33 = OpTypePointer Function %32
+ %36 = OpConstant %7 10
+ %37 = OpTypeInt 32 0
+ %38 = OpConstant %37 0
+ %39 = OpTypePointer Function %7
+ %42 = OpConstant %37 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %17 = OpVariable %10 Function
+ %34 = OpVariable %33 Function
+ %101 = OpCompositeConstruct %31 %27 %36 %27
+ OpStore %11 %16
+ %20 = OpAccessChain %19 %11 %18
+ %21 = OpLoad %6 %20
+ %22 = OpIAdd %6 %21 %12
+ %102 = OpCompositeConstruct %9 %22 %15
+ %23 = OpAccessChain %19 %17 %18
+ %205 = OpCompositeExtract %6 %102 0
+ OpStore %23 %205
+ %25 = OpAccessChain %24 %17 %12
+ %26 = OpLoad %8 %25
+ %202 = OpCompositeExtract %7 %101 0
+ %204 = OpCompositeExtract %7 %101 2
+ %28 = OpCompositeConstruct %8 %204 %202
+ %29 = OpFAdd %8 %26 %28
+ %30 = OpAccessChain %24 %17 %12
+ OpStore %30 %29
+ %35 = OpLoad %9 %11
+ %40 = OpAccessChain %39 %11 %12 %38
+ %41 = OpLoad %7 %40
+ %43 = OpAccessChain %39 %11 %12 %42
+ %44 = OpLoad %7 %43
+ %203 = OpCompositeExtract %7 %101 1
+ %45 = OpCompositeConstruct %31 %203 %41 %44
+ %100 = OpCompositeConstruct %32 %16 %45
+ %201 = OpCompositeExtract %31 %100 1
+ %46 = OpCompositeConstruct %32 %35 %201
+ OpStore %34 %46
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(DataSynonymTransformationTest, VectorCompositeSynonyms) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "f"
+ OpName %12 "v2"
+ OpName %18 "v3"
+ OpName %23 "v4"
+ OpName %32 "b"
+ OpName %36 "bv2"
+ OpName %41 "bv3"
+ OpName %50 "bv4"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 42
+ %10 = OpTypeVector %6 2
+ %11 = OpTypePointer Function %10
+ %16 = OpTypeVector %6 3
+ %17 = OpTypePointer Function %16
+ %21 = OpTypeVector %6 4
+ %22 = OpTypePointer Function %21
+ %30 = OpTypeBool
+ %31 = OpTypePointer Function %30
+ %33 = OpConstantFalse %30
+ %34 = OpTypeVector %30 2
+ %35 = OpTypePointer Function %34
+ %37 = OpConstantTrue %30
+ %38 = OpConstantComposite %34 %37 %37
+ %39 = OpTypeVector %30 3
+ %40 = OpTypePointer Function %39
+ %48 = OpTypeVector %30 4
+ %49 = OpTypePointer Function %48
+ %51 = OpTypeInt 32 0
+ %52 = OpConstant %51 2
+ %55 = OpConstant %6 0
+ %57 = OpConstant %51 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %12 = OpVariable %11 Function
+ %18 = OpVariable %17 Function
+ %23 = OpVariable %22 Function
+ %32 = OpVariable %31 Function
+ %36 = OpVariable %35 Function
+ %41 = OpVariable %40 Function
+ %50 = OpVariable %49 Function
+ OpStore %8 %9
+ %13 = OpLoad %6 %8
+ %14 = OpLoad %6 %8
+ %15 = OpCompositeConstruct %10 %13 %14
+ OpStore %12 %15
+ %19 = OpLoad %10 %12
+ %20 = OpVectorShuffle %16 %19 %19 0 0 1
+ OpStore %18 %20
+ %24 = OpLoad %16 %18
+ %25 = OpLoad %6 %8
+ %26 = OpCompositeExtract %6 %24 0
+ %27 = OpCompositeExtract %6 %24 1
+ %28 = OpCompositeExtract %6 %24 2
+ %29 = OpCompositeConstruct %21 %26 %27 %28 %25
+ OpStore %23 %29
+ OpStore %32 %33
+ OpStore %36 %38
+ %42 = OpLoad %30 %32
+ %43 = OpLoad %34 %36
+ %44 = OpVectorShuffle %34 %43 %43 0 0
+ %45 = OpCompositeExtract %30 %44 0
+ %46 = OpCompositeExtract %30 %44 1
+ %47 = OpCompositeConstruct %39 %42 %45 %46
+ OpStore %41 %47
+ %53 = OpAccessChain %7 %23 %52
+ %54 = OpLoad %6 %53
+
+ %100 = OpCompositeConstruct %21 %20 %54
+ %101 = OpCompositeConstruct %21 %15 %19
+ %102 = OpCompositeConstruct %16 %27 %15
+ %103 = OpCompositeConstruct %48 %33 %47
+ %104 = OpCompositeConstruct %34 %42 %45
+ %105 = OpCompositeConstruct %39 %38 %46
+
+ %86 = OpCopyObject %30 %33
+ %56 = OpFOrdNotEqual %30 %54 %55
+ %80 = OpCopyObject %16 %20
+ %58 = OpAccessChain %7 %18 %57
+ %59 = OpLoad %6 %58
+ %60 = OpFOrdNotEqual %30 %59 %55
+ %61 = OpLoad %34 %36
+ %62 = OpLogicalAnd %30 %45 %46
+ %63 = OpLogicalOr %30 %45 %46
+ %64 = OpCompositeConstruct %48 %56 %60 %62 %63
+ OpStore %12 %15
+ %81 = OpVectorShuffle %16 %19 %19 0 0 1
+ %82 = OpCompositeConstruct %21 %26 %27 %28 %25
+ %83 = OpCopyObject %10 %15
+ %84 = OpCopyObject %39 %47
+ OpStore %50 %64
+ %85 = OpCopyObject %30 %42
+ OpStore %36 %38
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+ fact_manager.AddFact(MakeSynonymFact(20, {0}, 100, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(20, {1}, 100, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(20, {2}, 100, {2}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(54, {}, 100, {3}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(15, {0}, 101, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(15, {1}, 101, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(19, {0}, 101, {2}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(19, {1}, 101, {3}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(27, {}, 102, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(15, {0}, 102, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(15, {1}, 102, {2}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(33, {}, 103, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(47, {0}, 103, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(47, {1}, 103, {2}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(47, {2}, 103, {3}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(42, {}, 104, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(45, {}, 104, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(38, {0}, 105, {0}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(38, {1}, 105, {1}), context.get());
+ fact_manager.AddFact(MakeSynonymFact(46, {}, 105, {2}), context.get());
+
+ // Replace %20 with %100[0:2] in '%80 = OpCopyObject %16 %20'
+ auto instruction_descriptor_1 =
+ MakeInstructionDescriptor(80, SpvOpCopyObject, 0);
+ auto shuffle_1 = TransformationVectorShuffle(instruction_descriptor_1, 200,
+ 100, 100, {0, 1, 2});
+ ASSERT_TRUE(shuffle_1.IsApplicable(context.get(), fact_manager));
+ shuffle_1.Apply(context.get(), &fact_manager);
+ auto replacement_1 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(20, instruction_descriptor_1, 0), 200);
+ ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager));
+ replacement_1.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %54 with %100[3] in '%56 = OpFOrdNotEqual %30 %54 %55'
+ auto instruction_descriptor_2 =
+ MakeInstructionDescriptor(56, SpvOpFOrdNotEqual, 0);
+ auto extract_2 =
+ TransformationCompositeExtract(instruction_descriptor_2, 201, 100, {3});
+
+ ASSERT_TRUE(extract_2.IsApplicable(context.get(), fact_manager));
+ extract_2.Apply(context.get(), &fact_manager);
+ auto replacement_2 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(54, instruction_descriptor_2, 0), 201);
+ ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager));
+ replacement_2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %15 with %101[0:1] in 'OpStore %12 %15'
+ auto instruction_descriptor_3 = MakeInstructionDescriptor(64, SpvOpStore, 0);
+ auto shuffle_3 = TransformationVectorShuffle(instruction_descriptor_3, 202,
+ 101, 101, {0, 1});
+ ASSERT_TRUE(shuffle_3.IsApplicable(context.get(), fact_manager));
+ shuffle_3.Apply(context.get(), &fact_manager);
+ auto replacement_3 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(15, instruction_descriptor_3, 1), 202);
+ ASSERT_TRUE(replacement_3.IsApplicable(context.get(), fact_manager));
+ replacement_3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %19 with %101[2:3] in '%81 = OpVectorShuffle %16 %19 %19 0 0 1'
+ auto instruction_descriptor_4 =
+ MakeInstructionDescriptor(81, SpvOpVectorShuffle, 0);
+ auto shuffle_4 = TransformationVectorShuffle(instruction_descriptor_4, 203,
+ 101, 101, {2, 3});
+ ASSERT_TRUE(shuffle_4.IsApplicable(context.get(), fact_manager));
+ shuffle_4.Apply(context.get(), &fact_manager);
+ auto replacement_4 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(19, instruction_descriptor_4, 0), 203);
+ ASSERT_TRUE(replacement_4.IsApplicable(context.get(), fact_manager));
+ replacement_4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %27 with %102[0] in '%82 = OpCompositeConstruct %21 %26 %27 %28
+ // %25'
+ auto instruction_descriptor_5 =
+ MakeInstructionDescriptor(82, SpvOpCompositeConstruct, 0);
+ auto extract_5 =
+ TransformationCompositeExtract(instruction_descriptor_5, 204, 102, {0});
+
+ ASSERT_TRUE(extract_5.IsApplicable(context.get(), fact_manager));
+ extract_5.Apply(context.get(), &fact_manager);
+ auto replacement_5 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(27, instruction_descriptor_5, 1), 204);
+ ASSERT_TRUE(replacement_5.IsApplicable(context.get(), fact_manager));
+ replacement_5.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %15 with %102[1:2] in '%83 = OpCopyObject %10 %15'
+ auto instruction_descriptor_6 =
+ MakeInstructionDescriptor(83, SpvOpCopyObject, 0);
+ auto shuffle_6 = TransformationVectorShuffle(instruction_descriptor_6, 205,
+ 102, 102, {1, 2});
+ ASSERT_TRUE(shuffle_6.IsApplicable(context.get(), fact_manager));
+ shuffle_6.Apply(context.get(), &fact_manager);
+ auto replacement_6 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(15, instruction_descriptor_6, 0), 205);
+ ASSERT_TRUE(replacement_6.IsApplicable(context.get(), fact_manager));
+ replacement_6.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %33 with %103[0] in '%86 = OpCopyObject %30 %33'
+ auto instruction_descriptor_7 =
+ MakeInstructionDescriptor(86, SpvOpCopyObject, 0);
+ auto extract_7 =
+ TransformationCompositeExtract(instruction_descriptor_7, 206, 103, {0});
+ ASSERT_TRUE(extract_7.IsApplicable(context.get(), fact_manager));
+ extract_7.Apply(context.get(), &fact_manager);
+ auto replacement_7 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(33, instruction_descriptor_7, 0), 206);
+ ASSERT_TRUE(replacement_7.IsApplicable(context.get(), fact_manager));
+ replacement_7.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %47 with %103[1:3] in '%84 = OpCopyObject %39 %47'
+ auto instruction_descriptor_8 =
+ MakeInstructionDescriptor(84, SpvOpCopyObject, 0);
+ auto shuffle_8 = TransformationVectorShuffle(instruction_descriptor_8, 207,
+ 103, 103, {1, 2, 3});
+ ASSERT_TRUE(shuffle_8.IsApplicable(context.get(), fact_manager));
+ shuffle_8.Apply(context.get(), &fact_manager);
+ auto replacement_8 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(47, instruction_descriptor_8, 0), 207);
+ ASSERT_TRUE(replacement_8.IsApplicable(context.get(), fact_manager));
+ replacement_8.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %42 with %104[0] in '%85 = OpCopyObject %30 %42'
+ auto instruction_descriptor_9 =
+ MakeInstructionDescriptor(85, SpvOpCopyObject, 0);
+ auto extract_9 =
+ TransformationCompositeExtract(instruction_descriptor_9, 208, 104, {0});
+ ASSERT_TRUE(extract_9.IsApplicable(context.get(), fact_manager));
+ extract_9.Apply(context.get(), &fact_manager);
+ auto replacement_9 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(42, instruction_descriptor_9, 0), 208);
+ ASSERT_TRUE(replacement_9.IsApplicable(context.get(), fact_manager));
+ replacement_9.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %45 with %104[1] in '%63 = OpLogicalOr %30 %45 %46'
+ auto instruction_descriptor_10 =
+ MakeInstructionDescriptor(63, SpvOpLogicalOr, 0);
+ auto extract_10 =
+ TransformationCompositeExtract(instruction_descriptor_10, 209, 104, {1});
+ ASSERT_TRUE(extract_10.IsApplicable(context.get(), fact_manager));
+ extract_10.Apply(context.get(), &fact_manager);
+ auto replacement_10 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(45, instruction_descriptor_10, 0), 209);
+ ASSERT_TRUE(replacement_10.IsApplicable(context.get(), fact_manager));
+ replacement_10.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %38 with %105[0:1] in 'OpStore %36 %38'
+ auto instruction_descriptor_11 = MakeInstructionDescriptor(85, SpvOpStore, 0);
+ auto shuffle_11 = TransformationVectorShuffle(instruction_descriptor_11, 210,
+ 105, 105, {0, 1});
+ ASSERT_TRUE(shuffle_11.IsApplicable(context.get(), fact_manager));
+ shuffle_11.Apply(context.get(), &fact_manager);
+ auto replacement_11 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(38, instruction_descriptor_11, 1), 210);
+ ASSERT_TRUE(replacement_11.IsApplicable(context.get(), fact_manager));
+ replacement_11.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %46 with %105[2] in '%62 = OpLogicalAnd %30 %45 %46'
+ auto instruction_descriptor_12 =
+ MakeInstructionDescriptor(62, SpvOpLogicalAnd, 0);
+ auto extract_12 =
+ TransformationCompositeExtract(instruction_descriptor_12, 211, 105, {2});
+ ASSERT_TRUE(extract_12.IsApplicable(context.get(), fact_manager));
+ extract_12.Apply(context.get(), &fact_manager);
+ auto replacement_12 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(46, instruction_descriptor_12, 1), 211);
+ ASSERT_TRUE(replacement_12.IsApplicable(context.get(), fact_manager));
+ replacement_12.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ const std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "f"
+ OpName %12 "v2"
+ OpName %18 "v3"
+ OpName %23 "v4"
+ OpName %32 "b"
+ OpName %36 "bv2"
+ OpName %41 "bv3"
+ OpName %50 "bv4"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 42
+ %10 = OpTypeVector %6 2
+ %11 = OpTypePointer Function %10
+ %16 = OpTypeVector %6 3
+ %17 = OpTypePointer Function %16
+ %21 = OpTypeVector %6 4
+ %22 = OpTypePointer Function %21
+ %30 = OpTypeBool
+ %31 = OpTypePointer Function %30
+ %33 = OpConstantFalse %30
+ %34 = OpTypeVector %30 2
+ %35 = OpTypePointer Function %34
+ %37 = OpConstantTrue %30
+ %38 = OpConstantComposite %34 %37 %37
+ %39 = OpTypeVector %30 3
+ %40 = OpTypePointer Function %39
+ %48 = OpTypeVector %30 4
+ %49 = OpTypePointer Function %48
+ %51 = OpTypeInt 32 0
+ %52 = OpConstant %51 2
+ %55 = OpConstant %6 0
+ %57 = OpConstant %51 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %12 = OpVariable %11 Function
+ %18 = OpVariable %17 Function
+ %23 = OpVariable %22 Function
+ %32 = OpVariable %31 Function
+ %36 = OpVariable %35 Function
+ %41 = OpVariable %40 Function
+ %50 = OpVariable %49 Function
+ OpStore %8 %9
+ %13 = OpLoad %6 %8
+ %14 = OpLoad %6 %8
+ %15 = OpCompositeConstruct %10 %13 %14
+ OpStore %12 %15
+ %19 = OpLoad %10 %12
+ %20 = OpVectorShuffle %16 %19 %19 0 0 1
+ OpStore %18 %20
+ %24 = OpLoad %16 %18
+ %25 = OpLoad %6 %8
+ %26 = OpCompositeExtract %6 %24 0
+ %27 = OpCompositeExtract %6 %24 1
+ %28 = OpCompositeExtract %6 %24 2
+ %29 = OpCompositeConstruct %21 %26 %27 %28 %25
+ OpStore %23 %29
+ OpStore %32 %33
+ OpStore %36 %38
+ %42 = OpLoad %30 %32
+ %43 = OpLoad %34 %36
+ %44 = OpVectorShuffle %34 %43 %43 0 0
+ %45 = OpCompositeExtract %30 %44 0
+ %46 = OpCompositeExtract %30 %44 1
+ %47 = OpCompositeConstruct %39 %42 %45 %46
+ OpStore %41 %47
+ %53 = OpAccessChain %7 %23 %52
+ %54 = OpLoad %6 %53
+
+ %100 = OpCompositeConstruct %21 %20 %54
+ %101 = OpCompositeConstruct %21 %15 %19
+ %102 = OpCompositeConstruct %16 %27 %15
+ %103 = OpCompositeConstruct %48 %33 %47
+ %104 = OpCompositeConstruct %34 %42 %45
+ %105 = OpCompositeConstruct %39 %38 %46
+
+ %206 = OpCompositeExtract %30 %103 0
+ %86 = OpCopyObject %30 %206
+ %201 = OpCompositeExtract %6 %100 3
+ %56 = OpFOrdNotEqual %30 %201 %55
+ %200 = OpVectorShuffle %16 %100 %100 0 1 2
+ %80 = OpCopyObject %16 %200
+ %58 = OpAccessChain %7 %18 %57
+ %59 = OpLoad %6 %58
+ %60 = OpFOrdNotEqual %30 %59 %55
+ %61 = OpLoad %34 %36
+ %211 = OpCompositeExtract %30 %105 2
+ %62 = OpLogicalAnd %30 %45 %211
+ %209 = OpCompositeExtract %30 %104 1
+ %63 = OpLogicalOr %30 %209 %46
+ %64 = OpCompositeConstruct %48 %56 %60 %62 %63
+ %202 = OpVectorShuffle %10 %101 %101 0 1
+ OpStore %12 %202
+ %203 = OpVectorShuffle %10 %101 %101 2 3
+ %81 = OpVectorShuffle %16 %203 %19 0 0 1
+ %204 = OpCompositeExtract %6 %102 0
+ %82 = OpCompositeConstruct %21 %26 %204 %28 %25
+ %205 = OpVectorShuffle %10 %102 %102 1 2
+ %83 = OpCopyObject %10 %205
+ %207 = OpVectorShuffle %39 %103 %103 1 2 3
+ %84 = OpCopyObject %39 %207
+ OpStore %50 %64
+ %208 = OpCompositeExtract %30 %104 0
+ %85 = OpCopyObject %30 %208
+ %210 = OpVectorShuffle %34 %105 %105 0 1
+ OpStore %36 %210
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/equivalence_relation_test.cpp b/test/fuzz/equivalence_relation_test.cpp
new file mode 100644
index 0000000..3f2ea58
--- /dev/null
+++ b/test/fuzz/equivalence_relation_test.cpp
@@ -0,0 +1,145 @@
+// 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 <set>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "source/fuzz/equivalence_relation.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+struct UInt32Equals {
+ bool operator()(const uint32_t* first, const uint32_t* second) const {
+ return *first == *second;
+ }
+};
+
+struct UInt32Hash {
+ size_t operator()(const uint32_t* element) const {
+ return static_cast<size_t>(*element);
+ }
+};
+
+std::vector<uint32_t> ToUIntVector(
+ const std::vector<const uint32_t*>& pointers) {
+ std::vector<uint32_t> result;
+ for (auto pointer : pointers) {
+ result.push_back(*pointer);
+ }
+ return result;
+}
+
+TEST(EquivalenceRelationTest, BasicTest) {
+ EquivalenceRelation<uint32_t, UInt32Hash, UInt32Equals> relation;
+ ASSERT_TRUE(relation.GetAllKnownValues().empty());
+
+ for (uint32_t element = 2; element < 80; element += 2) {
+ relation.MakeEquivalent(0, element);
+ relation.MakeEquivalent(element - 1, element + 1);
+ }
+
+ for (uint32_t element = 82; element < 100; element += 2) {
+ relation.MakeEquivalent(80, element);
+ relation.MakeEquivalent(element - 1, element + 1);
+ }
+
+ relation.MakeEquivalent(78, 80);
+
+ std::vector<uint32_t> class1;
+ for (uint32_t element = 0; element < 98; element += 2) {
+ ASSERT_TRUE(relation.IsEquivalent(0, element));
+ ASSERT_TRUE(relation.IsEquivalent(element, element + 2));
+ class1.push_back(element);
+ }
+ class1.push_back(98);
+
+ ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(0)),
+ testing::WhenSorted(class1));
+ ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(4)),
+ testing::WhenSorted(class1));
+ ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(40)),
+ testing::WhenSorted(class1));
+
+ std::vector<uint32_t> class2;
+ for (uint32_t element = 1; element < 79; element += 2) {
+ ASSERT_TRUE(relation.IsEquivalent(1, element));
+ ASSERT_TRUE(relation.IsEquivalent(element, element + 2));
+ class2.push_back(element);
+ }
+ class2.push_back(79);
+ ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(1)),
+ testing::WhenSorted(class2));
+ ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(11)),
+ testing::WhenSorted(class2));
+ ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(31)),
+ testing::WhenSorted(class2));
+
+ std::vector<uint32_t> class3;
+ for (uint32_t element = 81; element < 99; element += 2) {
+ ASSERT_TRUE(relation.IsEquivalent(81, element));
+ ASSERT_TRUE(relation.IsEquivalent(element, element + 2));
+ class3.push_back(element);
+ }
+ class3.push_back(99);
+ ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(81)),
+ testing::WhenSorted(class3));
+ ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(91)),
+ testing::WhenSorted(class3));
+ ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(99)),
+ testing::WhenSorted(class3));
+
+ bool first = true;
+ std::vector<const uint32_t*> previous_class;
+ for (auto representative : relation.GetEquivalenceClassRepresentatives()) {
+ std::vector<const uint32_t*> current_class =
+ relation.GetEquivalenceClass(*representative);
+ ASSERT_TRUE(std::find(current_class.begin(), current_class.end(),
+ representative) != current_class.end());
+ if (!first) {
+ ASSERT_TRUE(std::find(previous_class.begin(), previous_class.end(),
+ representative) == previous_class.end());
+ }
+ previous_class = current_class;
+ first = false;
+ }
+}
+
+TEST(EquivalenceRelationTest, DeterministicEquivalenceClassOrder) {
+ EquivalenceRelation<uint32_t, UInt32Hash, UInt32Equals> relation1;
+ EquivalenceRelation<uint32_t, UInt32Hash, UInt32Equals> relation2;
+
+ for (uint32_t i = 0; i < 1000; ++i) {
+ if (i >= 10) {
+ relation1.MakeEquivalent(i, i - 10);
+ relation2.MakeEquivalent(i, i - 10);
+ }
+ }
+
+ // We constructed the equivalence relations in the same way, so we would like
+ // them to have identical representatives, and identically-ordered equivalence
+ // classes per representative.
+ ASSERT_THAT(ToUIntVector(relation1.GetEquivalenceClassRepresentatives()),
+ ToUIntVector(relation2.GetEquivalenceClassRepresentatives()));
+ for (auto representative : relation1.GetEquivalenceClassRepresentatives()) {
+ ASSERT_THAT(ToUIntVector(relation1.GetEquivalenceClass(*representative)),
+ ToUIntVector(relation2.GetEquivalenceClass(*representative)));
+ }
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/fact_manager_test.cpp b/test/fuzz/fact_manager_test.cpp
index 738f8c9..b3f32cd 100644
--- a/test/fuzz/fact_manager_test.cpp
+++ b/test/fuzz/fact_manager_test.cpp
@@ -738,6 +738,441 @@
uniform_buffer_element_descriptor));
}
+TEST(FactManagerTest, DataSynonymFacts) {
+ // The SPIR-V types and constants come from the following code. The body of
+ // the SPIR-V function then constructs a composite that is synonymous with
+ // myT.
+ //
+ // #version 310 es
+ //
+ // precision highp float;
+ //
+ // struct S {
+ // int a;
+ // uvec2 b;
+ // };
+ //
+ // struct T {
+ // bool c[5];
+ // mat4x2 d;
+ // S e;
+ // };
+ //
+ // void main() {
+ // T myT = T(bool[5](true, false, true, false, true),
+ // mat4x2(vec2(1.0, 2.0), vec2(3.0, 4.0),
+ // vec2(5.0, 6.0), vec2(7.0, 8.0)),
+ // S(10, uvec2(100u, 200u)));
+ // }
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %15 "S"
+ OpMemberName %15 0 "a"
+ OpMemberName %15 1 "b"
+ OpName %16 "T"
+ OpMemberName %16 0 "c"
+ OpMemberName %16 1 "d"
+ OpMemberName %16 2 "e"
+ OpName %18 "myT"
+ OpMemberDecorate %15 0 RelaxedPrecision
+ OpMemberDecorate %15 1 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeBool
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 5
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypeFloat 32
+ %11 = OpTypeVector %10 2
+ %12 = OpTypeMatrix %11 4
+ %13 = OpTypeInt 32 1
+ %14 = OpTypeVector %7 2
+ %15 = OpTypeStruct %13 %14
+ %16 = OpTypeStruct %9 %12 %15
+ %17 = OpTypePointer Function %16
+ %19 = OpConstantTrue %6
+ %20 = OpConstantFalse %6
+ %21 = OpConstantComposite %9 %19 %20 %19 %20 %19
+ %22 = OpConstant %10 1
+ %23 = OpConstant %10 2
+ %24 = OpConstantComposite %11 %22 %23
+ %25 = OpConstant %10 3
+ %26 = OpConstant %10 4
+ %27 = OpConstantComposite %11 %25 %26
+ %28 = OpConstant %10 5
+ %29 = OpConstant %10 6
+ %30 = OpConstantComposite %11 %28 %29
+ %31 = OpConstant %10 7
+ %32 = OpConstant %10 8
+ %33 = OpConstantComposite %11 %31 %32
+ %34 = OpConstantComposite %12 %24 %27 %30 %33
+ %35 = OpConstant %13 10
+ %36 = OpConstant %7 100
+ %37 = OpConstant %7 200
+ %38 = OpConstantComposite %14 %36 %37
+ %39 = OpConstantComposite %15 %35 %38
+ %40 = OpConstantComposite %16 %21 %34 %39
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %18 = OpVariable %17 Function
+ OpStore %18 %40
+ %100 = OpCompositeConstruct %9 %19 %20 %19 %20 %19
+ %101 = OpCompositeConstruct %11 %22 %23
+ %102 = OpCompositeConstruct %11 %25 %26
+ %103 = OpCompositeConstruct %11 %28 %29
+ %104 = OpCompositeConstruct %11 %31 %32
+ %105 = OpCompositeConstruct %12 %101 %102 %103 %104
+ %106 = OpCompositeConstruct %14 %36 %37
+ %107 = OpCompositeConstruct %15 %35 %106
+ %108 = OpCompositeConstruct %16 %100 %105 %107
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(24, {}), MakeDataDescriptor(101, {}), context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}),
+ MakeDataDescriptor(101, {0}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {1}),
+ MakeDataDescriptor(101, {1}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}),
+ MakeDataDescriptor(101, {1}),
+ context.get()));
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(24, {}),
+ MakeDataDescriptor(101, {}), context.get());
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(24, {}), MakeDataDescriptor(101, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}),
+ MakeDataDescriptor(101, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {1}),
+ MakeDataDescriptor(101, {1}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}),
+ MakeDataDescriptor(101, {1}),
+ context.get()));
+
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(27, {}), MakeDataDescriptor(102, {}), context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {0}),
+ MakeDataDescriptor(102, {0}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {1}),
+ MakeDataDescriptor(102, {1}),
+ context.get()));
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(27, {0}),
+ MakeDataDescriptor(102, {0}), context.get());
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(27, {}), MakeDataDescriptor(102, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {0}),
+ MakeDataDescriptor(102, {0}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {1}),
+ MakeDataDescriptor(102, {1}),
+ context.get()));
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(27, {1}),
+ MakeDataDescriptor(102, {1}), context.get());
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(27, {}), MakeDataDescriptor(102, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {0}),
+ MakeDataDescriptor(102, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {1}),
+ MakeDataDescriptor(102, {1}),
+ context.get()));
+
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(30, {}), MakeDataDescriptor(103, {}), context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {0}),
+ MakeDataDescriptor(103, {0}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {1}),
+ MakeDataDescriptor(103, {1}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(33, {}), MakeDataDescriptor(104, {}), context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {0}),
+ MakeDataDescriptor(104, {0}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {1}),
+ MakeDataDescriptor(104, {1}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(34, {}), MakeDataDescriptor(105, {}), context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {0}),
+ MakeDataDescriptor(105, {0}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {1}),
+ MakeDataDescriptor(105, {1}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {2}),
+ MakeDataDescriptor(105, {2}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {3}),
+ MakeDataDescriptor(105, {3}),
+ context.get()));
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(30, {}),
+ MakeDataDescriptor(103, {}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(33, {}),
+ MakeDataDescriptor(104, {}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {0}),
+ MakeDataDescriptor(105, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {1}),
+ MakeDataDescriptor(105, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {2}),
+ MakeDataDescriptor(105, {2}), context.get());
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(30, {}), MakeDataDescriptor(103, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {0}),
+ MakeDataDescriptor(103, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {1}),
+ MakeDataDescriptor(103, {1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(33, {}), MakeDataDescriptor(104, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {0}),
+ MakeDataDescriptor(104, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {1}),
+ MakeDataDescriptor(104, {1}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(34, {}), MakeDataDescriptor(105, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {0}),
+ MakeDataDescriptor(105, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {1}),
+ MakeDataDescriptor(105, {1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {2}),
+ MakeDataDescriptor(105, {2}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {3}),
+ MakeDataDescriptor(105, {3}),
+ context.get()));
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {3}),
+ MakeDataDescriptor(105, {3}), context.get());
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {0}),
+ MakeDataDescriptor(104, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {3}),
+ MakeDataDescriptor(105, {3}),
+ context.get()));
+
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(21, {}), MakeDataDescriptor(100, {}), context.get()));
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {0}),
+ MakeDataDescriptor(100, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {1}),
+ MakeDataDescriptor(100, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {2}),
+ MakeDataDescriptor(100, {2}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {3}),
+ MakeDataDescriptor(100, {3}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {4}),
+ MakeDataDescriptor(100, {4}), context.get());
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(21, {}), MakeDataDescriptor(100, {}), context.get()));
+
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(39, {0}),
+ MakeDataDescriptor(107, {0}),
+ context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(35, {}), MakeDataDescriptor(39, {0}), context.get()));
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(39, {0}),
+ MakeDataDescriptor(35, {}), context.get());
+ ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(39, {0}),
+ MakeDataDescriptor(107, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(35, {}), MakeDataDescriptor(39, {0}), context.get()));
+
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(38, {0}), MakeDataDescriptor(36, {}), context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(38, {1}), MakeDataDescriptor(37, {}), context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(106, {0}), MakeDataDescriptor(36, {}), context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(106, {1}), MakeDataDescriptor(37, {}), context.get()));
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(38, {}), MakeDataDescriptor(106, {}), context.get()));
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(38, {0}),
+ MakeDataDescriptor(36, {}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(106, {0}),
+ MakeDataDescriptor(36, {}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(38, {1}),
+ MakeDataDescriptor(37, {}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(106, {1}),
+ MakeDataDescriptor(37, {}), context.get());
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(38, {0}), MakeDataDescriptor(36, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(38, {1}), MakeDataDescriptor(37, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(106, {0}), MakeDataDescriptor(36, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(106, {1}), MakeDataDescriptor(37, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(38, {}), MakeDataDescriptor(106, {}), context.get()));
+
+ ASSERT_FALSE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(40, {}), MakeDataDescriptor(108, {}), context.get()));
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(107, {0}),
+ MakeDataDescriptor(35, {}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {0}),
+ MakeDataDescriptor(108, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {1}),
+ MakeDataDescriptor(108, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {2}),
+ MakeDataDescriptor(108, {2}), context.get());
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(40, {}), MakeDataDescriptor(108, {}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0}),
+ MakeDataDescriptor(108, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1}),
+ MakeDataDescriptor(108, {1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2}),
+ MakeDataDescriptor(108, {2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 0}),
+ MakeDataDescriptor(108, {0, 0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 1}),
+ MakeDataDescriptor(108, {0, 1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 2}),
+ MakeDataDescriptor(108, {0, 2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 3}),
+ MakeDataDescriptor(108, {0, 3}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 4}),
+ MakeDataDescriptor(108, {0, 4}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 0}),
+ MakeDataDescriptor(108, {1, 0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 1}),
+ MakeDataDescriptor(108, {1, 1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 2}),
+ MakeDataDescriptor(108, {1, 2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 3}),
+ MakeDataDescriptor(108, {1, 3}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 0, 0}),
+ MakeDataDescriptor(108, {1, 0, 0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 1, 0}),
+ MakeDataDescriptor(108, {1, 1, 0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 2, 0}),
+ MakeDataDescriptor(108, {1, 2, 0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 3, 0}),
+ MakeDataDescriptor(108, {1, 3, 0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 0, 1}),
+ MakeDataDescriptor(108, {1, 0, 1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 1, 1}),
+ MakeDataDescriptor(108, {1, 1, 1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 2, 1}),
+ MakeDataDescriptor(108, {1, 2, 1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 3, 1}),
+ MakeDataDescriptor(108, {1, 3, 1}),
+ context.get()));
+
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 0}),
+ MakeDataDescriptor(108, {2, 0}),
+ context.get()));
+
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 1}),
+ MakeDataDescriptor(108, {2, 1}),
+ context.get()));
+
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 1, 0}),
+ MakeDataDescriptor(108, {2, 1, 0}),
+ context.get()));
+
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 1, 1}),
+ MakeDataDescriptor(108, {2, 1, 1}),
+ context.get()));
+}
+
+TEST(FactManagerTest, RecursiveAdditionOfFacts) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %12 "main"
+ OpExecutionMode %12 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 4
+ %8 = OpTypeMatrix %7 4
+ %9 = OpConstant %6 0
+ %10 = OpConstantComposite %7 %9 %9 %9 %9
+ %11 = OpConstantComposite %8 %10 %10 %10 %10
+ %12 = OpFunction %2 None %3
+ %13 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
+ MakeDataDescriptor(11, {2}), context.get());
+
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(10, {}), MakeDataDescriptor(11, {2}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {0}),
+ MakeDataDescriptor(11, {2, 0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {1}),
+ MakeDataDescriptor(11, {2, 1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {2}),
+ MakeDataDescriptor(11, {2, 2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {3}),
+ MakeDataDescriptor(11, {2, 3}),
+ context.get()));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools
diff --git a/test/fuzz/fuzz_test_util.cpp b/test/fuzz/fuzz_test_util.cpp
index e2b9518..bc6d4ee 100644
--- a/test/fuzz/fuzz_test_util.cpp
+++ b/test/fuzz/fuzz_test_util.cpp
@@ -16,6 +16,8 @@
#include <iostream>
+#include "tools/io.h"
+
namespace spvtools {
namespace fuzz {
@@ -89,5 +91,19 @@
return result;
}
+void DumpShader(opt::IRContext* context, const char* filename) {
+ std::vector<uint32_t> binary;
+ context->module()->ToBinary(&binary, false);
+ DumpShader(binary, filename);
+}
+
+void DumpShader(const std::vector<uint32_t>& binary, const char* filename) {
+ auto write_file_succeeded =
+ WriteFile(filename, "wb", &binary[0], binary.size());
+ if (!write_file_succeeded) {
+ std::cerr << "Failed to dump shader" << std::endl;
+ }
+}
+
} // namespace fuzz
} // namespace spvtools
diff --git a/test/fuzz/fuzz_test_util.h b/test/fuzz/fuzz_test_util.h
index 88a0b20..93f37e5 100644
--- a/test/fuzz/fuzz_test_util.h
+++ b/test/fuzz/fuzz_test_util.h
@@ -93,6 +93,13 @@
}
};
+// Dumps the SPIRV-V module in |context| to file |filename|. Useful for
+// interactive debugging.
+void DumpShader(opt::IRContext* context, const char* filename);
+
+// Dumps |binary| to file |filename|. Useful for interactive debugging.
+void DumpShader(const std::vector<uint32_t>& binary, const char* filename);
+
} // namespace fuzz
} // namespace spvtools
diff --git a/test/fuzz/fuzzer_replayer_test.cpp b/test/fuzz/fuzzer_replayer_test.cpp
index 550c4fc..22a26fc 100644
--- a/test/fuzz/fuzzer_replayer_test.cpp
+++ b/test/fuzz/fuzzer_replayer_test.cpp
@@ -21,6 +21,28 @@
namespace fuzz {
namespace {
+const uint32_t kNumFuzzerRuns = 20;
+
+void AddConstantUniformFact(protobufs::FactSequence* facts,
+ uint32_t descriptor_set, uint32_t binding,
+ std::vector<uint32_t>&& indices, uint32_t value) {
+ protobufs::FactConstantUniform fact;
+ *fact.mutable_uniform_buffer_element_descriptor() =
+ MakeUniformBufferElementDescriptor(descriptor_set, binding,
+ std::move(indices));
+ *fact.mutable_constant_word()->Add() = value;
+ protobufs::Fact temp;
+ *temp.mutable_constant_uniform_fact() = fact;
+ *facts->mutable_fact()->Add() = temp;
+}
+
+// Reinterpret the bits of |value| as a 32-bit unsigned int
+uint32_t FloatBitsAsUint(float value) {
+ uint32_t result;
+ memcpy(&result, &value, sizeof(float));
+ return result;
+}
+
// Assembles the given |shader| text, and then runs the fuzzer |num_runs|
// times, using successive seeds starting from |initial_seed|. Checks that
// the binary produced after each fuzzer run is valid, and that replaying
@@ -29,7 +51,7 @@
void RunFuzzerAndReplayer(const std::string& shader,
const protobufs::FactSequence& initial_facts,
uint32_t initial_seed, uint32_t num_runs) {
- const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto env = SPV_ENV_UNIVERSAL_1_5;
std::vector<uint32_t> binary_in;
SpirvTools t(env);
@@ -54,7 +76,7 @@
std::vector<uint32_t> replayer_binary_out;
protobufs::TransformationSequence replayer_transformation_sequence_out;
- Replayer replayer(env);
+ Replayer replayer(env, false);
replayer.SetMessageConsumer(kSilentConsumer);
auto replayer_result_status = replayer.Run(
binary_in, initial_facts, fuzzer_transformation_sequence_out,
@@ -240,9 +262,9 @@
OpFunctionEnd
)";
- // Do 5 fuzzer runs, starting from an initial seed of 0 (seed value chosen
+ // Do some fuzzer runs, starting from an initial seed of 0 (seed value chosen
// arbitrarily).
- RunFuzzerAndReplayer(shader, protobufs::FactSequence(), 0, 5);
+ RunFuzzerAndReplayer(shader, protobufs::FactSequence(), 0, kNumFuzzerRuns);
}
TEST(FuzzerReplayerTest, Miscellaneous2) {
@@ -303,7 +325,7 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main" %16 %139
+ OpEntryPoint Fragment %4 "main" %16 %139 %25 %68
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
@@ -485,9 +507,9 @@
OpFunctionEnd
)";
- // Do 5 fuzzer runs, starting from an initial seed of 10 (seed value chosen
+ // Do some fuzzer runs, starting from an initial seed of 10 (seed value chosen
// arbitrarily).
- RunFuzzerAndReplayer(shader, protobufs::FactSequence(), 10, 5);
+ RunFuzzerAndReplayer(shader, protobufs::FactSequence(), 10, kNumFuzzerRuns);
}
TEST(FuzzerReplayerTest, Miscellaneous3) {
@@ -603,7 +625,7 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main" %68 %100
+ OpEntryPoint Fragment %4 "main" %68 %100 %24
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
@@ -951,28 +973,657 @@
// Add the facts "resolution.x == 250" and "resolution.y == 100".
protobufs::FactSequence facts;
- {
- protobufs::FactConstantUniform resolution_x_eq_250;
- *resolution_x_eq_250.mutable_uniform_buffer_element_descriptor() =
- MakeUniformBufferElementDescriptor(0, 0, {0, 0});
- *resolution_x_eq_250.mutable_constant_word()->Add() = 250;
- protobufs::Fact temp;
- *temp.mutable_constant_uniform_fact() = resolution_x_eq_250;
- *facts.mutable_fact()->Add() = temp;
- }
- {
- protobufs::FactConstantUniform resolution_y_eq_100;
- *resolution_y_eq_100.mutable_uniform_buffer_element_descriptor() =
- MakeUniformBufferElementDescriptor(0, 0, {0, 1});
- *resolution_y_eq_100.mutable_constant_word()->Add() = 100;
- protobufs::Fact temp;
- *temp.mutable_constant_uniform_fact() = resolution_y_eq_100;
- *facts.mutable_fact()->Add() = temp;
- }
+ AddConstantUniformFact(&facts, 0, 0, {0, 0}, 250);
+ AddConstantUniformFact(&facts, 0, 0, {0, 1}, 100);
- // Do 5 fuzzer runs, starting from an initial seed of 94 (seed value chosen
+ // Do some fuzzer runs, starting from an initial seed of 94 (seed value chosen
// arbitrarily).
- RunFuzzerAndReplayer(shader, facts, 94, 5);
+ RunFuzzerAndReplayer(shader, facts, 94, kNumFuzzerRuns);
+}
+
+TEST(FuzzerReplayerTest, Miscellaneous4) {
+ // The SPIR-V comes from the 'matrices_smart_loops' GLSL shader that ships
+ // with GraphicsFuzz.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %327 %363 %65 %70 %80 %90 %99 %108 %117 %126 %135 %144 %333
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "matrix_number"
+ OpName %12 "cols"
+ OpName %23 "rows"
+ OpName %31 "c"
+ OpName %41 "r"
+ OpName %65 "m22"
+ OpName %68 "buf0"
+ OpMemberName %68 0 "one"
+ OpName %70 ""
+ OpName %80 "m23"
+ OpName %90 "m24"
+ OpName %99 "m32"
+ OpName %108 "m33"
+ OpName %117 "m34"
+ OpName %126 "m42"
+ OpName %135 "m43"
+ OpName %144 "m44"
+ OpName %164 "sum_index"
+ OpName %165 "cols"
+ OpName %173 "rows"
+ OpName %184 "sums"
+ OpName %189 "c"
+ OpName %198 "r"
+ OpName %325 "region_x"
+ OpName %327 "gl_FragCoord"
+ OpName %331 "buf1"
+ OpMemberName %331 0 "resolution"
+ OpName %333 ""
+ OpName %340 "region_y"
+ OpName %348 "overall_region"
+ OpName %363 "_GLF_color"
+ OpDecorate %8 RelaxedPrecision
+ OpDecorate %12 RelaxedPrecision
+ OpDecorate %19 RelaxedPrecision
+ OpDecorate %23 RelaxedPrecision
+ OpDecorate %29 RelaxedPrecision
+ OpDecorate %31 RelaxedPrecision
+ OpDecorate %38 RelaxedPrecision
+ OpDecorate %39 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ OpDecorate %47 RelaxedPrecision
+ OpDecorate %48 RelaxedPrecision
+ OpDecorate %50 RelaxedPrecision
+ OpDecorate %66 RelaxedPrecision
+ OpDecorate %67 RelaxedPrecision
+ OpMemberDecorate %68 0 Offset 0
+ OpDecorate %68 Block
+ OpDecorate %70 DescriptorSet 0
+ OpDecorate %70 Binding 0
+ OpDecorate %81 RelaxedPrecision
+ OpDecorate %82 RelaxedPrecision
+ OpDecorate %91 RelaxedPrecision
+ OpDecorate %92 RelaxedPrecision
+ OpDecorate %100 RelaxedPrecision
+ OpDecorate %101 RelaxedPrecision
+ OpDecorate %109 RelaxedPrecision
+ OpDecorate %110 RelaxedPrecision
+ OpDecorate %118 RelaxedPrecision
+ OpDecorate %119 RelaxedPrecision
+ OpDecorate %127 RelaxedPrecision
+ OpDecorate %128 RelaxedPrecision
+ OpDecorate %136 RelaxedPrecision
+ OpDecorate %137 RelaxedPrecision
+ OpDecorate %145 RelaxedPrecision
+ OpDecorate %146 RelaxedPrecision
+ OpDecorate %152 RelaxedPrecision
+ OpDecorate %154 RelaxedPrecision
+ OpDecorate %155 RelaxedPrecision
+ OpDecorate %156 RelaxedPrecision
+ OpDecorate %157 RelaxedPrecision
+ OpDecorate %159 RelaxedPrecision
+ OpDecorate %160 RelaxedPrecision
+ OpDecorate %161 RelaxedPrecision
+ OpDecorate %162 RelaxedPrecision
+ OpDecorate %163 RelaxedPrecision
+ OpDecorate %164 RelaxedPrecision
+ OpDecorate %165 RelaxedPrecision
+ OpDecorate %171 RelaxedPrecision
+ OpDecorate %173 RelaxedPrecision
+ OpDecorate %179 RelaxedPrecision
+ OpDecorate %185 RelaxedPrecision
+ OpDecorate %189 RelaxedPrecision
+ OpDecorate %195 RelaxedPrecision
+ OpDecorate %196 RelaxedPrecision
+ OpDecorate %198 RelaxedPrecision
+ OpDecorate %204 RelaxedPrecision
+ OpDecorate %205 RelaxedPrecision
+ OpDecorate %207 RelaxedPrecision
+ OpDecorate %218 RelaxedPrecision
+ OpDecorate %219 RelaxedPrecision
+ OpDecorate %220 RelaxedPrecision
+ OpDecorate %228 RelaxedPrecision
+ OpDecorate %229 RelaxedPrecision
+ OpDecorate %230 RelaxedPrecision
+ OpDecorate %238 RelaxedPrecision
+ OpDecorate %239 RelaxedPrecision
+ OpDecorate %240 RelaxedPrecision
+ OpDecorate %248 RelaxedPrecision
+ OpDecorate %249 RelaxedPrecision
+ OpDecorate %250 RelaxedPrecision
+ OpDecorate %258 RelaxedPrecision
+ OpDecorate %259 RelaxedPrecision
+ OpDecorate %260 RelaxedPrecision
+ OpDecorate %268 RelaxedPrecision
+ OpDecorate %269 RelaxedPrecision
+ OpDecorate %270 RelaxedPrecision
+ OpDecorate %278 RelaxedPrecision
+ OpDecorate %279 RelaxedPrecision
+ OpDecorate %280 RelaxedPrecision
+ OpDecorate %288 RelaxedPrecision
+ OpDecorate %289 RelaxedPrecision
+ OpDecorate %290 RelaxedPrecision
+ OpDecorate %298 RelaxedPrecision
+ OpDecorate %299 RelaxedPrecision
+ OpDecorate %300 RelaxedPrecision
+ OpDecorate %309 RelaxedPrecision
+ OpDecorate %310 RelaxedPrecision
+ OpDecorate %311 RelaxedPrecision
+ OpDecorate %312 RelaxedPrecision
+ OpDecorate %313 RelaxedPrecision
+ OpDecorate %319 RelaxedPrecision
+ OpDecorate %320 RelaxedPrecision
+ OpDecorate %321 RelaxedPrecision
+ OpDecorate %322 RelaxedPrecision
+ OpDecorate %323 RelaxedPrecision
+ OpDecorate %324 RelaxedPrecision
+ OpDecorate %325 RelaxedPrecision
+ OpDecorate %327 BuiltIn FragCoord
+ OpMemberDecorate %331 0 Offset 0
+ OpDecorate %331 Block
+ OpDecorate %333 DescriptorSet 0
+ OpDecorate %333 Binding 1
+ OpDecorate %339 RelaxedPrecision
+ OpDecorate %340 RelaxedPrecision
+ OpDecorate %347 RelaxedPrecision
+ OpDecorate %348 RelaxedPrecision
+ OpDecorate %349 RelaxedPrecision
+ OpDecorate %351 RelaxedPrecision
+ OpDecorate %352 RelaxedPrecision
+ OpDecorate %353 RelaxedPrecision
+ OpDecorate %354 RelaxedPrecision
+ OpDecorate %356 RelaxedPrecision
+ OpDecorate %363 Location 0
+ OpDecorate %364 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 0
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %10 = OpTypeInt 32 1
+ %11 = OpTypePointer Function %10
+ %13 = OpConstant %10 2
+ %20 = OpConstant %10 4
+ %21 = OpTypeBool
+ %32 = OpConstant %10 0
+ %61 = OpTypeFloat 32
+ %62 = OpTypeVector %61 2
+ %63 = OpTypeMatrix %62 2
+ %64 = OpTypePointer Private %63
+ %65 = OpVariable %64 Private
+ %68 = OpTypeStruct %61
+ %69 = OpTypePointer Uniform %68
+ %70 = OpVariable %69 Uniform
+ %71 = OpTypePointer Uniform %61
+ %74 = OpTypePointer Private %61
+ %77 = OpTypeVector %61 3
+ %78 = OpTypeMatrix %77 2
+ %79 = OpTypePointer Private %78
+ %80 = OpVariable %79 Private
+ %87 = OpTypeVector %61 4
+ %88 = OpTypeMatrix %87 2
+ %89 = OpTypePointer Private %88
+ %90 = OpVariable %89 Private
+ %97 = OpTypeMatrix %62 3
+ %98 = OpTypePointer Private %97
+ %99 = OpVariable %98 Private
+ %106 = OpTypeMatrix %77 3
+ %107 = OpTypePointer Private %106
+ %108 = OpVariable %107 Private
+ %115 = OpTypeMatrix %87 3
+ %116 = OpTypePointer Private %115
+ %117 = OpVariable %116 Private
+ %124 = OpTypeMatrix %62 4
+ %125 = OpTypePointer Private %124
+ %126 = OpVariable %125 Private
+ %133 = OpTypeMatrix %77 4
+ %134 = OpTypePointer Private %133
+ %135 = OpVariable %134 Private
+ %142 = OpTypeMatrix %87 4
+ %143 = OpTypePointer Private %142
+ %144 = OpVariable %143 Private
+ %153 = OpConstant %10 1
+ %158 = OpConstant %6 1
+ %181 = OpConstant %6 9
+ %182 = OpTypeArray %61 %181
+ %183 = OpTypePointer Function %182
+ %186 = OpConstant %61 0
+ %187 = OpTypePointer Function %61
+ %314 = OpConstant %61 16
+ %326 = OpTypePointer Input %87
+ %327 = OpVariable %326 Input
+ %328 = OpTypePointer Input %61
+ %331 = OpTypeStruct %62
+ %332 = OpTypePointer Uniform %331
+ %333 = OpVariable %332 Uniform
+ %336 = OpConstant %61 3
+ %350 = OpConstant %10 3
+ %357 = OpConstant %10 9
+ %362 = OpTypePointer Output %87
+ %363 = OpVariable %362 Output
+ %368 = OpConstant %61 1
+ %374 = OpConstantComposite %87 %186 %186 %186 %368
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %12 = OpVariable %11 Function
+ %23 = OpVariable %11 Function
+ %31 = OpVariable %11 Function
+ %41 = OpVariable %11 Function
+ %164 = OpVariable %11 Function
+ %165 = OpVariable %11 Function
+ %173 = OpVariable %11 Function
+ %184 = OpVariable %183 Function
+ %189 = OpVariable %11 Function
+ %198 = OpVariable %11 Function
+ %325 = OpVariable %11 Function
+ %340 = OpVariable %11 Function
+ %348 = OpVariable %11 Function
+ OpStore %8 %9
+ OpStore %12 %13
+ OpBranch %14
+ %14 = OpLabel
+ OpLoopMerge %16 %17 None
+ OpBranch %18
+ %18 = OpLabel
+ %19 = OpLoad %10 %12
+ %22 = OpSLessThanEqual %21 %19 %20
+ OpBranchConditional %22 %15 %16
+ %15 = OpLabel
+ OpStore %23 %13
+ OpBranch %24
+ %24 = OpLabel
+ OpLoopMerge %26 %27 None
+ OpBranch %28
+ %28 = OpLabel
+ %29 = OpLoad %10 %23
+ %30 = OpSLessThanEqual %21 %29 %20
+ OpBranchConditional %30 %25 %26
+ %25 = OpLabel
+ OpStore %31 %32
+ OpBranch %33
+ %33 = OpLabel
+ OpLoopMerge %35 %36 None
+ OpBranch %37
+ %37 = OpLabel
+ %38 = OpLoad %10 %31
+ %39 = OpLoad %10 %12
+ %40 = OpSLessThan %21 %38 %39
+ OpBranchConditional %40 %34 %35
+ %34 = OpLabel
+ OpStore %41 %32
+ OpBranch %42
+ %42 = OpLabel
+ OpLoopMerge %44 %45 None
+ OpBranch %46
+ %46 = OpLabel
+ %47 = OpLoad %10 %41
+ %48 = OpLoad %10 %23
+ %49 = OpSLessThan %21 %47 %48
+ OpBranchConditional %49 %43 %44
+ %43 = OpLabel
+ %50 = OpLoad %6 %8
+ OpSelectionMerge %60 None
+ OpSwitch %50 %60 0 %51 1 %52 2 %53 3 %54 4 %55 5 %56 6 %57 7 %58 8 %59
+ %51 = OpLabel
+ %66 = OpLoad %10 %31
+ %67 = OpLoad %10 %41
+ %72 = OpAccessChain %71 %70 %32
+ %73 = OpLoad %61 %72
+ %75 = OpAccessChain %74 %65 %66 %67
+ OpStore %75 %73
+ OpBranch %60
+ %52 = OpLabel
+ %81 = OpLoad %10 %31
+ %82 = OpLoad %10 %41
+ %83 = OpAccessChain %71 %70 %32
+ %84 = OpLoad %61 %83
+ %85 = OpAccessChain %74 %80 %81 %82
+ OpStore %85 %84
+ OpBranch %60
+ %53 = OpLabel
+ %91 = OpLoad %10 %31
+ %92 = OpLoad %10 %41
+ %93 = OpAccessChain %71 %70 %32
+ %94 = OpLoad %61 %93
+ %95 = OpAccessChain %74 %90 %91 %92
+ OpStore %95 %94
+ OpBranch %60
+ %54 = OpLabel
+ %100 = OpLoad %10 %31
+ %101 = OpLoad %10 %41
+ %102 = OpAccessChain %71 %70 %32
+ %103 = OpLoad %61 %102
+ %104 = OpAccessChain %74 %99 %100 %101
+ OpStore %104 %103
+ OpBranch %60
+ %55 = OpLabel
+ %109 = OpLoad %10 %31
+ %110 = OpLoad %10 %41
+ %111 = OpAccessChain %71 %70 %32
+ %112 = OpLoad %61 %111
+ %113 = OpAccessChain %74 %108 %109 %110
+ OpStore %113 %112
+ OpBranch %60
+ %56 = OpLabel
+ %118 = OpLoad %10 %31
+ %119 = OpLoad %10 %41
+ %120 = OpAccessChain %71 %70 %32
+ %121 = OpLoad %61 %120
+ %122 = OpAccessChain %74 %117 %118 %119
+ OpStore %122 %121
+ OpBranch %60
+ %57 = OpLabel
+ %127 = OpLoad %10 %31
+ %128 = OpLoad %10 %41
+ %129 = OpAccessChain %71 %70 %32
+ %130 = OpLoad %61 %129
+ %131 = OpAccessChain %74 %126 %127 %128
+ OpStore %131 %130
+ OpBranch %60
+ %58 = OpLabel
+ %136 = OpLoad %10 %31
+ %137 = OpLoad %10 %41
+ %138 = OpAccessChain %71 %70 %32
+ %139 = OpLoad %61 %138
+ %140 = OpAccessChain %74 %135 %136 %137
+ OpStore %140 %139
+ OpBranch %60
+ %59 = OpLabel
+ %145 = OpLoad %10 %31
+ %146 = OpLoad %10 %41
+ %147 = OpAccessChain %71 %70 %32
+ %148 = OpLoad %61 %147
+ %149 = OpAccessChain %74 %144 %145 %146
+ OpStore %149 %148
+ OpBranch %60
+ %60 = OpLabel
+ OpBranch %45
+ %45 = OpLabel
+ %152 = OpLoad %10 %41
+ %154 = OpIAdd %10 %152 %153
+ OpStore %41 %154
+ OpBranch %42
+ %44 = OpLabel
+ OpBranch %36
+ %36 = OpLabel
+ %155 = OpLoad %10 %31
+ %156 = OpIAdd %10 %155 %153
+ OpStore %31 %156
+ OpBranch %33
+ %35 = OpLabel
+ %157 = OpLoad %6 %8
+ %159 = OpIAdd %6 %157 %158
+ OpStore %8 %159
+ OpBranch %27
+ %27 = OpLabel
+ %160 = OpLoad %10 %23
+ %161 = OpIAdd %10 %160 %153
+ OpStore %23 %161
+ OpBranch %24
+ %26 = OpLabel
+ OpBranch %17
+ %17 = OpLabel
+ %162 = OpLoad %10 %12
+ %163 = OpIAdd %10 %162 %153
+ OpStore %12 %163
+ OpBranch %14
+ %16 = OpLabel
+ OpStore %164 %32
+ OpStore %165 %13
+ OpBranch %166
+ %166 = OpLabel
+ OpLoopMerge %168 %169 None
+ OpBranch %170
+ %170 = OpLabel
+ %171 = OpLoad %10 %165
+ %172 = OpSLessThanEqual %21 %171 %20
+ OpBranchConditional %172 %167 %168
+ %167 = OpLabel
+ OpStore %173 %13
+ OpBranch %174
+ %174 = OpLabel
+ OpLoopMerge %176 %177 None
+ OpBranch %178
+ %178 = OpLabel
+ %179 = OpLoad %10 %173
+ %180 = OpSLessThanEqual %21 %179 %20
+ OpBranchConditional %180 %175 %176
+ %175 = OpLabel
+ %185 = OpLoad %10 %164
+ %188 = OpAccessChain %187 %184 %185
+ OpStore %188 %186
+ OpStore %189 %32
+ OpBranch %190
+ %190 = OpLabel
+ OpLoopMerge %192 %193 None
+ OpBranch %194
+ %194 = OpLabel
+ %195 = OpLoad %10 %189
+ %196 = OpLoad %10 %165
+ %197 = OpSLessThan %21 %195 %196
+ OpBranchConditional %197 %191 %192
+ %191 = OpLabel
+ OpStore %198 %32
+ OpBranch %199
+ %199 = OpLabel
+ OpLoopMerge %201 %202 None
+ OpBranch %203
+ %203 = OpLabel
+ %204 = OpLoad %10 %198
+ %205 = OpLoad %10 %173
+ %206 = OpSLessThan %21 %204 %205
+ OpBranchConditional %206 %200 %201
+ %200 = OpLabel
+ %207 = OpLoad %10 %164
+ OpSelectionMerge %217 None
+ OpSwitch %207 %217 0 %208 1 %209 2 %210 3 %211 4 %212 5 %213 6 %214 7 %215 8 %216
+ %208 = OpLabel
+ %218 = OpLoad %10 %164
+ %219 = OpLoad %10 %189
+ %220 = OpLoad %10 %198
+ %221 = OpAccessChain %74 %65 %219 %220
+ %222 = OpLoad %61 %221
+ %223 = OpAccessChain %187 %184 %218
+ %224 = OpLoad %61 %223
+ %225 = OpFAdd %61 %224 %222
+ %226 = OpAccessChain %187 %184 %218
+ OpStore %226 %225
+ OpBranch %217
+ %209 = OpLabel
+ %228 = OpLoad %10 %164
+ %229 = OpLoad %10 %189
+ %230 = OpLoad %10 %198
+ %231 = OpAccessChain %74 %80 %229 %230
+ %232 = OpLoad %61 %231
+ %233 = OpAccessChain %187 %184 %228
+ %234 = OpLoad %61 %233
+ %235 = OpFAdd %61 %234 %232
+ %236 = OpAccessChain %187 %184 %228
+ OpStore %236 %235
+ OpBranch %217
+ %210 = OpLabel
+ %238 = OpLoad %10 %164
+ %239 = OpLoad %10 %189
+ %240 = OpLoad %10 %198
+ %241 = OpAccessChain %74 %90 %239 %240
+ %242 = OpLoad %61 %241
+ %243 = OpAccessChain %187 %184 %238
+ %244 = OpLoad %61 %243
+ %245 = OpFAdd %61 %244 %242
+ %246 = OpAccessChain %187 %184 %238
+ OpStore %246 %245
+ OpBranch %217
+ %211 = OpLabel
+ %248 = OpLoad %10 %164
+ %249 = OpLoad %10 %189
+ %250 = OpLoad %10 %198
+ %251 = OpAccessChain %74 %99 %249 %250
+ %252 = OpLoad %61 %251
+ %253 = OpAccessChain %187 %184 %248
+ %254 = OpLoad %61 %253
+ %255 = OpFAdd %61 %254 %252
+ %256 = OpAccessChain %187 %184 %248
+ OpStore %256 %255
+ OpBranch %217
+ %212 = OpLabel
+ %258 = OpLoad %10 %164
+ %259 = OpLoad %10 %189
+ %260 = OpLoad %10 %198
+ %261 = OpAccessChain %74 %108 %259 %260
+ %262 = OpLoad %61 %261
+ %263 = OpAccessChain %187 %184 %258
+ %264 = OpLoad %61 %263
+ %265 = OpFAdd %61 %264 %262
+ %266 = OpAccessChain %187 %184 %258
+ OpStore %266 %265
+ OpBranch %217
+ %213 = OpLabel
+ %268 = OpLoad %10 %164
+ %269 = OpLoad %10 %189
+ %270 = OpLoad %10 %198
+ %271 = OpAccessChain %74 %117 %269 %270
+ %272 = OpLoad %61 %271
+ %273 = OpAccessChain %187 %184 %268
+ %274 = OpLoad %61 %273
+ %275 = OpFAdd %61 %274 %272
+ %276 = OpAccessChain %187 %184 %268
+ OpStore %276 %275
+ OpBranch %217
+ %214 = OpLabel
+ %278 = OpLoad %10 %164
+ %279 = OpLoad %10 %189
+ %280 = OpLoad %10 %198
+ %281 = OpAccessChain %74 %126 %279 %280
+ %282 = OpLoad %61 %281
+ %283 = OpAccessChain %187 %184 %278
+ %284 = OpLoad %61 %283
+ %285 = OpFAdd %61 %284 %282
+ %286 = OpAccessChain %187 %184 %278
+ OpStore %286 %285
+ OpBranch %217
+ %215 = OpLabel
+ %288 = OpLoad %10 %164
+ %289 = OpLoad %10 %189
+ %290 = OpLoad %10 %198
+ %291 = OpAccessChain %74 %135 %289 %290
+ %292 = OpLoad %61 %291
+ %293 = OpAccessChain %187 %184 %288
+ %294 = OpLoad %61 %293
+ %295 = OpFAdd %61 %294 %292
+ %296 = OpAccessChain %187 %184 %288
+ OpStore %296 %295
+ OpBranch %217
+ %216 = OpLabel
+ %298 = OpLoad %10 %164
+ %299 = OpLoad %10 %189
+ %300 = OpLoad %10 %198
+ %301 = OpAccessChain %74 %144 %299 %300
+ %302 = OpLoad %61 %301
+ %303 = OpAccessChain %187 %184 %298
+ %304 = OpLoad %61 %303
+ %305 = OpFAdd %61 %304 %302
+ %306 = OpAccessChain %187 %184 %298
+ OpStore %306 %305
+ OpBranch %217
+ %217 = OpLabel
+ OpBranch %202
+ %202 = OpLabel
+ %309 = OpLoad %10 %198
+ %310 = OpIAdd %10 %309 %153
+ OpStore %198 %310
+ OpBranch %199
+ %201 = OpLabel
+ OpBranch %193
+ %193 = OpLabel
+ %311 = OpLoad %10 %189
+ %312 = OpIAdd %10 %311 %153
+ OpStore %189 %312
+ OpBranch %190
+ %192 = OpLabel
+ %313 = OpLoad %10 %164
+ %315 = OpAccessChain %187 %184 %313
+ %316 = OpLoad %61 %315
+ %317 = OpFDiv %61 %316 %314
+ %318 = OpAccessChain %187 %184 %313
+ OpStore %318 %317
+ %319 = OpLoad %10 %164
+ %320 = OpIAdd %10 %319 %153
+ OpStore %164 %320
+ OpBranch %177
+ %177 = OpLabel
+ %321 = OpLoad %10 %173
+ %322 = OpIAdd %10 %321 %153
+ OpStore %173 %322
+ OpBranch %174
+ %176 = OpLabel
+ OpBranch %169
+ %169 = OpLabel
+ %323 = OpLoad %10 %165
+ %324 = OpIAdd %10 %323 %153
+ OpStore %165 %324
+ OpBranch %166
+ %168 = OpLabel
+ %329 = OpAccessChain %328 %327 %9
+ %330 = OpLoad %61 %329
+ %334 = OpAccessChain %71 %333 %32 %9
+ %335 = OpLoad %61 %334
+ %337 = OpFDiv %61 %335 %336
+ %338 = OpFDiv %61 %330 %337
+ %339 = OpConvertFToS %10 %338
+ OpStore %325 %339
+ %341 = OpAccessChain %328 %327 %158
+ %342 = OpLoad %61 %341
+ %343 = OpAccessChain %71 %333 %32 %9
+ %344 = OpLoad %61 %343
+ %345 = OpFDiv %61 %344 %336
+ %346 = OpFDiv %61 %342 %345
+ %347 = OpConvertFToS %10 %346
+ OpStore %340 %347
+ %349 = OpLoad %10 %340
+ %351 = OpIMul %10 %349 %350
+ %352 = OpLoad %10 %325
+ %353 = OpIAdd %10 %351 %352
+ OpStore %348 %353
+ %354 = OpLoad %10 %348
+ %355 = OpSGreaterThan %21 %354 %32
+ %356 = OpLoad %10 %348
+ %358 = OpSLessThan %21 %356 %357
+ %359 = OpLogicalAnd %21 %355 %358
+ OpSelectionMerge %361 None
+ OpBranchConditional %359 %360 %373
+ %360 = OpLabel
+ %364 = OpLoad %10 %348
+ %365 = OpAccessChain %187 %184 %364
+ %366 = OpLoad %61 %365
+ %367 = OpCompositeConstruct %77 %366 %366 %366
+ %369 = OpCompositeExtract %61 %367 0
+ %370 = OpCompositeExtract %61 %367 1
+ %371 = OpCompositeExtract %61 %367 2
+ %372 = OpCompositeConstruct %87 %369 %370 %371 %368
+ OpStore %363 %372
+ OpBranch %361
+ %373 = OpLabel
+ OpStore %363 %374
+ OpBranch %361
+ %361 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ // Add the facts:
+ // - "one == 1.0"
+ // - "resolution.y == 256.0",
+ protobufs::FactSequence facts;
+ AddConstantUniformFact(&facts, 0, 0, {0}, FloatBitsAsUint(1.0));
+ AddConstantUniformFact(&facts, 0, 1, {0, 0}, FloatBitsAsUint(256.0));
+ AddConstantUniformFact(&facts, 0, 1, {0, 1}, FloatBitsAsUint(256.0));
+
+ // Do some fuzzer runs, starting from an initial seed of 14 (seed value chosen
+ // arbitrarily).
+ RunFuzzerAndReplayer(shader, facts, 14, kNumFuzzerRuns);
}
} // namespace
diff --git a/test/fuzz/fuzzer_shrinker_test.cpp b/test/fuzz/fuzzer_shrinker_test.cpp
index 85f41bc..6485070 100644
--- a/test/fuzz/fuzzer_shrinker_test.cpp
+++ b/test/fuzz/fuzzer_shrinker_test.cpp
@@ -125,7 +125,7 @@
const std::vector<uint32_t>& expected_binary_out,
uint32_t expected_transformations_out_size, uint32_t step_limit) {
// Run the shrinker.
- Shrinker shrinker(target_env, step_limit);
+ Shrinker shrinker(target_env, step_limit, false);
shrinker.SetMessageConsumer(kSilentConsumer);
std::vector<uint32_t> binary_out;
@@ -154,10 +154,11 @@
void RunFuzzerAndShrinker(const std::string& shader,
const protobufs::FactSequence& initial_facts,
uint32_t seed) {
- const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto env = SPV_ENV_UNIVERSAL_1_5;
std::vector<uint32_t> binary_in;
SpirvTools t(env);
+ t.SetMessageConsumer(kConsoleMessageConsumer);
ASSERT_TRUE(t.Assemble(shader, &binary_in, kFuzzAssembleOption));
ASSERT_TRUE(t.Validate(binary_in));
@@ -433,7 +434,7 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main" %16 %139
+ OpEntryPoint Fragment %4 "main" %16 %139 %25 %68
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
@@ -731,7 +732,7 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main" %68 %100
+ OpEntryPoint Fragment %4 "main" %68 %100 %24
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
diff --git a/test/fuzz/instruction_descriptor_test.cpp b/test/fuzz/instruction_descriptor_test.cpp
new file mode 100644
index 0000000..5165cfb
--- /dev/null
+++ b/test/fuzz/instruction_descriptor_test.cpp
@@ -0,0 +1,69 @@
+// 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/fuzz/instruction_descriptor.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(InstructionDescriptorTest, BasicTest) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 0
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %10 = OpTypeInt 32 1
+ %11 = OpTypePointer Function %10
+ %13 = OpConstant %10 2
+ %32 = OpConstant %10 0
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %164 = OpVariable %11 Function
+ %165 = OpVariable %11 Function
+ OpBranch %16
+ %16 = OpLabel
+ OpStore %164 %32
+ OpStore %165 %13
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_4;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ for (auto& function : *context->module()) {
+ for (auto& block : function) {
+ for (auto inst_it = block.cbegin(); inst_it != block.cend(); ++inst_it) {
+ ASSERT_EQ(&*inst_it,
+ FindInstruction(MakeInstructionDescriptor(block, inst_it),
+ context.get()));
+ }
+ }
+ }
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/transformation_add_dead_break_test.cpp b/test/fuzz/transformation_add_dead_break_test.cpp
index 99bc9d9..1dd0c9d 100644
--- a/test/fuzz/transformation_add_dead_break_test.cpp
+++ b/test/fuzz/transformation_add_dead_break_test.cpp
@@ -2080,6 +2080,534 @@
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
+TEST(TransformationAddDeadBreakTest, RespectDominanceRules1) {
+ // Right after the loop, an OpCopyObject defined by the loop is used. Adding
+ // a dead break would prevent that use from being dominated by its definition,
+ // so is not allowed.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpLoopMerge %101 %102 None
+ OpBranch %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %104
+ %104 = OpLabel
+ OpBranch %102
+ %102 = OpLabel
+ OpBranchConditional %11 %100 %101
+ %101 = OpLabel
+ %201 = OpCopyObject %10 %200
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadBreak(100, 101, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadBreakTest, RespectDominanceRules2) {
+ // This example captures the following idiom:
+ //
+ // if {
+ // L1:
+ // }
+ // definition;
+ // L2:
+ // use;
+ //
+ // Adding a dead jump from L1 to L2 would lead to 'definition' no longer
+ // dominating 'use', and so is not allowed.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpSelectionMerge %101 None
+ OpBranchConditional %11 %102 %103
+ %102 = OpLabel
+ OpBranch %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %101
+ %101 = OpLabel
+ %201 = OpCopyObject %10 %200
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadBreakTest, RespectDominanceRules3) {
+ // Right after the loop, an OpCopyObject defined by the loop is used in an
+ // OpPhi. Adding a dead break is OK in this case, due to the use being in an
+ // OpPhi.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpLoopMerge %101 %102 None
+ OpBranch %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %104
+ %104 = OpLabel
+ OpBranch %102
+ %102 = OpLabel
+ OpBranchConditional %11 %100 %101
+ %101 = OpLabel
+ %201 = OpPhi %10 %200 %102
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto good_transformation = TransformationAddDeadBreak(100, 101, false, {11});
+ ASSERT_TRUE(good_transformation.IsApplicable(context.get(), fact_manager));
+
+ good_transformation.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpLoopMerge %101 %102 None
+ OpBranchConditional %11 %101 %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %104
+ %104 = OpLabel
+ OpBranch %102
+ %102 = OpLabel
+ OpBranchConditional %11 %100 %101
+ %101 = OpLabel
+ %201 = OpPhi %10 %200 %102 %11 %100
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationAddDeadBreakTest, RespectDominanceRules4) {
+ // This example captures the following idiom:
+ //
+ // if {
+ // L1:
+ // }
+ // definition;
+ // L2:
+ // use in OpPhi;
+ //
+ // Adding a dead jump from L1 to L2 is OK, due to 'use' being in an OpPhi.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpSelectionMerge %101 None
+ OpBranchConditional %11 %102 %103
+ %102 = OpLabel
+ OpBranch %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %101
+ %101 = OpLabel
+ %201 = OpPhi %10 %200 %103
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto good_transformation = TransformationAddDeadBreak(102, 101, false, {11});
+ ASSERT_TRUE(good_transformation.IsApplicable(context.get(), fact_manager));
+
+ good_transformation.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpSelectionMerge %101 None
+ OpBranchConditional %11 %102 %103
+ %102 = OpLabel
+ OpBranchConditional %11 %101 %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %101
+ %101 = OpLabel
+ %201 = OpPhi %10 %200 %103 %11 %102
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationAddDeadBreakTest, RespectDominanceRules5) {
+ // After, but not right after, the loop, an OpCopyObject defined by the loop
+ // is used in an OpPhi. Adding a dead break is not OK in this case.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpLoopMerge %101 %102 None
+ OpBranch %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %104
+ %104 = OpLabel
+ OpBranch %102
+ %102 = OpLabel
+ OpBranchConditional %11 %100 %101
+ %101 = OpLabel
+ OpBranch %105
+ %105 = OpLabel
+ %201 = OpPhi %10 %200 %101
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadBreak(100, 101, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadBreakTest, RespectDominanceRules6) {
+ // This example captures the following idiom:
+ //
+ // if {
+ // L1:
+ // }
+ // definition;
+ // L2:
+ // goto L3;
+ // L3:
+ // use in OpPhi;
+ //
+ // Adding a dead jump from L1 to L2 not OK, due to the use in an OpPhi being
+ // in L3.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpSelectionMerge %101 None
+ OpBranchConditional %11 %102 %103
+ %102 = OpLabel
+ OpBranch %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %101
+ %101 = OpLabel
+ OpBranch %150
+ %150 = OpLabel
+ %201 = OpPhi %10 %200 %101
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadBreakTest, RespectDominanceRules7) {
+ // This example - a variation on an earlier test - captures the following
+ // idiom:
+ //
+ // loop {
+ // L1:
+ // }
+ // definition;
+ // L2:
+ // use;
+ //
+ // Adding a dead jump from L1 to L2 would lead to 'definition' no longer
+ // dominating 'use', and so is not allowed.
+ //
+ // This version of the test captures the case where L1 appears after the
+ // loop merge (which SPIR-V dominance rules allow).
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpLoopMerge %101 %104 None
+ OpBranchConditional %11 %102 %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %101
+ %101 = OpLabel
+ %201 = OpCopyObject %10 %200
+ OpReturn
+ %102 = OpLabel
+ OpBranch %103
+ %104 = OpLabel
+ OpBranch %100
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadBreakTest, RespectDominanceRules8) {
+ // A variation of RespectDominanceRules8 where the defining block appears
+ // in the loop, but after the definition of interest.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpLoopMerge %101 %104 None
+ OpBranchConditional %11 %102 %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %101
+ %102 = OpLabel
+ OpBranch %103
+ %101 = OpLabel
+ %201 = OpCopyObject %10 %200
+ OpReturn
+ %104 = OpLabel
+ OpBranch %100
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadBreakTest,
+ BreakWouldDisobeyDominanceBlockOrderingRules) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeBool
+ %9 = OpConstantTrue %6
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %10
+ %10 = OpLabel
+ OpLoopMerge %16 %15 None
+ OpBranch %11
+ %11 = OpLabel
+ OpSelectionMerge %14 None
+ OpBranchConditional %9 %12 %13
+ %14 = OpLabel
+ OpBranch %15
+ %12 = OpLabel
+ OpBranch %16
+ %13 = OpLabel
+ OpBranch %16
+ %15 = OpLabel
+ OpBranch %10
+ %16 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // Bad because 14 comes before 12 in the module, and 14 has no predecessors.
+ // This means that an edge from 12 to 14 will lead to 12 dominating 14, which
+ // is illegal if 12 appears after 14.
+ auto bad_transformation = TransformationAddDeadBreak(12, 14, true, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools
diff --git a/test/fuzz/transformation_add_dead_continue_test.cpp b/test/fuzz/transformation_add_dead_continue_test.cpp
index 573db19..8173e72 100644
--- a/test/fuzz/transformation_add_dead_continue_test.cpp
+++ b/test/fuzz/transformation_add_dead_continue_test.cpp
@@ -1029,6 +1029,649 @@
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
+TEST(TransformationAddDeadContinueTest, RespectDominanceRules1) {
+ // Checks that a dead continue cannot be added if it would prevent a block
+ // later in the loop from dominating the loop's continue construct, in the
+ // case where said block defines and id that is used in the loop's continue
+ // construct.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %6
+ %6 = OpLabel
+ OpLoopMerge %8 %9 None
+ OpBranch %7
+ %7 = OpLabel
+ %21 = OpCopyObject %10 %11
+ OpBranch %9
+ %9 = OpLabel
+ %20 = OpPhi %10 %21 %7
+ OpBranchConditional %11 %6 %8
+ %8 = OpLabel
+ OpBranch %12
+ %12 = OpLabel
+ OpLoopMerge %14 %15 None
+ OpBranch %13
+ %13 = OpLabel
+ OpBranch %22
+ %22 = OpLabel
+ %23 = OpCopyObject %10 %11
+ OpBranch %25
+ %25 = OpLabel
+ OpBranch %15
+ %15 = OpLabel
+ %26 = OpCopyObject %10 %23
+ OpBranchConditional %11 %12 %14
+ %14 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // This transformation is not applicable because the dead continue from the
+ // loop body prevents the definition of %23 later in the loop body from
+ // dominating its use in the loop's continue target.
+ auto bad_transformation = TransformationAddDeadContinue(13, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+
+ auto good_transformation_1 = TransformationAddDeadContinue(7, false, {});
+ ASSERT_TRUE(good_transformation_1.IsApplicable(context.get(), fact_manager));
+ good_transformation_1.Apply(context.get(), &fact_manager);
+
+ auto good_transformation_2 = TransformationAddDeadContinue(22, false, {});
+ ASSERT_TRUE(good_transformation_2.IsApplicable(context.get(), fact_manager));
+ good_transformation_2.Apply(context.get(), &fact_manager);
+
+ // This transformation is OK, because the definition of %21 in the loop body
+ // is only used in an OpPhi in the loop's continue target.
+ auto good_transformation_3 = TransformationAddDeadContinue(6, false, {11});
+ ASSERT_TRUE(good_transformation_3.IsApplicable(context.get(), fact_manager));
+ good_transformation_3.Apply(context.get(), &fact_manager);
+
+ std::string after_transformations = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %6
+ %6 = OpLabel
+ OpLoopMerge %8 %9 None
+ OpBranchConditional %11 %9 %7
+ %7 = OpLabel
+ %21 = OpCopyObject %10 %11
+ OpBranchConditional %11 %9 %9
+ %9 = OpLabel
+ %20 = OpPhi %10 %21 %7 %11 %6
+ OpBranchConditional %11 %6 %8
+ %8 = OpLabel
+ OpBranch %12
+ %12 = OpLabel
+ OpLoopMerge %14 %15 None
+ OpBranch %13
+ %13 = OpLabel
+ OpBranch %22
+ %22 = OpLabel
+ %23 = OpCopyObject %10 %11
+ OpBranchConditional %11 %15 %25
+ %25 = OpLabel
+ OpBranch %15
+ %15 = OpLabel
+ %26 = OpCopyObject %10 %23
+ OpBranchConditional %11 %12 %14
+ %14 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
+}
+
+TEST(TransformationAddDeadContinueTest, RespectDominanceRules2) {
+ // Checks that a dead continue cannot be added if it would lead to a use after
+ // the loop failing to be dominated by its definition.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpLoopMerge %101 %102 None
+ OpBranch %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %104
+ %104 = OpLabel
+ OpBranch %102
+ %102 = OpLabel
+ OpBranchConditional %11 %100 %101
+ %101 = OpLabel
+ %201 = OpCopyObject %10 %200
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // This transformation would shortcut the part of the loop body that defines
+ // an id used after the loop.
+ auto bad_transformation = TransformationAddDeadContinue(100, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadContinueTest, RespectDominanceRules3) {
+ // Checks that a dead continue cannot be added if it would lead to a dominance
+ // problem with an id used in an OpPhi after the loop.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeBool
+ %11 = OpConstantFalse %10
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpLoopMerge %101 %102 None
+ OpBranch %103
+ %103 = OpLabel
+ %200 = OpCopyObject %10 %11
+ OpBranch %104
+ %104 = OpLabel
+ OpBranch %102
+ %102 = OpLabel
+ OpBranchConditional %11 %100 %101
+ %101 = OpLabel
+ %201 = OpPhi %10 %200 %102
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // This transformation would shortcut the part of the loop body that defines
+ // an id used after the loop.
+ auto bad_transformation = TransformationAddDeadContinue(100, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadContinueTest, Miscellaneous1) {
+ // A miscellaneous test that exposed a bug in spirv-fuzz.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %586 %623
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpMemberDecorate %34 0 Offset 0
+ OpDecorate %34 Block
+ OpDecorate %36 DescriptorSet 0
+ OpDecorate %36 Binding 0
+ OpDecorate %586 BuiltIn FragCoord
+ OpMemberDecorate %591 0 Offset 0
+ OpDecorate %591 Block
+ OpDecorate %593 DescriptorSet 0
+ OpDecorate %593 Binding 1
+ OpDecorate %623 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %16 = OpConstant %6 2
+ %17 = OpTypeBool
+ %27 = OpTypeFloat 32
+ %28 = OpTypeVector %27 2
+ %29 = OpTypeMatrix %28 2
+ %30 = OpTypePointer Private %29
+ %31 = OpVariable %30 Private
+ %34 = OpTypeStruct %27
+ %35 = OpTypePointer Uniform %34
+ %36 = OpVariable %35 Uniform
+ %37 = OpTypePointer Uniform %27
+ %40 = OpTypePointer Private %27
+ %43 = OpConstant %6 1
+ %62 = OpConstant %6 3
+ %64 = OpTypeVector %27 3
+ %65 = OpTypeMatrix %64 2
+ %66 = OpTypePointer Private %65
+ %67 = OpVariable %66 Private
+ %92 = OpConstant %6 4
+ %94 = OpTypeVector %27 4
+ %95 = OpTypeMatrix %94 2
+ %96 = OpTypePointer Private %95
+ %97 = OpVariable %96 Private
+ %123 = OpTypeMatrix %28 3
+ %124 = OpTypePointer Private %123
+ %125 = OpVariable %124 Private
+ %151 = OpTypeMatrix %64 3
+ %152 = OpTypePointer Private %151
+ %153 = OpVariable %152 Private
+ %179 = OpTypeMatrix %94 3
+ %180 = OpTypePointer Private %179
+ %181 = OpVariable %180 Private
+ %207 = OpTypeMatrix %28 4
+ %208 = OpTypePointer Private %207
+ %209 = OpVariable %208 Private
+ %235 = OpTypeMatrix %64 4
+ %236 = OpTypePointer Private %235
+ %237 = OpVariable %236 Private
+ %263 = OpTypeMatrix %94 4
+ %264 = OpTypePointer Private %263
+ %265 = OpVariable %264 Private
+ %275 = OpTypeInt 32 0
+ %276 = OpConstant %275 9
+ %277 = OpTypeArray %27 %276
+ %278 = OpTypePointer Function %277
+ %280 = OpConstant %27 0
+ %281 = OpTypePointer Function %27
+ %311 = OpConstant %27 16
+ %448 = OpConstant %6 5
+ %482 = OpConstant %6 6
+ %516 = OpConstant %6 7
+ %550 = OpConstant %6 8
+ %585 = OpTypePointer Input %94
+ %586 = OpVariable %585 Input
+ %587 = OpConstant %275 0
+ %588 = OpTypePointer Input %27
+ %591 = OpTypeStruct %28
+ %592 = OpTypePointer Uniform %591
+ %593 = OpVariable %592 Uniform
+ %596 = OpConstant %27 3
+ %601 = OpConstant %275 1
+ %617 = OpConstant %6 9
+ %622 = OpTypePointer Output %94
+ %623 = OpVariable %622 Output
+ %628 = OpConstant %27 1
+ %634 = OpConstantComposite %94 %280 %280 %280 %628
+ %635 = OpUndef %6
+ %636 = OpUndef %17
+ %637 = OpUndef %27
+ %638 = OpUndef %64
+ %639 = OpUndef %94
+ %640 = OpConstantTrue %17
+ %736 = OpConstantFalse %17
+ %642 = OpVariable %37 Uniform
+ %643 = OpVariable %40 Private
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %164
+ %164 = OpLabel
+ OpLoopMerge %166 %167 None
+ OpBranch %165
+ %165 = OpLabel
+ OpBranch %172
+ %172 = OpLabel
+ OpSelectionMerge %174 None
+ OpBranchConditional %640 %174 %174
+ %174 = OpLabel
+ %785 = OpCopyObject %6 %43
+ OpBranch %167
+ %167 = OpLabel
+ %190 = OpIAdd %6 %9 %785
+ OpBranchConditional %640 %164 %166
+ %166 = OpLabel
+ OpBranch %196
+ %196 = OpLabel
+ OpBranch %194
+ %194 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // This transformation would shortcut the part of the loop body that defines
+ // an id used in the continue target.
+ auto bad_transformation = TransformationAddDeadContinue(165, false, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadContinueTest, Miscellaneous2) {
+ // A miscellaneous test that exposed a bug in spirv-fuzz.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %51 = OpTypeBool
+ %395 = OpConstantTrue %51
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %389
+ %389 = OpLabel
+ OpLoopMerge %388 %391 None
+ OpBranch %339
+ %339 = OpLabel
+ OpSelectionMerge %396 None
+ OpBranchConditional %395 %388 %396
+ %396 = OpLabel
+ OpBranch %1552
+ %1552 = OpLabel
+ OpLoopMerge %1553 %1554 None
+ OpBranch %1556
+ %1556 = OpLabel
+ OpLoopMerge %1557 %1570 None
+ OpBranchConditional %395 %1562 %1557
+ %1562 = OpLabel
+ OpSelectionMerge %1570 None
+ OpBranchConditional %395 %1571 %1570
+ %1571 = OpLabel
+ OpBranch %1557
+ %1570 = OpLabel
+ OpBranch %1556
+ %1557 = OpLabel
+ OpSelectionMerge %1586 None
+ OpBranchConditional %395 %1553 %1586
+ %1586 = OpLabel
+ OpBranch %1553
+ %1554 = OpLabel
+ OpBranch %1552
+ %1553 = OpLabel
+ OpBranch %388
+ %391 = OpLabel
+ OpBranch %389
+ %388 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // This transformation would introduce a branch from a continue target to
+ // itself.
+ auto bad_transformation = TransformationAddDeadContinue(1554, true, {});
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadContinueTest, Miscellaneous3) {
+ // A miscellaneous test that exposed a bug in spirv-fuzz.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %85 = OpTypeBool
+ %434 = OpConstantFalse %85
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %234
+ %234 = OpLabel
+ OpLoopMerge %235 %236 None
+ OpBranch %259
+ %259 = OpLabel
+ OpLoopMerge %260 %274 None
+ OpBranchConditional %434 %265 %260
+ %265 = OpLabel
+ OpBranch %275
+ %275 = OpLabel
+ OpBranch %260
+ %274 = OpLabel
+ OpBranch %259
+ %260 = OpLabel
+ OpSelectionMerge %298 None
+ OpBranchConditional %434 %299 %300
+ %300 = OpLabel
+ OpBranch %235
+ %298 = OpLabel
+ OpUnreachable
+ %236 = OpLabel
+ OpBranch %234
+ %299 = OpLabel
+ OpBranch %235
+ %235 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadContinue(299, false, {});
+
+ // The continue edge would connect %299 to the previously-unreachable %236,
+ // making %299 dominate %236, and breaking the rule that block ordering must
+ // respect dominance.
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadContinueTest, Miscellaneous4) {
+ // A miscellaneous test that exposed a bug in spirv-fuzz.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "i"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %16 = OpConstant %6 100
+ %17 = OpTypeBool
+ %100 = OpConstantFalse %17
+ %21 = OpConstant %6 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ OpStore %8 %9
+ OpBranch %10
+ %13 = OpLabel
+ %20 = OpLoad %6 %8
+ %22 = OpIAdd %6 %20 %21
+ OpStore %8 %22
+ OpBranch %10
+ %10 = OpLabel
+ OpLoopMerge %12 %13 None
+ OpBranch %14
+ %14 = OpLabel
+ %15 = OpLoad %6 %8
+ %18 = OpSLessThan %17 %15 %16
+ OpBranchConditional %18 %11 %12
+ %11 = OpLabel
+ OpBranch %12
+ %12 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadContinue(10, false, {});
+
+ // The continue edge would connect %10 to the previously-unreachable %13,
+ // making %10 dominate %13, and breaking the rule that block ordering must
+ // respect dominance.
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadContinueTest, Miscellaneous5) {
+ // A miscellaneous test that exposed a bug in spirv-fuzz.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeBool
+ %7 = OpTypePointer Function %6
+ %9 = OpConstantTrue %6
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %98
+ %98 = OpLabel
+ OpLoopMerge %100 %101 None
+ OpBranch %99
+ %99 = OpLabel
+ OpSelectionMerge %111 None
+ OpBranchConditional %9 %110 %111
+ %110 = OpLabel
+ OpBranch %100
+ %111 = OpLabel
+ %200 = OpCopyObject %6 %9
+ OpBranch %101
+ %101 = OpLabel
+ %201 = OpCopyObject %6 %200
+ OpBranchConditional %9 %98 %100
+ %100 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadContinue(110, true, {});
+
+ // The continue edge would lead to the use of %200 in block %101 no longer
+ // being dominated by its definition in block %111.
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationAddDeadContinueTest, DISABLED_Miscellaneous6) {
+ // A miscellaneous test that exposing a known bug in spirv-fuzz.
+
+ // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2919): re-enable
+ // this test as an when the known issue is fixed.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeBool
+ %9 = OpConstantTrue %6
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %10
+ %10 = OpLabel
+ OpLoopMerge %13 %12 None
+ OpBranchConditional %9 %13 %11
+ %11 = OpLabel
+ %20 = OpCopyObject %6 %9
+ OpBranch %12
+ %12 = OpLabel
+ OpBranchConditional %9 %10 %13
+ %13 = OpLabel
+ %21 = OpCopyObject %6 %20
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto bad_transformation = TransformationAddDeadContinue(10, true, {});
+
+ ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools
diff --git a/test/fuzz/transformation_add_no_contraction_decoration_test.cpp b/test/fuzz/transformation_add_no_contraction_decoration_test.cpp
new file mode 100644
index 0000000..b1a87ea
--- /dev/null
+++ b/test/fuzz/transformation_add_no_contraction_decoration_test.cpp
@@ -0,0 +1,194 @@
+// 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/fuzz/transformation_add_no_contraction_decoration.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationAddNoContractionDecorationTest, BasicScenarios) {
+ // This is a simple transformation and this test handles the main cases.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "x"
+ OpName %10 "y"
+ OpName %14 "i"
+ OpDecorate %32 NoContraction
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %11 = OpConstant %6 2
+ %12 = OpTypeInt 32 1
+ %13 = OpTypePointer Function %12
+ %15 = OpConstant %12 0
+ %22 = OpConstant %12 10
+ %23 = OpTypeBool
+ %31 = OpConstant %6 3.5999999
+ %38 = OpConstant %12 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %10 = OpVariable %7 Function
+ %14 = OpVariable %13 Function
+ OpStore %8 %9
+ OpStore %10 %11
+ OpStore %14 %15
+ OpBranch %16
+ %16 = OpLabel
+ OpLoopMerge %18 %19 None
+ OpBranch %20
+ %20 = OpLabel
+ %21 = OpLoad %12 %14
+ %24 = OpSLessThan %23 %21 %22
+ OpBranchConditional %24 %17 %18
+ %17 = OpLabel
+ %25 = OpLoad %6 %10
+ %26 = OpLoad %6 %10
+ %27 = OpFMul %6 %25 %26
+ %28 = OpLoad %6 %8
+ %29 = OpFAdd %6 %28 %27
+ OpStore %8 %29
+ %30 = OpLoad %6 %10
+ %32 = OpFDiv %6 %30 %31
+ OpStore %10 %32
+ %33 = OpLoad %12 %14
+ %34 = OpConvertSToF %6 %33
+ %35 = OpLoad %6 %8
+ %36 = OpFAdd %6 %35 %34
+ OpStore %8 %36
+ OpBranch %19
+ %19 = OpLabel
+ %37 = OpLoad %12 %14
+ %39 = OpIAdd %12 %37 %38
+ OpStore %14 %39
+ OpBranch %16
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_4;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ FactManager fact_manager;
+
+ // Invalid: 200 is not an id
+ ASSERT_FALSE(TransformationAddNoContractionDecoration(200).IsApplicable(
+ context.get(), fact_manager));
+ // Invalid: 17 is a block id
+ ASSERT_FALSE(TransformationAddNoContractionDecoration(17).IsApplicable(
+ context.get(), fact_manager));
+ // Invalid: 24 is not arithmetic
+ ASSERT_FALSE(TransformationAddNoContractionDecoration(24).IsApplicable(
+ context.get(), fact_manager));
+
+ // It is valid to add NoContraction to each of these ids (and it's fine to
+ // have duplicates of the decoration, in the case of 32).
+ for (uint32_t result_id : {32u, 32u, 27u, 29u, 39u}) {
+ TransformationAddNoContractionDecoration transformation(result_id);
+ ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
+ transformation.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ }
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "x"
+ OpName %10 "y"
+ OpName %14 "i"
+ OpDecorate %32 NoContraction
+ OpDecorate %32 NoContraction
+ OpDecorate %32 NoContraction
+ OpDecorate %27 NoContraction
+ OpDecorate %29 NoContraction
+ OpDecorate %39 NoContraction
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %11 = OpConstant %6 2
+ %12 = OpTypeInt 32 1
+ %13 = OpTypePointer Function %12
+ %15 = OpConstant %12 0
+ %22 = OpConstant %12 10
+ %23 = OpTypeBool
+ %31 = OpConstant %6 3.5999999
+ %38 = OpConstant %12 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %10 = OpVariable %7 Function
+ %14 = OpVariable %13 Function
+ OpStore %8 %9
+ OpStore %10 %11
+ OpStore %14 %15
+ OpBranch %16
+ %16 = OpLabel
+ OpLoopMerge %18 %19 None
+ OpBranch %20
+ %20 = OpLabel
+ %21 = OpLoad %12 %14
+ %24 = OpSLessThan %23 %21 %22
+ OpBranchConditional %24 %17 %18
+ %17 = OpLabel
+ %25 = OpLoad %6 %10
+ %26 = OpLoad %6 %10
+ %27 = OpFMul %6 %25 %26
+ %28 = OpLoad %6 %8
+ %29 = OpFAdd %6 %28 %27
+ OpStore %8 %29
+ %30 = OpLoad %6 %10
+ %32 = OpFDiv %6 %30 %31
+ OpStore %10 %32
+ %33 = OpLoad %12 %14
+ %34 = OpConvertSToF %6 %33
+ %35 = OpLoad %6 %8
+ %36 = OpFAdd %6 %35 %34
+ OpStore %8 %36
+ OpBranch %19
+ %19 = OpLabel
+ %37 = OpLoad %12 %14
+ %39 = OpIAdd %12 %37 %38
+ OpStore %14 %39
+ OpBranch %16
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/transformation_composite_construct_test.cpp b/test/fuzz/transformation_composite_construct_test.cpp
new file mode 100644
index 0000000..d303368
--- /dev/null
+++ b/test/fuzz/transformation_composite_construct_test.cpp
@@ -0,0 +1,1356 @@
+// 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/fuzz/transformation_composite_construct.h"
+#include "source/fuzz/data_descriptor.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationCompositeConstructTest, ConstructArrays) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %11 "floats"
+ OpName %22 "x"
+ OpName %39 "vecs"
+ OpName %49 "bools"
+ OpName %60 "many_uvec3s"
+ OpDecorate %60 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 2
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpTypeInt 32 1
+ %13 = OpConstant %12 0
+ %14 = OpConstant %6 1
+ %15 = OpTypePointer Function %6
+ %17 = OpConstant %12 1
+ %18 = OpConstant %6 2
+ %20 = OpTypeVector %6 2
+ %21 = OpTypePointer Function %20
+ %32 = OpTypeBool
+ %36 = OpConstant %7 3
+ %37 = OpTypeArray %20 %36
+ %38 = OpTypePointer Private %37
+ %39 = OpVariable %38 Private
+ %40 = OpConstant %6 3
+ %41 = OpConstantComposite %20 %40 %40
+ %42 = OpTypePointer Private %20
+ %44 = OpConstant %12 2
+ %47 = OpTypeArray %32 %36
+ %48 = OpTypePointer Function %47
+ %50 = OpConstantTrue %32
+ %51 = OpTypePointer Function %32
+ %56 = OpTypeVector %7 3
+ %57 = OpTypeArray %56 %8
+ %58 = OpTypeArray %57 %8
+ %59 = OpTypePointer Function %58
+ %61 = OpConstant %7 4
+ %62 = OpConstantComposite %56 %61 %61 %61
+ %63 = OpTypePointer Function %56
+ %65 = OpConstant %7 5
+ %66 = OpConstantComposite %56 %65 %65 %65
+ %67 = OpConstant %7 6
+ %68 = OpConstantComposite %56 %67 %67 %67
+ %69 = OpConstantComposite %57 %66 %68
+ %100 = OpUndef %57
+ %70 = OpTypePointer Function %57
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %22 = OpVariable %21 Function
+ %49 = OpVariable %48 Function
+ %60 = OpVariable %59 Function
+ %16 = OpAccessChain %15 %11 %13
+ OpStore %16 %14
+ %19 = OpAccessChain %15 %11 %17
+ OpStore %19 %18
+ %23 = OpAccessChain %15 %11 %13
+ %24 = OpLoad %6 %23
+ %25 = OpAccessChain %15 %11 %17
+ %26 = OpLoad %6 %25
+ %27 = OpCompositeConstruct %20 %24 %26
+ OpStore %22 %27
+ %28 = OpAccessChain %15 %11 %13
+ %29 = OpLoad %6 %28
+ %30 = OpAccessChain %15 %11 %17
+ %31 = OpLoad %6 %30
+ %33 = OpFOrdGreaterThan %32 %29 %31
+ OpSelectionMerge %35 None
+ OpBranchConditional %33 %34 %35
+ %34 = OpLabel
+ %43 = OpAccessChain %42 %39 %17
+ OpStore %43 %41
+ %45 = OpLoad %20 %22
+ %46 = OpAccessChain %42 %39 %44
+ OpStore %46 %45
+ OpBranch %35
+ %35 = OpLabel
+ %52 = OpAccessChain %51 %49 %13
+ OpStore %52 %50
+ %53 = OpAccessChain %51 %49 %13
+ %54 = OpLoad %32 %53
+ %55 = OpAccessChain %51 %49 %17
+ OpStore %55 %54
+ %64 = OpAccessChain %63 %60 %13 %13
+ OpStore %64 %62
+ %71 = OpAccessChain %70 %60 %17
+ OpStore %71 %69
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // Make a vec2[3]
+ TransformationCompositeConstruct make_vec2_array_length_3(
+ 37, {41, 45, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0),
+ 200);
+ // Bad: there are too many components
+ TransformationCompositeConstruct make_vec2_array_length_3_bad(
+ 37, {41, 45, 27, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0),
+ 200);
+ ASSERT_TRUE(
+ make_vec2_array_length_3.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ make_vec2_array_length_3_bad.IsApplicable(context.get(), fact_manager));
+ make_vec2_array_length_3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(41, {}), MakeDataDescriptor(200, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(45, {}), MakeDataDescriptor(200, {1}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(27, {}), MakeDataDescriptor(200, {2}), context.get()));
+
+ // Make a float[2]
+ TransformationCompositeConstruct make_float_array_length_2(
+ 9, {24, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201);
+ // Bad: %41 does not have type float
+ TransformationCompositeConstruct make_float_array_length_2_bad(
+ 9, {41, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201);
+ ASSERT_TRUE(
+ make_float_array_length_2.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ make_float_array_length_2_bad.IsApplicable(context.get(), fact_manager));
+ make_float_array_length_2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(24, {}), MakeDataDescriptor(201, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(40, {}), MakeDataDescriptor(201, {1}), context.get()));
+
+ // Make a bool[3]
+ TransformationCompositeConstruct make_bool_array_length_3(
+ 47, {33, 50, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0),
+ 202);
+ // Bad: %54 is not available at the desired program point.
+ TransformationCompositeConstruct make_bool_array_length_3_bad(
+ 47, {33, 54, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0),
+ 202);
+ ASSERT_TRUE(
+ make_bool_array_length_3.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ make_bool_array_length_3_bad.IsApplicable(context.get(), fact_manager));
+ make_bool_array_length_3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(33, {}), MakeDataDescriptor(202, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {1}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {2}), context.get()));
+
+ // make a uvec3[2][2]
+ TransformationCompositeConstruct make_uvec3_array_length_2_2(
+ 58, {69, 100}, MakeInstructionDescriptor(64, SpvOpStore, 0), 203);
+ // Bad: Skip count 100 is too large.
+ TransformationCompositeConstruct make_uvec3_array_length_2_2_bad(
+ 58, {33, 54}, MakeInstructionDescriptor(64, SpvOpStore, 100), 203);
+ ASSERT_TRUE(
+ make_uvec3_array_length_2_2.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_uvec3_array_length_2_2_bad.IsApplicable(context.get(),
+ fact_manager));
+ make_uvec3_array_length_2_2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(69, {}), MakeDataDescriptor(203, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(100, {}),
+ MakeDataDescriptor(203, {1}),
+ context.get()));
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %11 "floats"
+ OpName %22 "x"
+ OpName %39 "vecs"
+ OpName %49 "bools"
+ OpName %60 "many_uvec3s"
+ OpDecorate %60 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 2
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpTypeInt 32 1
+ %13 = OpConstant %12 0
+ %14 = OpConstant %6 1
+ %15 = OpTypePointer Function %6
+ %17 = OpConstant %12 1
+ %18 = OpConstant %6 2
+ %20 = OpTypeVector %6 2
+ %21 = OpTypePointer Function %20
+ %32 = OpTypeBool
+ %36 = OpConstant %7 3
+ %37 = OpTypeArray %20 %36
+ %38 = OpTypePointer Private %37
+ %39 = OpVariable %38 Private
+ %40 = OpConstant %6 3
+ %41 = OpConstantComposite %20 %40 %40
+ %42 = OpTypePointer Private %20
+ %44 = OpConstant %12 2
+ %47 = OpTypeArray %32 %36
+ %48 = OpTypePointer Function %47
+ %50 = OpConstantTrue %32
+ %51 = OpTypePointer Function %32
+ %56 = OpTypeVector %7 3
+ %57 = OpTypeArray %56 %8
+ %58 = OpTypeArray %57 %8
+ %59 = OpTypePointer Function %58
+ %61 = OpConstant %7 4
+ %62 = OpConstantComposite %56 %61 %61 %61
+ %63 = OpTypePointer Function %56
+ %65 = OpConstant %7 5
+ %66 = OpConstantComposite %56 %65 %65 %65
+ %67 = OpConstant %7 6
+ %68 = OpConstantComposite %56 %67 %67 %67
+ %69 = OpConstantComposite %57 %66 %68
+ %100 = OpUndef %57
+ %70 = OpTypePointer Function %57
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %22 = OpVariable %21 Function
+ %49 = OpVariable %48 Function
+ %60 = OpVariable %59 Function
+ %16 = OpAccessChain %15 %11 %13
+ OpStore %16 %14
+ %19 = OpAccessChain %15 %11 %17
+ OpStore %19 %18
+ %23 = OpAccessChain %15 %11 %13
+ %24 = OpLoad %6 %23
+ %25 = OpAccessChain %15 %11 %17
+ %26 = OpLoad %6 %25
+ %27 = OpCompositeConstruct %20 %24 %26
+ OpStore %22 %27
+ %28 = OpAccessChain %15 %11 %13
+ %29 = OpLoad %6 %28
+ %30 = OpAccessChain %15 %11 %17
+ %31 = OpLoad %6 %30
+ %33 = OpFOrdGreaterThan %32 %29 %31
+ %202 = OpCompositeConstruct %47 %33 %50 %50
+ OpSelectionMerge %35 None
+ OpBranchConditional %33 %34 %35
+ %34 = OpLabel
+ %43 = OpAccessChain %42 %39 %17
+ OpStore %43 %41
+ %45 = OpLoad %20 %22
+ %200 = OpCompositeConstruct %37 %41 %45 %27
+ %46 = OpAccessChain %42 %39 %44
+ OpStore %46 %45
+ OpBranch %35
+ %35 = OpLabel
+ %52 = OpAccessChain %51 %49 %13
+ OpStore %52 %50
+ %53 = OpAccessChain %51 %49 %13
+ %54 = OpLoad %32 %53
+ %55 = OpAccessChain %51 %49 %17
+ OpStore %55 %54
+ %64 = OpAccessChain %63 %60 %13 %13
+ %203 = OpCompositeConstruct %58 %69 %100
+ OpStore %64 %62
+ %71 = OpAccessChain %70 %60 %17
+ %201 = OpCompositeConstruct %9 %24 %40
+ OpStore %71 %69
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationCompositeConstructTest, ConstructMatrices) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "v1"
+ OpName %12 "v2"
+ OpName %14 "v3"
+ OpName %19 "v4"
+ OpName %26 "v5"
+ OpName %29 "v6"
+ OpName %34 "m34"
+ OpName %37 "m43"
+ OpName %43 "vecs"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 3
+ %8 = OpTypePointer Function %7
+ %10 = OpConstant %6 1
+ %11 = OpConstantComposite %7 %10 %10 %10
+ %17 = OpTypeVector %6 4
+ %18 = OpTypePointer Function %17
+ %21 = OpConstant %6 2
+ %32 = OpTypeMatrix %17 3
+ %33 = OpTypePointer Private %32
+ %34 = OpVariable %33 Private
+ %35 = OpTypeMatrix %7 4
+ %36 = OpTypePointer Private %35
+ %37 = OpVariable %36 Private
+ %38 = OpTypeVector %6 2
+ %39 = OpTypeInt 32 0
+ %40 = OpConstant %39 3
+ %41 = OpTypeArray %38 %40
+ %42 = OpTypePointer Private %41
+ %43 = OpVariable %42 Private
+ %100 = OpUndef %7
+ %101 = OpUndef %17
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %9 = OpVariable %8 Function
+ %12 = OpVariable %8 Function
+ %14 = OpVariable %8 Function
+ %19 = OpVariable %18 Function
+ %26 = OpVariable %18 Function
+ %29 = OpVariable %18 Function
+ OpStore %9 %11
+ %13 = OpLoad %7 %9
+ OpStore %12 %13
+ %15 = OpLoad %7 %12
+ %16 = OpVectorShuffle %7 %15 %15 2 1 0
+ OpStore %14 %16
+ %20 = OpLoad %7 %14
+ %22 = OpCompositeExtract %6 %20 0
+ %23 = OpCompositeExtract %6 %20 1
+ %24 = OpCompositeExtract %6 %20 2
+ %25 = OpCompositeConstruct %17 %22 %23 %24 %21
+ OpStore %19 %25
+ %27 = OpLoad %17 %19
+ %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
+ OpStore %26 %28
+ %30 = OpLoad %7 %9
+ %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
+ OpStore %29 %31
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // make a mat3x4
+ TransformationCompositeConstruct make_mat34(
+ 32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
+ // Bad: %35 is mat4x3, not mat3x4.
+ TransformationCompositeConstruct make_mat34_bad(
+ 35, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
+ ASSERT_TRUE(make_mat34.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_mat34_bad.IsApplicable(context.get(), fact_manager));
+ make_mat34.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2}), context.get()));
+
+ // make a mat4x3
+ TransformationCompositeConstruct make_mat43(
+ 35, {11, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201);
+ // Bad: %25 does not match the matrix's column type.
+ TransformationCompositeConstruct make_mat43_bad(
+ 35, {25, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201);
+ ASSERT_TRUE(make_mat43.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_mat43_bad.IsApplicable(context.get(), fact_manager));
+ make_mat43.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(11, {}), MakeDataDescriptor(201, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(13, {}), MakeDataDescriptor(201, {1}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(16, {}), MakeDataDescriptor(201, {2}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(100, {}),
+ MakeDataDescriptor(201, {3}),
+ context.get()));
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "v1"
+ OpName %12 "v2"
+ OpName %14 "v3"
+ OpName %19 "v4"
+ OpName %26 "v5"
+ OpName %29 "v6"
+ OpName %34 "m34"
+ OpName %37 "m43"
+ OpName %43 "vecs"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 3
+ %8 = OpTypePointer Function %7
+ %10 = OpConstant %6 1
+ %11 = OpConstantComposite %7 %10 %10 %10
+ %17 = OpTypeVector %6 4
+ %18 = OpTypePointer Function %17
+ %21 = OpConstant %6 2
+ %32 = OpTypeMatrix %17 3
+ %33 = OpTypePointer Private %32
+ %34 = OpVariable %33 Private
+ %35 = OpTypeMatrix %7 4
+ %36 = OpTypePointer Private %35
+ %37 = OpVariable %36 Private
+ %38 = OpTypeVector %6 2
+ %39 = OpTypeInt 32 0
+ %40 = OpConstant %39 3
+ %41 = OpTypeArray %38 %40
+ %42 = OpTypePointer Private %41
+ %43 = OpVariable %42 Private
+ %100 = OpUndef %7
+ %101 = OpUndef %17
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %9 = OpVariable %8 Function
+ %12 = OpVariable %8 Function
+ %14 = OpVariable %8 Function
+ %19 = OpVariable %18 Function
+ %26 = OpVariable %18 Function
+ %29 = OpVariable %18 Function
+ OpStore %9 %11
+ %13 = OpLoad %7 %9
+ OpStore %12 %13
+ %15 = OpLoad %7 %12
+ %16 = OpVectorShuffle %7 %15 %15 2 1 0
+ OpStore %14 %16
+ %20 = OpLoad %7 %14
+ %22 = OpCompositeExtract %6 %20 0
+ %23 = OpCompositeExtract %6 %20 1
+ %24 = OpCompositeExtract %6 %20 2
+ %25 = OpCompositeConstruct %17 %22 %23 %24 %21
+ OpStore %19 %25
+ %27 = OpLoad %17 %19
+ %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
+ OpStore %26 %28
+ %30 = OpLoad %7 %9
+ %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
+ %201 = OpCompositeConstruct %35 %11 %13 %16 %100
+ OpStore %29 %31
+ %200 = OpCompositeConstruct %32 %25 %28 %31
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationCompositeConstructTest, ConstructStructs) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "Inner"
+ OpMemberName %9 0 "a"
+ OpMemberName %9 1 "b"
+ OpName %11 "i1"
+ OpName %22 "i2"
+ OpName %33 "Outer"
+ OpMemberName %33 0 "c"
+ OpMemberName %33 1 "d"
+ OpMemberName %33 2 "e"
+ OpName %35 "o"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 2
+ %8 = OpTypeInt 32 1
+ %9 = OpTypeStruct %7 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpConstant %8 0
+ %13 = OpConstant %6 2
+ %14 = OpTypeInt 32 0
+ %15 = OpConstant %14 0
+ %16 = OpTypePointer Function %6
+ %18 = OpConstant %8 1
+ %19 = OpConstant %8 3
+ %20 = OpTypePointer Function %8
+ %23 = OpTypePointer Function %7
+ %31 = OpConstant %14 2
+ %32 = OpTypeArray %9 %31
+ %33 = OpTypeStruct %32 %9 %6
+ %34 = OpTypePointer Function %33
+ %36 = OpConstant %6 1
+ %37 = OpConstantComposite %7 %36 %13
+ %38 = OpConstant %8 2
+ %39 = OpConstantComposite %9 %37 %38
+ %40 = OpConstant %6 3
+ %41 = OpConstant %6 4
+ %42 = OpConstantComposite %7 %40 %41
+ %56 = OpConstant %6 5
+ %100 = OpUndef %9
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %22 = OpVariable %10 Function
+ %35 = OpVariable %34 Function
+ %17 = OpAccessChain %16 %11 %12 %15
+ OpStore %17 %13
+ %21 = OpAccessChain %20 %11 %18
+ OpStore %21 %19
+ %24 = OpAccessChain %23 %11 %12
+ %25 = OpLoad %7 %24
+ %26 = OpAccessChain %23 %22 %12
+ OpStore %26 %25
+ %27 = OpAccessChain %20 %11 %18
+ %28 = OpLoad %8 %27
+ %29 = OpIAdd %8 %28 %18
+ %30 = OpAccessChain %20 %22 %18
+ OpStore %30 %29
+ %43 = OpAccessChain %20 %11 %18
+ %44 = OpLoad %8 %43
+ %45 = OpCompositeConstruct %9 %42 %44
+ %46 = OpCompositeConstruct %32 %39 %45
+ %47 = OpLoad %9 %22
+ %48 = OpCompositeConstruct %33 %46 %47 %40
+ OpStore %35 %48
+ %49 = OpLoad %9 %11
+ %50 = OpAccessChain %10 %35 %12 %12
+ OpStore %50 %49
+ %51 = OpLoad %9 %22
+ %52 = OpAccessChain %10 %35 %12 %18
+ OpStore %52 %51
+ %53 = OpAccessChain %10 %35 %12 %12
+ %54 = OpLoad %9 %53
+ %55 = OpAccessChain %10 %35 %18
+ OpStore %55 %54
+ %57 = OpAccessChain %16 %35 %38
+ OpStore %57 %56
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // make an Inner
+ TransformationCompositeConstruct make_inner(
+ 9, {25, 19}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200);
+ // Bad: Too few fields to make the struct.
+ TransformationCompositeConstruct make_inner_bad(
+ 9, {25}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200);
+ ASSERT_TRUE(make_inner.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_inner_bad.IsApplicable(context.get(), fact_manager));
+ make_inner.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(19, {}), MakeDataDescriptor(200, {1}), context.get()));
+
+ // make an Outer
+ TransformationCompositeConstruct make_outer(
+ 33, {46, 200, 56}, MakeInstructionDescriptor(200, SpvOpAccessChain, 0),
+ 201);
+ // Bad: %200 is not available at the desired program point.
+ TransformationCompositeConstruct make_outer_bad(
+ 33, {46, 200, 56},
+ MakeInstructionDescriptor(200, SpvOpCompositeConstruct, 0), 201);
+ ASSERT_TRUE(make_outer.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_outer_bad.IsApplicable(context.get(), fact_manager));
+ make_outer.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(46, {}), MakeDataDescriptor(201, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(200, {}),
+ MakeDataDescriptor(201, {1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(56, {}), MakeDataDescriptor(201, {2}), context.get()));
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "Inner"
+ OpMemberName %9 0 "a"
+ OpMemberName %9 1 "b"
+ OpName %11 "i1"
+ OpName %22 "i2"
+ OpName %33 "Outer"
+ OpMemberName %33 0 "c"
+ OpMemberName %33 1 "d"
+ OpMemberName %33 2 "e"
+ OpName %35 "o"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 2
+ %8 = OpTypeInt 32 1
+ %9 = OpTypeStruct %7 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpConstant %8 0
+ %13 = OpConstant %6 2
+ %14 = OpTypeInt 32 0
+ %15 = OpConstant %14 0
+ %16 = OpTypePointer Function %6
+ %18 = OpConstant %8 1
+ %19 = OpConstant %8 3
+ %20 = OpTypePointer Function %8
+ %23 = OpTypePointer Function %7
+ %31 = OpConstant %14 2
+ %32 = OpTypeArray %9 %31
+ %33 = OpTypeStruct %32 %9 %6
+ %34 = OpTypePointer Function %33
+ %36 = OpConstant %6 1
+ %37 = OpConstantComposite %7 %36 %13
+ %38 = OpConstant %8 2
+ %39 = OpConstantComposite %9 %37 %38
+ %40 = OpConstant %6 3
+ %41 = OpConstant %6 4
+ %42 = OpConstantComposite %7 %40 %41
+ %56 = OpConstant %6 5
+ %100 = OpUndef %9
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %22 = OpVariable %10 Function
+ %35 = OpVariable %34 Function
+ %17 = OpAccessChain %16 %11 %12 %15
+ OpStore %17 %13
+ %21 = OpAccessChain %20 %11 %18
+ OpStore %21 %19
+ %24 = OpAccessChain %23 %11 %12
+ %25 = OpLoad %7 %24
+ %26 = OpAccessChain %23 %22 %12
+ OpStore %26 %25
+ %27 = OpAccessChain %20 %11 %18
+ %28 = OpLoad %8 %27
+ %29 = OpIAdd %8 %28 %18
+ %30 = OpAccessChain %20 %22 %18
+ OpStore %30 %29
+ %43 = OpAccessChain %20 %11 %18
+ %44 = OpLoad %8 %43
+ %45 = OpCompositeConstruct %9 %42 %44
+ %46 = OpCompositeConstruct %32 %39 %45
+ %47 = OpLoad %9 %22
+ %48 = OpCompositeConstruct %33 %46 %47 %40
+ OpStore %35 %48
+ %49 = OpLoad %9 %11
+ %50 = OpAccessChain %10 %35 %12 %12
+ OpStore %50 %49
+ %51 = OpLoad %9 %22
+ %52 = OpAccessChain %10 %35 %12 %18
+ OpStore %52 %51
+ %53 = OpAccessChain %10 %35 %12 %12
+ %54 = OpLoad %9 %53
+ %55 = OpAccessChain %10 %35 %18
+ OpStore %55 %54
+ %200 = OpCompositeConstruct %9 %25 %19
+ %201 = OpCompositeConstruct %33 %46 %200 %56
+ %57 = OpAccessChain %16 %35 %38
+ OpStore %57 %56
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationCompositeConstructTest, ConstructVectors) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "v2"
+ OpName %27 "v3"
+ OpName %46 "v4"
+ OpName %53 "iv2"
+ OpName %61 "uv3"
+ OpName %72 "bv4"
+ OpName %88 "uv2"
+ OpName %95 "bv3"
+ OpName %104 "bv2"
+ OpName %116 "iv3"
+ OpName %124 "iv4"
+ OpName %133 "uv4"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 2
+ %8 = OpTypePointer Function %7
+ %10 = OpConstant %6 1
+ %11 = OpConstant %6 2
+ %12 = OpConstantComposite %7 %10 %11
+ %13 = OpTypeInt 32 0
+ %14 = OpConstant %13 0
+ %15 = OpTypePointer Function %6
+ %18 = OpConstant %13 1
+ %21 = OpTypeBool
+ %25 = OpTypeVector %6 3
+ %26 = OpTypePointer Function %25
+ %33 = OpConstant %6 3
+ %34 = OpConstant %6 -0.756802499
+ %38 = OpConstant %13 2
+ %44 = OpTypeVector %6 4
+ %45 = OpTypePointer Function %44
+ %50 = OpTypeInt 32 1
+ %51 = OpTypeVector %50 2
+ %52 = OpTypePointer Function %51
+ %57 = OpTypePointer Function %50
+ %59 = OpTypeVector %13 3
+ %60 = OpTypePointer Function %59
+ %65 = OpConstant %13 3
+ %67 = OpTypePointer Function %13
+ %70 = OpTypeVector %21 4
+ %71 = OpTypePointer Function %70
+ %73 = OpConstantTrue %21
+ %74 = OpTypePointer Function %21
+ %86 = OpTypeVector %13 2
+ %87 = OpTypePointer Function %86
+ %93 = OpTypeVector %21 3
+ %94 = OpTypePointer Function %93
+ %102 = OpTypeVector %21 2
+ %103 = OpTypePointer Function %102
+ %111 = OpConstantFalse %21
+ %114 = OpTypeVector %50 3
+ %115 = OpTypePointer Function %114
+ %117 = OpConstant %50 3
+ %122 = OpTypeVector %50 4
+ %123 = OpTypePointer Function %122
+ %131 = OpTypeVector %13 4
+ %132 = OpTypePointer Function %131
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %9 = OpVariable %8 Function
+ %27 = OpVariable %26 Function
+ %46 = OpVariable %45 Function
+ %53 = OpVariable %52 Function
+ %61 = OpVariable %60 Function
+ %72 = OpVariable %71 Function
+ %88 = OpVariable %87 Function
+ %95 = OpVariable %94 Function
+ %104 = OpVariable %103 Function
+ %116 = OpVariable %115 Function
+ %124 = OpVariable %123 Function
+ %133 = OpVariable %132 Function
+ OpStore %9 %12
+ %16 = OpAccessChain %15 %9 %14
+ %17 = OpLoad %6 %16
+ %19 = OpAccessChain %15 %9 %18
+ %20 = OpLoad %6 %19
+ %22 = OpFOrdGreaterThan %21 %17 %20
+ OpSelectionMerge %24 None
+ OpBranchConditional %22 %23 %101
+ %23 = OpLabel
+ %28 = OpAccessChain %15 %9 %14
+ %29 = OpLoad %6 %28
+ %30 = OpAccessChain %15 %9 %18
+ %31 = OpLoad %6 %30
+ %32 = OpFAdd %6 %29 %31
+ %35 = OpCompositeConstruct %25 %32 %33 %34
+ OpStore %27 %35
+ %36 = OpAccessChain %15 %27 %14
+ %37 = OpLoad %6 %36
+ %39 = OpAccessChain %15 %27 %38
+ %40 = OpLoad %6 %39
+ %41 = OpFOrdLessThan %21 %37 %40
+ OpSelectionMerge %43 None
+ OpBranchConditional %41 %42 %69
+ %42 = OpLabel
+ %47 = OpAccessChain %15 %9 %18
+ %48 = OpLoad %6 %47
+ %49 = OpAccessChain %15 %46 %14
+ OpStore %49 %48
+ %54 = OpAccessChain %15 %27 %38
+ %55 = OpLoad %6 %54
+ %56 = OpConvertFToS %50 %55
+ %58 = OpAccessChain %57 %53 %14
+ OpStore %58 %56
+ %62 = OpAccessChain %15 %46 %14
+ %63 = OpLoad %6 %62
+ %64 = OpConvertFToU %13 %63
+ %66 = OpIAdd %13 %64 %65
+ %68 = OpAccessChain %67 %61 %14
+ OpStore %68 %66
+ OpBranch %43
+ %69 = OpLabel
+ %75 = OpAccessChain %74 %72 %14
+ OpStore %75 %73
+ %76 = OpAccessChain %74 %72 %14
+ %77 = OpLoad %21 %76
+ %78 = OpLogicalNot %21 %77
+ %79 = OpAccessChain %74 %72 %18
+ OpStore %79 %78
+ %80 = OpAccessChain %74 %72 %14
+ %81 = OpLoad %21 %80
+ %82 = OpAccessChain %74 %72 %18
+ %83 = OpLoad %21 %82
+ %84 = OpLogicalAnd %21 %81 %83
+ %85 = OpAccessChain %74 %72 %38
+ OpStore %85 %84
+ %89 = OpAccessChain %67 %88 %14
+ %90 = OpLoad %13 %89
+ %91 = OpINotEqual %21 %90 %14
+ %92 = OpAccessChain %74 %72 %65
+ OpStore %92 %91
+ OpBranch %43
+ %43 = OpLabel
+ %96 = OpLoad %70 %72
+ %97 = OpCompositeExtract %21 %96 0
+ %98 = OpCompositeExtract %21 %96 1
+ %99 = OpCompositeExtract %21 %96 2
+ %100 = OpCompositeConstruct %93 %97 %98 %99
+ OpStore %95 %100
+ OpBranch %24
+ %101 = OpLabel
+ %105 = OpAccessChain %67 %88 %14
+ %106 = OpLoad %13 %105
+ %107 = OpINotEqual %21 %106 %14
+ %108 = OpCompositeConstruct %102 %107 %107
+ OpStore %104 %108
+ OpBranch %24
+ %24 = OpLabel
+ %109 = OpAccessChain %74 %104 %18
+ %110 = OpLoad %21 %109
+ %112 = OpLogicalOr %21 %110 %111
+ %113 = OpAccessChain %74 %104 %14
+ OpStore %113 %112
+ %118 = OpAccessChain %57 %116 %14
+ OpStore %118 %117
+ %119 = OpAccessChain %57 %116 %14
+ %120 = OpLoad %50 %119
+ %121 = OpAccessChain %57 %53 %18
+ OpStore %121 %120
+ %125 = OpAccessChain %57 %116 %14
+ %126 = OpLoad %50 %125
+ %127 = OpAccessChain %57 %53 %18
+ %128 = OpLoad %50 %127
+ %129 = OpIAdd %50 %126 %128
+ %130 = OpAccessChain %57 %124 %65
+ OpStore %130 %129
+ %134 = OpAccessChain %57 %116 %14
+ %135 = OpLoad %50 %134
+ %136 = OpBitcast %13 %135
+ %137 = OpAccessChain %67 %133 %14
+ OpStore %137 %136
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ TransformationCompositeConstruct make_vec2(
+ 7, {17, 11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200);
+ // Bad: not enough data for a vec2
+ TransformationCompositeConstruct make_vec2_bad(
+ 7, {11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200);
+ ASSERT_TRUE(make_vec2.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_vec2_bad.IsApplicable(context.get(), fact_manager));
+ make_vec2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(17, {}), MakeDataDescriptor(200, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(11, {}), MakeDataDescriptor(200, {1}), context.get()));
+
+ TransformationCompositeConstruct make_vec3(
+ 25, {12, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0),
+ 201);
+ // Bad: too much data for a vec3
+ TransformationCompositeConstruct make_vec3_bad(
+ 25, {12, 32, 32},
+ MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), 201);
+ ASSERT_TRUE(make_vec3.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_vec3_bad.IsApplicable(context.get(), fact_manager));
+ make_vec3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(12, {0}),
+ MakeDataDescriptor(201, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(12, {1}),
+ MakeDataDescriptor(201, {1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(32, {}), MakeDataDescriptor(201, {2}), context.get()));
+
+ TransformationCompositeConstruct make_vec4(
+ 44, {32, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
+ 202);
+ // Bad: id 48 is not available at the insertion points
+ TransformationCompositeConstruct make_vec4_bad(
+ 44, {48, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
+ 202);
+ ASSERT_TRUE(make_vec4.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_vec4_bad.IsApplicable(context.get(), fact_manager));
+ make_vec4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {1}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(10, {}), MakeDataDescriptor(202, {2}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(11, {}), MakeDataDescriptor(202, {3}), context.get()));
+
+ TransformationCompositeConstruct make_ivec2(
+ 51, {126, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
+ // Bad: if 128 is not available at the instruction that defines 128
+ TransformationCompositeConstruct make_ivec2_bad(
+ 51, {128, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
+ ASSERT_TRUE(make_ivec2.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_ivec2_bad.IsApplicable(context.get(), fact_manager));
+ make_ivec2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(126, {}),
+ MakeDataDescriptor(203, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(120, {}),
+ MakeDataDescriptor(203, {1}),
+ context.get()));
+
+ TransformationCompositeConstruct make_ivec3(
+ 114, {56, 117, 56}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
+ 204);
+ // Bad because 1300 is not an id
+ TransformationCompositeConstruct make_ivec3_bad(
+ 114, {56, 117, 1300}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
+ 204);
+ ASSERT_TRUE(make_ivec3.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_ivec3_bad.IsApplicable(context.get(), fact_manager));
+ make_ivec3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
+ MakeDataDescriptor(204, {1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {2}), context.get()));
+
+ TransformationCompositeConstruct make_ivec4(
+ 122, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
+ 205);
+ // Bad because 86 is the wrong type.
+ TransformationCompositeConstruct make_ivec4_bad(
+ 86, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
+ 205);
+ ASSERT_TRUE(make_ivec4.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_ivec4_bad.IsApplicable(context.get(), fact_manager));
+ make_ivec4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(56, {}), MakeDataDescriptor(205, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
+ MakeDataDescriptor(205, {1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
+ MakeDataDescriptor(205, {2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
+ MakeDataDescriptor(205, {3}),
+ context.get()));
+
+ TransformationCompositeConstruct make_uvec2(
+ 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 0), 206);
+ TransformationCompositeConstruct make_uvec2_bad(
+ 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 200), 206);
+ ASSERT_TRUE(make_uvec2.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_uvec2_bad.IsApplicable(context.get(), fact_manager));
+ make_uvec2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(18, {}), MakeDataDescriptor(206, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(38, {}), MakeDataDescriptor(206, {1}), context.get()));
+
+ TransformationCompositeConstruct make_uvec3(
+ 59, {14, 18, 136}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
+ // Bad because 1300 is not an id
+ TransformationCompositeConstruct make_uvec3_bad(
+ 59, {14, 18, 1300}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
+ ASSERT_TRUE(make_uvec3.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_uvec3_bad.IsApplicable(context.get(), fact_manager));
+ make_uvec3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(14, {}), MakeDataDescriptor(207, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(18, {}), MakeDataDescriptor(207, {1}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}),
+ MakeDataDescriptor(207, {2}),
+ context.get()));
+
+ TransformationCompositeConstruct make_uvec4(
+ 131, {14, 18, 136, 136},
+ MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208);
+ // Bad because 86 is the wrong type.
+ TransformationCompositeConstruct make_uvec4_bad(
+ 86, {14, 18, 136, 136},
+ MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208);
+ ASSERT_TRUE(make_uvec4.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_uvec4_bad.IsApplicable(context.get(), fact_manager));
+ make_uvec4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(14, {}), MakeDataDescriptor(208, {0}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(18, {}), MakeDataDescriptor(208, {1}), context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}),
+ MakeDataDescriptor(208, {2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}),
+ MakeDataDescriptor(208, {3}),
+ context.get()));
+
+ TransformationCompositeConstruct make_bvec2(
+ 102,
+ {
+ 111,
+ 41,
+ },
+ MakeInstructionDescriptor(75, SpvOpAccessChain, 0), 209);
+ // Bad because 0 is not a valid base instruction id
+ TransformationCompositeConstruct make_bvec2_bad(
+ 102,
+ {
+ 111,
+ 41,
+ },
+ MakeInstructionDescriptor(0, SpvOpExtInstImport, 0), 209);
+ ASSERT_TRUE(make_bvec2.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_bvec2_bad.IsApplicable(context.get(), fact_manager));
+ make_bvec2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(111, {}),
+ MakeDataDescriptor(209, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(41, {}), MakeDataDescriptor(209, {1}), context.get()));
+
+ TransformationCompositeConstruct make_bvec3(
+ 93, {108, 73}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
+ // Bad because there are too many components for a bvec3
+ TransformationCompositeConstruct make_bvec3_bad(
+ 93, {108, 108}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
+ ASSERT_TRUE(make_bvec3.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_bvec3_bad.IsApplicable(context.get(), fact_manager));
+ make_bvec3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}),
+ MakeDataDescriptor(210, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}),
+ MakeDataDescriptor(210, {1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(
+ MakeDataDescriptor(73, {}), MakeDataDescriptor(210, {2}), context.get()));
+
+ TransformationCompositeConstruct make_bvec4(
+ 70, {108, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
+ // Bad because 21 is a type, not a result id
+ TransformationCompositeConstruct make_bvec4_bad(
+ 70, {21, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
+ ASSERT_TRUE(make_bvec4.IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(make_bvec4_bad.IsApplicable(context.get(), fact_manager));
+ make_bvec4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}),
+ MakeDataDescriptor(211, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}),
+ MakeDataDescriptor(211, {1}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}),
+ MakeDataDescriptor(211, {2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}),
+ MakeDataDescriptor(211, {3}),
+ context.get()));
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "v2"
+ OpName %27 "v3"
+ OpName %46 "v4"
+ OpName %53 "iv2"
+ OpName %61 "uv3"
+ OpName %72 "bv4"
+ OpName %88 "uv2"
+ OpName %95 "bv3"
+ OpName %104 "bv2"
+ OpName %116 "iv3"
+ OpName %124 "iv4"
+ OpName %133 "uv4"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 2
+ %8 = OpTypePointer Function %7
+ %10 = OpConstant %6 1
+ %11 = OpConstant %6 2
+ %12 = OpConstantComposite %7 %10 %11
+ %13 = OpTypeInt 32 0
+ %14 = OpConstant %13 0
+ %15 = OpTypePointer Function %6
+ %18 = OpConstant %13 1
+ %21 = OpTypeBool
+ %25 = OpTypeVector %6 3
+ %26 = OpTypePointer Function %25
+ %33 = OpConstant %6 3
+ %34 = OpConstant %6 -0.756802499
+ %38 = OpConstant %13 2
+ %44 = OpTypeVector %6 4
+ %45 = OpTypePointer Function %44
+ %50 = OpTypeInt 32 1
+ %51 = OpTypeVector %50 2
+ %52 = OpTypePointer Function %51
+ %57 = OpTypePointer Function %50
+ %59 = OpTypeVector %13 3
+ %60 = OpTypePointer Function %59
+ %65 = OpConstant %13 3
+ %67 = OpTypePointer Function %13
+ %70 = OpTypeVector %21 4
+ %71 = OpTypePointer Function %70
+ %73 = OpConstantTrue %21
+ %74 = OpTypePointer Function %21
+ %86 = OpTypeVector %13 2
+ %87 = OpTypePointer Function %86
+ %93 = OpTypeVector %21 3
+ %94 = OpTypePointer Function %93
+ %102 = OpTypeVector %21 2
+ %103 = OpTypePointer Function %102
+ %111 = OpConstantFalse %21
+ %114 = OpTypeVector %50 3
+ %115 = OpTypePointer Function %114
+ %117 = OpConstant %50 3
+ %122 = OpTypeVector %50 4
+ %123 = OpTypePointer Function %122
+ %131 = OpTypeVector %13 4
+ %132 = OpTypePointer Function %131
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %9 = OpVariable %8 Function
+ %27 = OpVariable %26 Function
+ %46 = OpVariable %45 Function
+ %53 = OpVariable %52 Function
+ %61 = OpVariable %60 Function
+ %72 = OpVariable %71 Function
+ %88 = OpVariable %87 Function
+ %95 = OpVariable %94 Function
+ %104 = OpVariable %103 Function
+ %116 = OpVariable %115 Function
+ %124 = OpVariable %123 Function
+ %133 = OpVariable %132 Function
+ OpStore %9 %12
+ %206 = OpCompositeConstruct %86 %18 %38
+ %16 = OpAccessChain %15 %9 %14
+ %17 = OpLoad %6 %16
+ %19 = OpAccessChain %15 %9 %18
+ %20 = OpLoad %6 %19
+ %22 = OpFOrdGreaterThan %21 %17 %20
+ OpSelectionMerge %24 None
+ OpBranchConditional %22 %23 %101
+ %23 = OpLabel
+ %28 = OpAccessChain %15 %9 %14
+ %29 = OpLoad %6 %28
+ %30 = OpAccessChain %15 %9 %18
+ %31 = OpLoad %6 %30
+ %32 = OpFAdd %6 %29 %31
+ %201 = OpCompositeConstruct %25 %12 %32
+ %35 = OpCompositeConstruct %25 %32 %33 %34
+ OpStore %27 %35
+ %36 = OpAccessChain %15 %27 %14
+ %37 = OpLoad %6 %36
+ %39 = OpAccessChain %15 %27 %38
+ %40 = OpLoad %6 %39
+ %41 = OpFOrdLessThan %21 %37 %40
+ OpSelectionMerge %43 None
+ OpBranchConditional %41 %42 %69
+ %42 = OpLabel
+ %47 = OpAccessChain %15 %9 %18
+ %48 = OpLoad %6 %47
+ %49 = OpAccessChain %15 %46 %14
+ OpStore %49 %48
+ %54 = OpAccessChain %15 %27 %38
+ %55 = OpLoad %6 %54
+ %56 = OpConvertFToS %50 %55
+ %58 = OpAccessChain %57 %53 %14
+ OpStore %58 %56
+ %62 = OpAccessChain %15 %46 %14
+ %63 = OpLoad %6 %62
+ %64 = OpConvertFToU %13 %63
+ %205 = OpCompositeConstruct %122 %56 %117 %117 %117
+ %66 = OpIAdd %13 %64 %65
+ %204 = OpCompositeConstruct %114 %56 %117 %56
+ %68 = OpAccessChain %67 %61 %14
+ OpStore %68 %66
+ OpBranch %43
+ %69 = OpLabel
+ %202 = OpCompositeConstruct %44 %32 %32 %10 %11
+ %209 = OpCompositeConstruct %102 %111 %41
+ %75 = OpAccessChain %74 %72 %14
+ OpStore %75 %73
+ %76 = OpAccessChain %74 %72 %14
+ %77 = OpLoad %21 %76
+ %78 = OpLogicalNot %21 %77
+ %79 = OpAccessChain %74 %72 %18
+ OpStore %79 %78
+ %80 = OpAccessChain %74 %72 %14
+ %81 = OpLoad %21 %80
+ %82 = OpAccessChain %74 %72 %18
+ %83 = OpLoad %21 %82
+ %84 = OpLogicalAnd %21 %81 %83
+ %85 = OpAccessChain %74 %72 %38
+ OpStore %85 %84
+ %89 = OpAccessChain %67 %88 %14
+ %90 = OpLoad %13 %89
+ %91 = OpINotEqual %21 %90 %14
+ %92 = OpAccessChain %74 %72 %65
+ OpStore %92 %91
+ OpBranch %43
+ %43 = OpLabel
+ %96 = OpLoad %70 %72
+ %97 = OpCompositeExtract %21 %96 0
+ %98 = OpCompositeExtract %21 %96 1
+ %99 = OpCompositeExtract %21 %96 2
+ %100 = OpCompositeConstruct %93 %97 %98 %99
+ %200 = OpCompositeConstruct %7 %17 %11
+ OpStore %95 %100
+ OpBranch %24
+ %101 = OpLabel
+ %105 = OpAccessChain %67 %88 %14
+ %106 = OpLoad %13 %105
+ %107 = OpINotEqual %21 %106 %14
+ %108 = OpCompositeConstruct %102 %107 %107
+ %210 = OpCompositeConstruct %93 %108 %73
+ OpStore %104 %108
+ %211 = OpCompositeConstruct %70 %108 %108
+ OpBranch %24
+ %24 = OpLabel
+ %109 = OpAccessChain %74 %104 %18
+ %110 = OpLoad %21 %109
+ %112 = OpLogicalOr %21 %110 %111
+ %113 = OpAccessChain %74 %104 %14
+ OpStore %113 %112
+ %118 = OpAccessChain %57 %116 %14
+ OpStore %118 %117
+ %119 = OpAccessChain %57 %116 %14
+ %120 = OpLoad %50 %119
+ %121 = OpAccessChain %57 %53 %18
+ OpStore %121 %120
+ %125 = OpAccessChain %57 %116 %14
+ %126 = OpLoad %50 %125
+ %127 = OpAccessChain %57 %53 %18
+ %203 = OpCompositeConstruct %51 %126 %120
+ %128 = OpLoad %50 %127
+ %129 = OpIAdd %50 %126 %128
+ %130 = OpAccessChain %57 %124 %65
+ OpStore %130 %129
+ %134 = OpAccessChain %57 %116 %14
+ %135 = OpLoad %50 %134
+ %136 = OpBitcast %13 %135
+ %208 = OpCompositeConstruct %131 %14 %18 %136 %136
+ %137 = OpAccessChain %67 %133 %14
+ OpStore %137 %136
+ %207 = OpCompositeConstruct %59 %14 %18 %136
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/transformation_composite_extract_test.cpp b/test/fuzz/transformation_composite_extract_test.cpp
new file mode 100644
index 0000000..5cc2115
--- /dev/null
+++ b/test/fuzz/transformation_composite_extract_test.cpp
@@ -0,0 +1,398 @@
+// 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/fuzz/transformation_composite_extract.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationCompositeExtractTest, BasicTest) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "a"
+ OpName %10 "b"
+ OpName %17 "FunnyPoint"
+ OpMemberName %17 0 "x"
+ OpMemberName %17 1 "y"
+ OpMemberName %17 2 "z"
+ OpName %19 "p"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %12 = OpTypeBool
+ %16 = OpTypeFloat 32
+ %17 = OpTypeStruct %16 %16 %6
+ %81 = OpTypeStruct %17 %16
+ %18 = OpTypePointer Function %17
+ %20 = OpConstant %6 0
+ %23 = OpTypePointer Function %16
+ %26 = OpConstant %6 1
+ %30 = OpConstant %6 2
+ %80 = OpUndef %16
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %10 = OpVariable %7 Function
+ %19 = OpVariable %18 Function
+ %9 = OpLoad %6 %8
+ %11 = OpLoad %6 %10
+ %100 = OpCompositeConstruct %17 %80 %80 %26
+ %104 = OpCompositeConstruct %81 %100 %80
+ %13 = OpIEqual %12 %9 %11
+ OpSelectionMerge %15 None
+ OpBranchConditional %13 %14 %25
+ %14 = OpLabel
+ %21 = OpLoad %6 %8
+ %22 = OpConvertSToF %16 %21
+ %101 = OpCompositeConstruct %17 %22 %80 %30
+ %24 = OpAccessChain %23 %19 %20
+ OpStore %24 %22
+ OpBranch %15
+ %25 = OpLabel
+ %27 = OpLoad %6 %10
+ %28 = OpConvertSToF %16 %27
+ %102 = OpCompositeConstruct %17 %80 %28 %27
+ %29 = OpAccessChain %23 %19 %26
+ OpStore %29 %28
+ OpBranch %15
+ %15 = OpLabel
+ %31 = OpAccessChain %23 %19 %20
+ %32 = OpLoad %16 %31
+ %33 = OpAccessChain %23 %19 %26
+ %34 = OpLoad %16 %33
+ %103 = OpCompositeConstruct %17 %34 %32 %9
+ %35 = OpFAdd %16 %32 %34
+ %36 = OpConvertFToS %6 %35
+ %37 = OpAccessChain %7 %19 %30
+ OpStore %37 %36
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_4;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // Instruction does not exist.
+ ASSERT_FALSE(TransformationCompositeExtract(
+ MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 101, {0})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Id for composite is not a composite.
+ ASSERT_FALSE(TransformationCompositeExtract(
+ MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 27, {})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Composite does not dominate instruction being inserted before.
+ ASSERT_FALSE(
+ TransformationCompositeExtract(
+ MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 200, 101, {0})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Too many indices for extraction from struct composite.
+ ASSERT_FALSE(
+ TransformationCompositeExtract(
+ MakeInstructionDescriptor(24, SpvOpAccessChain, 0), 200, 101, {0, 0})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Too many indices for extraction from struct composite.
+ ASSERT_FALSE(
+ TransformationCompositeExtract(
+ MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 0, 0})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Out of bounds index for extraction from struct composite.
+ ASSERT_FALSE(
+ TransformationCompositeExtract(
+ MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 3})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Result id already used.
+ ASSERT_FALSE(TransformationCompositeExtract(
+ MakeInstructionDescriptor(35, SpvOpFAdd, 0), 80, 103, {0})
+ .IsApplicable(context.get(), fact_manager));
+
+ TransformationCompositeExtract transformation_1(
+ MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2});
+ ASSERT_TRUE(transformation_1.IsApplicable(context.get(), fact_manager));
+ transformation_1.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ TransformationCompositeExtract transformation_2(
+ MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 202, 104, {0, 2});
+ ASSERT_TRUE(transformation_2.IsApplicable(context.get(), fact_manager));
+ transformation_2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ TransformationCompositeExtract transformation_3(
+ MakeInstructionDescriptor(29, SpvOpAccessChain, 0), 203, 104, {0});
+ ASSERT_TRUE(transformation_3.IsApplicable(context.get(), fact_manager));
+ transformation_3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ TransformationCompositeExtract transformation_4(
+ MakeInstructionDescriptor(24, SpvOpStore, 0), 204, 101, {0});
+ ASSERT_TRUE(transformation_4.IsApplicable(context.get(), fact_manager));
+ transformation_4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ TransformationCompositeExtract transformation_5(
+ MakeInstructionDescriptor(29, SpvOpBranch, 0), 205, 102, {2});
+ ASSERT_TRUE(transformation_5.IsApplicable(context.get(), fact_manager));
+ transformation_5.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ TransformationCompositeExtract transformation_6(
+ MakeInstructionDescriptor(37, SpvOpReturn, 0), 206, 103, {1});
+ ASSERT_TRUE(transformation_6.IsApplicable(context.get(), fact_manager));
+ transformation_6.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(201, {}),
+ MakeDataDescriptor(100, {2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(202, {}),
+ MakeDataDescriptor(104, {0, 2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(203, {}),
+ MakeDataDescriptor(104, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(204, {}),
+ MakeDataDescriptor(101, {0}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(205, {}),
+ MakeDataDescriptor(102, {2}),
+ context.get()));
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(206, {}),
+ MakeDataDescriptor(103, {1}),
+ context.get()));
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "a"
+ OpName %10 "b"
+ OpName %17 "FunnyPoint"
+ OpMemberName %17 0 "x"
+ OpMemberName %17 1 "y"
+ OpMemberName %17 2 "z"
+ OpName %19 "p"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %12 = OpTypeBool
+ %16 = OpTypeFloat 32
+ %17 = OpTypeStruct %16 %16 %6
+ %81 = OpTypeStruct %17 %16
+ %18 = OpTypePointer Function %17
+ %20 = OpConstant %6 0
+ %23 = OpTypePointer Function %16
+ %26 = OpConstant %6 1
+ %30 = OpConstant %6 2
+ %80 = OpUndef %16
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %10 = OpVariable %7 Function
+ %19 = OpVariable %18 Function
+ %9 = OpLoad %6 %8
+ %11 = OpLoad %6 %10
+ %100 = OpCompositeConstruct %17 %80 %80 %26
+ %104 = OpCompositeConstruct %81 %100 %80
+ %13 = OpIEqual %12 %9 %11
+ OpSelectionMerge %15 None
+ OpBranchConditional %13 %14 %25
+ %14 = OpLabel
+ %21 = OpLoad %6 %8
+ %22 = OpConvertSToF %16 %21
+ %101 = OpCompositeConstruct %17 %22 %80 %30
+ %24 = OpAccessChain %23 %19 %20
+ %204 = OpCompositeExtract %16 %101 0
+ OpStore %24 %22
+ OpBranch %15
+ %25 = OpLabel
+ %27 = OpLoad %6 %10
+ %28 = OpConvertSToF %16 %27
+ %102 = OpCompositeConstruct %17 %80 %28 %27
+ %203 = OpCompositeExtract %17 %104 0
+ %29 = OpAccessChain %23 %19 %26
+ OpStore %29 %28
+ %205 = OpCompositeExtract %6 %102 2
+ OpBranch %15
+ %15 = OpLabel
+ %31 = OpAccessChain %23 %19 %20
+ %32 = OpLoad %16 %31
+ %33 = OpAccessChain %23 %19 %26
+ %34 = OpLoad %16 %33
+ %103 = OpCompositeConstruct %17 %34 %32 %9
+ %35 = OpFAdd %16 %32 %34
+ %201 = OpCompositeExtract %6 %100 2
+ %36 = OpConvertFToS %6 %35
+ %202 = OpCompositeExtract %6 %104 0 2
+ %37 = OpAccessChain %7 %19 %30
+ OpStore %37 %36
+ %206 = OpCompositeExtract %16 %103 1
+ OpReturn
+ OpFunctionEnd
+ )";
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationCompositeExtractTest, IllegalInsertionPoints) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %51 %27
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %25 "buf"
+ OpMemberName %25 0 "value"
+ OpName %27 ""
+ OpName %51 "color"
+ OpMemberDecorate %25 0 Offset 0
+ OpDecorate %25 Block
+ OpDecorate %27 DescriptorSet 0
+ OpDecorate %27 Binding 0
+ OpDecorate %51 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 4
+ %10 = OpConstant %6 0.300000012
+ %11 = OpConstant %6 0.400000006
+ %12 = OpConstant %6 0.5
+ %13 = OpConstant %6 1
+ %14 = OpConstantComposite %7 %10 %11 %12 %13
+ %15 = OpTypeInt 32 1
+ %18 = OpConstant %15 0
+ %25 = OpTypeStruct %6
+ %26 = OpTypePointer Uniform %25
+ %27 = OpVariable %26 Uniform
+ %28 = OpTypePointer Uniform %6
+ %32 = OpTypeBool
+ %103 = OpConstantTrue %32
+ %34 = OpConstant %6 0.100000001
+ %48 = OpConstant %15 1
+ %50 = OpTypePointer Output %7
+ %51 = OpVariable %50 Output
+ %100 = OpTypePointer Function %6
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %101 = OpVariable %100 Function
+ %102 = OpVariable %100 Function
+ OpBranch %19
+ %19 = OpLabel
+ %60 = OpPhi %7 %14 %5 %58 %20
+ %59 = OpPhi %15 %18 %5 %49 %20
+ %29 = OpAccessChain %28 %27 %18
+ %30 = OpLoad %6 %29
+ %31 = OpConvertFToS %15 %30
+ %33 = OpSLessThan %32 %59 %31
+ OpLoopMerge %21 %20 None
+ OpBranchConditional %33 %20 %21
+ %20 = OpLabel
+ %39 = OpCompositeExtract %6 %60 0
+ %40 = OpFAdd %6 %39 %34
+ %55 = OpCompositeInsert %7 %40 %60 0
+ %44 = OpCompositeExtract %6 %60 1
+ %45 = OpFSub %6 %44 %34
+ %58 = OpCompositeInsert %7 %45 %55 1
+ %49 = OpIAdd %15 %59 %48
+ OpBranch %19
+ %21 = OpLabel
+ OpStore %51 %60
+ OpSelectionMerge %105 None
+ OpBranchConditional %103 %104 %105
+ %104 = OpLabel
+ OpBranch %105
+ %105 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_4;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // Cannot insert before the OpVariables of a function.
+ ASSERT_FALSE(
+ TransformationCompositeExtract(
+ MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, {0})
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationCompositeExtract(
+ MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, {1})
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationCompositeExtract(
+ MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, {1})
+ .IsApplicable(context.get(), fact_manager));
+ // OK to insert right after the OpVariables.
+ ASSERT_FALSE(TransformationCompositeExtract(
+ MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, {1})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Cannot insert before the OpPhis of a block.
+ ASSERT_FALSE(TransformationCompositeExtract(
+ MakeInstructionDescriptor(60, SpvOpPhi, 0), 200, 14, {2})
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationCompositeExtract(
+ MakeInstructionDescriptor(59, SpvOpPhi, 0), 200, 14, {3})
+ .IsApplicable(context.get(), fact_manager));
+ // OK to insert after the OpPhis.
+ ASSERT_TRUE(
+ TransformationCompositeExtract(
+ MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14, {3})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Cannot insert before OpLoopMerge
+ ASSERT_FALSE(TransformationCompositeExtract(
+ MakeInstructionDescriptor(33, SpvOpBranchConditional, 0),
+ 200, 14, {3})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Cannot insert before OpSelectionMerge
+ ASSERT_FALSE(TransformationCompositeExtract(
+ MakeInstructionDescriptor(21, SpvOpBranchConditional, 0),
+ 200, 14, {2})
+ .IsApplicable(context.get(), fact_manager));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/transformation_copy_object_test.cpp b/test/fuzz/transformation_copy_object_test.cpp
index 0c214c8..9d3fde0 100644
--- a/test/fuzz/transformation_copy_object_test.cpp
+++ b/test/fuzz/transformation_copy_object_test.cpp
@@ -12,8 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "source/fuzz/transformation_copy_object.h"
+#include <algorithm>
+#include <set>
+#include <unordered_set>
+
#include "source/fuzz/data_descriptor.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/transformation_copy_object.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
@@ -47,58 +52,77 @@
FactManager fact_manager;
- ASSERT_EQ(0, fact_manager.GetIdsForWhichSynonymsAreKnown().size());
+ ASSERT_EQ(0,
+ fact_manager.GetIdsForWhichSynonymsAreKnown(context.get()).size());
- TransformationCopyObject copy_true(7, 5, 1, 100);
- ASSERT_TRUE(copy_true.IsApplicable(context.get(), fact_manager));
- copy_true.Apply(context.get(), &fact_manager);
+ {
+ TransformationCopyObject copy_true(
+ 7, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100);
+ ASSERT_TRUE(copy_true.IsApplicable(context.get(), fact_manager));
+ copy_true.Apply(context.get(), &fact_manager);
- const std::set<uint32_t>& ids_for_which_synonyms_are_known =
- fact_manager.GetIdsForWhichSynonymsAreKnown();
- ASSERT_EQ(1, ids_for_which_synonyms_are_known.size());
- ASSERT_TRUE(ids_for_which_synonyms_are_known.find(7) !=
- ids_for_which_synonyms_are_known.end());
- ASSERT_EQ(1, fact_manager.GetSynonymsForId(7).size());
- protobufs::DataDescriptor descriptor_100 = MakeDataDescriptor(100, {});
- ASSERT_TRUE(DataDescriptorEquals()(&descriptor_100,
- &fact_manager.GetSynonymsForId(7)[0]));
+ std::vector<uint32_t> ids_for_which_synonyms_are_known =
+ fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
+ ASSERT_EQ(2, ids_for_which_synonyms_are_known.size());
+ ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
+ ids_for_which_synonyms_are_known.end(),
+ 7) != ids_for_which_synonyms_are_known.end());
+ ASSERT_EQ(2, fact_manager.GetSynonymsForId(7, context.get()).size());
+ protobufs::DataDescriptor descriptor_100 = MakeDataDescriptor(100, {});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}),
+ descriptor_100, context.get()));
+ }
- TransformationCopyObject copy_false(8, 100, 1, 101);
- ASSERT_TRUE(copy_false.IsApplicable(context.get(), fact_manager));
- copy_false.Apply(context.get(), &fact_manager);
- ASSERT_EQ(2, ids_for_which_synonyms_are_known.size());
- ASSERT_TRUE(ids_for_which_synonyms_are_known.find(8) !=
- ids_for_which_synonyms_are_known.end());
- ASSERT_EQ(1, fact_manager.GetSynonymsForId(8).size());
- protobufs::DataDescriptor descriptor_101 = MakeDataDescriptor(101, {});
- ASSERT_TRUE(DataDescriptorEquals()(&descriptor_101,
- &fact_manager.GetSynonymsForId(8)[0]));
+ {
+ TransformationCopyObject copy_false(
+ 8, MakeInstructionDescriptor(100, SpvOpReturn, 0), 101);
+ ASSERT_TRUE(copy_false.IsApplicable(context.get(), fact_manager));
+ copy_false.Apply(context.get(), &fact_manager);
+ std::vector<uint32_t> ids_for_which_synonyms_are_known =
+ fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
+ ASSERT_EQ(4, ids_for_which_synonyms_are_known.size());
+ ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
+ ids_for_which_synonyms_are_known.end(),
+ 8) != ids_for_which_synonyms_are_known.end());
+ ASSERT_EQ(2, fact_manager.GetSynonymsForId(8, context.get()).size());
+ protobufs::DataDescriptor descriptor_101 = MakeDataDescriptor(101, {});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(8, {}),
+ descriptor_101, context.get()));
+ }
- TransformationCopyObject copy_false_again(101, 5, 3, 102);
- ASSERT_TRUE(copy_false_again.IsApplicable(context.get(), fact_manager));
- copy_false_again.Apply(context.get(), &fact_manager);
- ASSERT_EQ(3, ids_for_which_synonyms_are_known.size());
- ASSERT_TRUE(ids_for_which_synonyms_are_known.find(101) !=
- ids_for_which_synonyms_are_known.end());
- ASSERT_EQ(1, fact_manager.GetSynonymsForId(101).size());
- protobufs::DataDescriptor descriptor_102 = MakeDataDescriptor(102, {});
- ASSERT_TRUE(DataDescriptorEquals()(&descriptor_102,
- &fact_manager.GetSynonymsForId(101)[0]));
+ {
+ TransformationCopyObject copy_false_again(
+ 101, MakeInstructionDescriptor(5, SpvOpReturn, 0), 102);
+ ASSERT_TRUE(copy_false_again.IsApplicable(context.get(), fact_manager));
+ copy_false_again.Apply(context.get(), &fact_manager);
+ std::vector<uint32_t> ids_for_which_synonyms_are_known =
+ fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
+ ASSERT_EQ(5, ids_for_which_synonyms_are_known.size());
+ ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
+ ids_for_which_synonyms_are_known.end(),
+ 101) != ids_for_which_synonyms_are_known.end());
+ ASSERT_EQ(3, fact_manager.GetSynonymsForId(101, context.get()).size());
+ protobufs::DataDescriptor descriptor_102 = MakeDataDescriptor(102, {});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(101, {}),
+ descriptor_102, context.get()));
+ }
- TransformationCopyObject copy_true_again(7, 102, 1, 103);
- ASSERT_TRUE(copy_true_again.IsApplicable(context.get(), fact_manager));
- copy_true_again.Apply(context.get(), &fact_manager);
- // This does re-uses an id for which synonyms are already known, so the count
- // of such ids does not change.
- ASSERT_EQ(3, ids_for_which_synonyms_are_known.size());
- ASSERT_TRUE(ids_for_which_synonyms_are_known.find(7) !=
- ids_for_which_synonyms_are_known.end());
- ASSERT_EQ(2, fact_manager.GetSynonymsForId(7).size());
- protobufs::DataDescriptor descriptor_103 = MakeDataDescriptor(103, {});
- ASSERT_TRUE(DataDescriptorEquals()(&descriptor_103,
- &fact_manager.GetSynonymsForId(7)[0]) ||
- DataDescriptorEquals()(&descriptor_103,
- &fact_manager.GetSynonymsForId(7)[1]));
+ {
+ TransformationCopyObject copy_true_again(
+ 7, MakeInstructionDescriptor(102, SpvOpReturn, 0), 103);
+ ASSERT_TRUE(copy_true_again.IsApplicable(context.get(), fact_manager));
+ copy_true_again.Apply(context.get(), &fact_manager);
+ std::vector<uint32_t> ids_for_which_synonyms_are_known =
+ fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
+ ASSERT_EQ(6, ids_for_which_synonyms_are_known.size());
+ ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
+ ids_for_which_synonyms_are_known.end(),
+ 7) != ids_for_which_synonyms_are_known.end());
+ ASSERT_EQ(3, fact_manager.GetSynonymsForId(7, context.get()).size());
+ protobufs::DataDescriptor descriptor_103 = MakeDataDescriptor(103, {});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}),
+ descriptor_103, context.get()));
+ }
std::string after_transformation = R"(
OpCapability Shader
@@ -318,90 +342,113 @@
FactManager fact_manager;
// Inapplicable because %18 is decorated.
- ASSERT_FALSE(TransformationCopyObject(18, 21, 0, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 18, MakeInstructionDescriptor(21, SpvOpAccessChain, 0), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because %77 is decorated.
- ASSERT_FALSE(TransformationCopyObject(17, 17, 1, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 77, MakeInstructionDescriptor(77, SpvOpBranch, 0), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because %80 is decorated.
- ASSERT_FALSE(TransformationCopyObject(80, 77, 0, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 80, MakeInstructionDescriptor(77, SpvOpIAdd, 0), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because %84 is not available at the requested point
- ASSERT_FALSE(TransformationCopyObject(84, 32, 1, 200)
- .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationCopyObject(
+ 84, MakeInstructionDescriptor(32, SpvOpCompositeExtract, 0), 200)
+ .IsApplicable(context.get(), fact_manager));
// Fine because %84 is available at the requested point
- ASSERT_TRUE(TransformationCopyObject(84, 32, 2, 200)
- .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationCopyObject(
+ 84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 200)
+ .IsApplicable(context.get(), fact_manager));
// Inapplicable because id %9 is already in use
- ASSERT_FALSE(TransformationCopyObject(84, 32, 2, 9)
- .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationCopyObject(
+ 84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 9)
+ .IsApplicable(context.get(), fact_manager));
- // Inapplicable because the requested point is not in a block
- ASSERT_FALSE(TransformationCopyObject(84, 86, 3, 200)
+ // Inapplicable because the requested point does not exist
+ ASSERT_FALSE(TransformationCopyObject(
+ 84, MakeInstructionDescriptor(86, SpvOpReturn, 2), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because %9 is not in a function
- ASSERT_FALSE(TransformationCopyObject(9, 9, 1, 200)
- .IsApplicable(context.get(), fact_manager));
-
- // Inapplicable because %9 is not in a function
- ASSERT_FALSE(TransformationCopyObject(9, 9, 1, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(9, SpvOpTypeInt, 0), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because the insert point is right before, or inside, a chunk
// of OpPhis
- ASSERT_FALSE(TransformationCopyObject(9, 30, 1, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(30, SpvOpPhi, 0), 200)
.IsApplicable(context.get(), fact_manager));
- ASSERT_FALSE(TransformationCopyObject(9, 99, 1, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(99, SpvOpPhi, 1), 200)
.IsApplicable(context.get(), fact_manager));
// OK, because the insert point is just after a chunk of OpPhis.
- ASSERT_TRUE(TransformationCopyObject(9, 96, 1, 200)
+ ASSERT_TRUE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(96, SpvOpAccessChain, 0), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because the insert point is right after an OpSelectionMerge
- ASSERT_FALSE(TransformationCopyObject(9, 58, 2, 200)
- .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationCopyObject(
+ 9, MakeInstructionDescriptor(58, SpvOpBranchConditional, 0), 200)
+ .IsApplicable(context.get(), fact_manager));
// OK, because the insert point is right before the OpSelectionMerge
- ASSERT_TRUE(TransformationCopyObject(9, 58, 1, 200)
+ ASSERT_TRUE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(58, SpvOpSelectionMerge, 0), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because the insert point is right after an OpSelectionMerge
- ASSERT_FALSE(TransformationCopyObject(9, 43, 2, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(43, SpvOpSwitch, 0), 200)
.IsApplicable(context.get(), fact_manager));
// OK, because the insert point is right before the OpSelectionMerge
- ASSERT_TRUE(TransformationCopyObject(9, 43, 1, 200)
+ ASSERT_TRUE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(43, SpvOpSelectionMerge, 0), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because the insert point is right after an OpLoopMerge
- ASSERT_FALSE(TransformationCopyObject(9, 40, 2, 200)
- .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationCopyObject(
+ 9, MakeInstructionDescriptor(40, SpvOpBranchConditional, 0), 200)
+ .IsApplicable(context.get(), fact_manager));
// OK, because the insert point is right before the OpLoopMerge
- ASSERT_TRUE(TransformationCopyObject(9, 40, 1, 200)
+ ASSERT_TRUE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because id %300 does not exist
- ASSERT_FALSE(TransformationCopyObject(300, 40, 1, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 300, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200)
.IsApplicable(context.get(), fact_manager));
// Inapplicable because the following instruction is OpVariable
- ASSERT_FALSE(TransformationCopyObject(9, 180, 0, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(180, SpvOpVariable, 0), 200)
.IsApplicable(context.get(), fact_manager));
- ASSERT_FALSE(TransformationCopyObject(9, 181, 0, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(181, SpvOpVariable, 0), 200)
.IsApplicable(context.get(), fact_manager));
- ASSERT_FALSE(TransformationCopyObject(9, 182, 0, 200)
+ ASSERT_FALSE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(182, SpvOpVariable, 0), 200)
.IsApplicable(context.get(), fact_manager));
// OK, because this is just past the group of OpVariable instructions.
- ASSERT_TRUE(TransformationCopyObject(9, 182, 1, 200)
+ ASSERT_TRUE(TransformationCopyObject(
+ 9, MakeInstructionDescriptor(182, SpvOpAccessChain, 0), 200)
.IsApplicable(context.get(), fact_manager));
}
@@ -470,13 +517,20 @@
FactManager fact_manager;
std::vector<TransformationCopyObject> transformations = {
- TransformationCopyObject(19, 22, 1, 100),
- TransformationCopyObject(22, 22, 1, 101),
- TransformationCopyObject(12, 22, 1, 102),
- TransformationCopyObject(11, 22, 1, 103),
- TransformationCopyObject(16, 22, 1, 104),
- TransformationCopyObject(8, 22, 1, 105),
- TransformationCopyObject(17, 22, 1, 106)};
+ TransformationCopyObject(19, MakeInstructionDescriptor(22, SpvOpStore, 0),
+ 100),
+ TransformationCopyObject(
+ 22, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 101),
+ TransformationCopyObject(
+ 12, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 102),
+ TransformationCopyObject(
+ 11, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 103),
+ TransformationCopyObject(
+ 16, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 104),
+ TransformationCopyObject(
+ 8, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 105),
+ TransformationCopyObject(
+ 17, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 106)};
for (auto& transformation : transformations) {
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
diff --git a/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp b/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp
index b97d00f..bfc7fa7 100644
--- a/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp
+++ b/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp
@@ -16,6 +16,7 @@
#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/id_use_descriptor.h"
+#include "source/fuzz/instruction_descriptor.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
@@ -164,12 +165,14 @@
FactManager fact_manager;
std::vector<protobufs::IdUseDescriptor> uses_of_true = {
- transformation::MakeIdUseDescriptor(41, SpvOpStore, 1, 44, 12),
- transformation::MakeIdUseDescriptor(41, SpvOpLogicalOr, 0, 46, 0)};
+ MakeIdUseDescriptor(41, MakeInstructionDescriptor(44, SpvOpStore, 12), 1),
+ MakeIdUseDescriptor(41, MakeInstructionDescriptor(46, SpvOpLogicalOr, 0),
+ 0)};
std::vector<protobufs::IdUseDescriptor> uses_of_false = {
- transformation::MakeIdUseDescriptor(43, SpvOpStore, 1, 44, 13),
- transformation::MakeIdUseDescriptor(43, SpvOpLogicalAnd, 1, 48, 0)};
+ MakeIdUseDescriptor(43, MakeInstructionDescriptor(44, SpvOpStore, 13), 1),
+ MakeIdUseDescriptor(43, MakeInstructionDescriptor(48, SpvOpLogicalAnd, 0),
+ 1)};
const uint32_t fresh_id = 100;
@@ -529,10 +532,10 @@
FactManager fact_manager;
- auto use_of_true_in_if =
- transformation::MakeIdUseDescriptor(13, SpvOpBranchConditional, 0, 10, 0);
- auto use_of_false_in_while =
- transformation::MakeIdUseDescriptor(21, SpvOpBranchConditional, 0, 16, 0);
+ auto use_of_true_in_if = MakeIdUseDescriptor(
+ 13, MakeInstructionDescriptor(10, SpvOpBranchConditional, 0), 0);
+ auto use_of_false_in_while = MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(16, SpvOpBranchConditional, 0), 0);
auto replacement_1 = TransformationReplaceBooleanConstantWithConstantBinary(
use_of_true_in_if, 9, 11, SpvOpSLessThan, 100);
@@ -597,6 +600,56 @@
ASSERT_TRUE(IsEqual(env, after, context.get()));
}
+TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest, OpPhi) {
+ // Hand-written SPIR-V to check applicability of the transformation on an
+ // OpPhi argument.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeBool
+ %7 = OpTypePointer Function %6
+ %9 = OpConstantTrue %6
+ %16 = OpConstantFalse %6
+ %10 = OpTypeInt 32 1
+ %11 = OpTypePointer Function %10
+ %13 = OpConstant %10 0
+ %15 = OpConstant %10 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpSelectionMerge %20 None
+ OpBranchConditional %9 %21 %22
+ %21 = OpLabel
+ OpBranch %20
+ %22 = OpLabel
+ OpBranch %20
+ %20 = OpLabel
+ %23 = OpPhi %6 %9 %21 %16 %22
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ auto replacement = TransformationReplaceBooleanConstantWithConstantBinary(
+ MakeIdUseDescriptor(9, MakeInstructionDescriptor(23, SpvOpPhi, 0), 0), 13,
+ 15, SpvOpSLessThan, 100);
+
+ ASSERT_FALSE(replacement.IsApplicable(context.get(), fact_manager));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools
diff --git a/test/fuzz/transformation_replace_constant_with_uniform_test.cpp b/test/fuzz/transformation_replace_constant_with_uniform_test.cpp
index 06ee025..ac2e3f9 100644
--- a/test/fuzz/transformation_replace_constant_with_uniform_test.cpp
+++ b/test/fuzz/transformation_replace_constant_with_uniform_test.cpp
@@ -13,6 +13,7 @@
// limitations under the License.
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
+#include "source/fuzz/instruction_descriptor.h"
#include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "test/fuzz/fuzz_test_util.h"
@@ -116,11 +117,11 @@
// The constant ids are 9, 11 and 14, for 1, 2 and 3 respectively.
protobufs::IdUseDescriptor use_of_9_in_store =
- transformation::MakeIdUseDescriptor(9, SpvOpStore, 1, 8, 0);
+ MakeIdUseDescriptor(9, MakeInstructionDescriptor(8, SpvOpStore, 0), 1);
protobufs::IdUseDescriptor use_of_11_in_add =
- transformation::MakeIdUseDescriptor(11, SpvOpIAdd, 1, 12, 0);
+ MakeIdUseDescriptor(11, MakeInstructionDescriptor(12, SpvOpIAdd, 0), 1);
protobufs::IdUseDescriptor use_of_14_in_add =
- transformation::MakeIdUseDescriptor(14, SpvOpIAdd, 0, 15, 0);
+ MakeIdUseDescriptor(14, MakeInstructionDescriptor(15, SpvOpIAdd, 0), 0);
// These transformations work: they match the facts.
auto transformation_use_of_9_in_store =
@@ -167,7 +168,7 @@
// The following transformation does not apply because the id descriptor is
// not sensible.
protobufs::IdUseDescriptor nonsense_id_use_descriptor =
- transformation::MakeIdUseDescriptor(9, SpvOpIAdd, 0, 15, 0);
+ MakeIdUseDescriptor(9, MakeInstructionDescriptor(15, SpvOpIAdd, 0), 0);
ASSERT_FALSE(TransformationReplaceConstantWithUniform(
nonsense_id_use_descriptor, blockname_a, 101, 102)
.IsApplicable(context.get(), fact_manager));
@@ -477,13 +478,13 @@
// The constant ids are 13, 15, 17 and 20, for 1, 2, 3 and 4 respectively.
protobufs::IdUseDescriptor use_of_13_in_store =
- transformation::MakeIdUseDescriptor(13, SpvOpStore, 1, 21, 0);
+ MakeIdUseDescriptor(13, MakeInstructionDescriptor(21, SpvOpStore, 0), 1);
protobufs::IdUseDescriptor use_of_15_in_add =
- transformation::MakeIdUseDescriptor(15, SpvOpIAdd, 1, 16, 0);
+ MakeIdUseDescriptor(15, MakeInstructionDescriptor(16, SpvOpIAdd, 0), 1);
protobufs::IdUseDescriptor use_of_17_in_add =
- transformation::MakeIdUseDescriptor(17, SpvOpIAdd, 0, 19, 0);
+ MakeIdUseDescriptor(17, MakeInstructionDescriptor(19, SpvOpIAdd, 0), 0);
protobufs::IdUseDescriptor use_of_20_in_store =
- transformation::MakeIdUseDescriptor(20, SpvOpStore, 1, 19, 1);
+ MakeIdUseDescriptor(20, MakeInstructionDescriptor(19, SpvOpStore, 1), 1);
// These transformations work: they match the facts.
auto transformation_use_of_13_in_store =
@@ -703,7 +704,7 @@
// The constant id is 9 for 0.
protobufs::IdUseDescriptor use_of_9_in_store =
- transformation::MakeIdUseDescriptor(9, SpvOpStore, 1, 8, 0);
+ MakeIdUseDescriptor(9, MakeInstructionDescriptor(8, SpvOpStore, 0), 1);
// This transformation is not available because no uniform pointer to integer
// type is present:
@@ -778,7 +779,7 @@
// The constant id is 9 for 9.
protobufs::IdUseDescriptor use_of_9_in_store =
- transformation::MakeIdUseDescriptor(9, SpvOpStore, 1, 8, 0);
+ MakeIdUseDescriptor(9, MakeInstructionDescriptor(8, SpvOpStore, 0), 1);
// This transformation is not available because no constant is present for the
// index 1 required to index into the uniform buffer:
@@ -852,7 +853,7 @@
// The constant id is 9 for 3.0.
protobufs::IdUseDescriptor use_of_9_in_store =
- transformation::MakeIdUseDescriptor(9, SpvOpStore, 1, 8, 0);
+ MakeIdUseDescriptor(9, MakeInstructionDescriptor(8, SpvOpStore, 0), 1);
// This transformation is not available because no integer type is present to
// allow a constant index to be expressed:
@@ -937,9 +938,9 @@
// The constant ids for 9 and 10 are 9 and 11 respectively
protobufs::IdUseDescriptor use_of_9_in_store =
- transformation::MakeIdUseDescriptor(9, SpvOpStore, 1, 10, 0);
+ MakeIdUseDescriptor(9, MakeInstructionDescriptor(10, SpvOpStore, 0), 1);
protobufs::IdUseDescriptor use_of_11_in_store =
- transformation::MakeIdUseDescriptor(11, SpvOpStore, 1, 10, 1);
+ MakeIdUseDescriptor(11, MakeInstructionDescriptor(10, SpvOpStore, 1), 1);
// These are right:
ASSERT_TRUE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
@@ -1220,58 +1221,58 @@
std::vector<TransformationReplaceConstantWithUniform> transformations;
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(18, SpvOpStore, 1, 20, 0),
+ MakeIdUseDescriptor(18, MakeInstructionDescriptor(20, SpvOpStore, 0), 1),
uniform_f_a_4, 200, 201));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(22, SpvOpStore, 1, 23, 0),
+ MakeIdUseDescriptor(22, MakeInstructionDescriptor(23, SpvOpStore, 0), 1),
uniform_f_a_3, 202, 203));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(25, SpvOpStore, 1, 26, 0),
+ MakeIdUseDescriptor(25, MakeInstructionDescriptor(26, SpvOpStore, 0), 1),
uniform_f_a_2, 204, 205));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(28, SpvOpStore, 1, 29, 0),
+ MakeIdUseDescriptor(28, MakeInstructionDescriptor(29, SpvOpStore, 0), 1),
uniform_f_a_1, 206, 207));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(31, SpvOpStore, 1, 32, 0),
+ MakeIdUseDescriptor(31, MakeInstructionDescriptor(32, SpvOpStore, 0), 1),
uniform_f_a_0, 208, 209));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(30, SpvOpStore, 1, 35, 0),
+ MakeIdUseDescriptor(30, MakeInstructionDescriptor(35, SpvOpStore, 0), 1),
uniform_f_b_w, 210, 211));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(27, SpvOpStore, 1, 37, 0),
+ MakeIdUseDescriptor(27, MakeInstructionDescriptor(37, SpvOpStore, 0), 1),
uniform_f_b_z, 212, 213));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(24, SpvOpStore, 1, 39, 0),
+ MakeIdUseDescriptor(24, MakeInstructionDescriptor(39, SpvOpStore, 0), 1),
uniform_f_b_y, 214, 215));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(21, SpvOpStore, 1, 41, 0),
+ MakeIdUseDescriptor(21, MakeInstructionDescriptor(41, SpvOpStore, 0), 1),
uniform_f_b_x, 216, 217));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(44, SpvOpStore, 1, 45, 0),
+ MakeIdUseDescriptor(44, MakeInstructionDescriptor(45, SpvOpStore, 0), 1),
uniform_f_c_z, 220, 221));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(46, SpvOpStore, 1, 47, 0),
+ MakeIdUseDescriptor(46, MakeInstructionDescriptor(47, SpvOpStore, 0), 1),
uniform_f_c_y, 222, 223));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(48, SpvOpStore, 1, 49, 0),
+ MakeIdUseDescriptor(48, MakeInstructionDescriptor(49, SpvOpStore, 0), 1),
uniform_f_c_x, 224, 225));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(50, SpvOpStore, 1, 52, 0),
+ MakeIdUseDescriptor(50, MakeInstructionDescriptor(52, SpvOpStore, 0), 1),
uniform_f_d, 226, 227));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(53, SpvOpStore, 1, 54, 0),
+ MakeIdUseDescriptor(53, MakeInstructionDescriptor(54, SpvOpStore, 0), 1),
uniform_h_x, 228, 229));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(55, SpvOpStore, 1, 56, 0),
+ MakeIdUseDescriptor(55, MakeInstructionDescriptor(56, SpvOpStore, 0), 1),
uniform_h_y, 230, 231));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
- transformation::MakeIdUseDescriptor(42, SpvOpStore, 1, 43, 0), uniform_g,
- 218, 219));
+ MakeIdUseDescriptor(42, MakeInstructionDescriptor(43, SpvOpStore, 0), 1),
+ uniform_g, 218, 219));
for (auto& transformation : transformations) {
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
diff --git a/test/fuzz/transformation_replace_id_with_synonym_test.cpp b/test/fuzz/transformation_replace_id_with_synonym_test.cpp
new file mode 100644
index 0000000..75e117a
--- /dev/null
+++ b/test/fuzz/transformation_replace_id_with_synonym_test.cpp
@@ -0,0 +1,1213 @@
+// 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/fuzz/transformation_replace_id_with_synonym.h"
+#include "source/fuzz/data_descriptor.h"
+#include "source/fuzz/id_use_descriptor.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+// The following shader was obtained from this GLSL, which was then optimized
+// with spirv-opt -O and manually edited to include some uses of OpCopyObject
+// (to introduce id synonyms).
+//
+// #version 310 es
+//
+// precision highp int;
+// precision highp float;
+//
+// layout(set = 0, binding = 0) uniform buf {
+// int a;
+// int b;
+// int c;
+// };
+//
+// layout(location = 0) out vec4 color;
+//
+// void main() {
+// int x = a;
+// float f = 0.0;
+// while (x < b) {
+// switch(x % 4) {
+// case 0:
+// color[0] = f;
+// break;
+// case 1:
+// color[1] = f;
+// break;
+// case 2:
+// color[2] = f;
+// break;
+// case 3:
+// color[3] = f;
+// break;
+// default:
+// break;
+// }
+// if (x > c) {
+// x++;
+// } else {
+// x += 2;
+// }
+// }
+// color[0] += color[1] + float(x);
+// }
+const std::string kComplexShader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %42
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "buf"
+ OpMemberName %9 0 "a"
+ OpMemberName %9 1 "b"
+ OpMemberName %9 2 "c"
+ OpName %11 ""
+ OpName %42 "color"
+ OpMemberDecorate %9 0 Offset 0
+ OpMemberDecorate %9 1 Offset 4
+ OpMemberDecorate %9 2 Offset 8
+ OpDecorate %9 Block
+ OpDecorate %11 DescriptorSet 0
+ OpDecorate %11 Binding 0
+ OpDecorate %42 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %9 = OpTypeStruct %6 %6 %6
+ %10 = OpTypePointer Uniform %9
+ %11 = OpVariable %10 Uniform
+ %12 = OpConstant %6 0
+ %13 = OpTypePointer Uniform %6
+ %16 = OpTypeFloat 32
+ %19 = OpConstant %16 0
+ %26 = OpConstant %6 1
+ %29 = OpTypeBool
+ %32 = OpConstant %6 4
+ %40 = OpTypeVector %16 4
+ %41 = OpTypePointer Output %40
+ %42 = OpVariable %41 Output
+ %44 = OpTypeInt 32 0
+ %45 = OpConstant %44 0
+ %46 = OpTypePointer Output %16
+ %50 = OpConstant %44 1
+ %54 = OpConstant %44 2
+ %58 = OpConstant %44 3
+ %64 = OpConstant %6 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %209 = OpCopyObject %6 %12
+ %14 = OpAccessChain %13 %11 %12
+ %15 = OpLoad %6 %14
+ %200 = OpCopyObject %6 %15
+ OpBranch %20
+ %20 = OpLabel
+ %84 = OpPhi %6 %15 %5 %86 %69
+ %27 = OpAccessChain %13 %11 %26
+ %28 = OpLoad %6 %27
+ %207 = OpCopyObject %6 %84
+ %201 = OpCopyObject %6 %15
+ %30 = OpSLessThan %29 %84 %28
+ OpLoopMerge %22 %69 None
+ OpBranchConditional %30 %21 %22
+ %21 = OpLabel
+ %33 = OpSMod %6 %84 %32
+ %208 = OpCopyObject %6 %33
+ OpSelectionMerge %39 None
+ OpSwitch %33 %38 0 %34 1 %35 2 %36 3 %37
+ %38 = OpLabel
+ %202 = OpCopyObject %6 %15
+ OpBranch %39
+ %34 = OpLabel
+ %210 = OpCopyObject %16 %19
+ %47 = OpAccessChain %46 %42 %45
+ OpStore %47 %19
+ OpBranch %39
+ %35 = OpLabel
+ %51 = OpAccessChain %46 %42 %50
+ OpStore %51 %19
+ OpBranch %39
+ %36 = OpLabel
+ %204 = OpCopyObject %44 %54
+ %55 = OpAccessChain %46 %42 %54
+ %203 = OpCopyObject %46 %55
+ OpStore %55 %19
+ OpBranch %39
+ %37 = OpLabel
+ %59 = OpAccessChain %46 %42 %58
+ OpStore %59 %19
+ OpBranch %39
+ %39 = OpLabel
+ %300 = OpIAdd %6 %15 %15
+ %65 = OpAccessChain %13 %11 %64
+ %66 = OpLoad %6 %65
+ %67 = OpSGreaterThan %29 %84 %66
+ OpSelectionMerge %69 None
+ OpBranchConditional %67 %68 %72
+ %68 = OpLabel
+ %71 = OpIAdd %6 %84 %26
+ OpBranch %69
+ %72 = OpLabel
+ %74 = OpIAdd %6 %84 %64
+ %205 = OpCopyObject %6 %74
+ OpBranch %69
+ %69 = OpLabel
+ %86 = OpPhi %6 %71 %68 %74 %72
+ %301 = OpPhi %6 %71 %68 %15 %72
+ OpBranch %20
+ %22 = OpLabel
+ %75 = OpAccessChain %46 %42 %50
+ %76 = OpLoad %16 %75
+ %78 = OpConvertSToF %16 %84
+ %80 = OpAccessChain %46 %42 %45
+ %206 = OpCopyObject %16 %78
+ %81 = OpLoad %16 %80
+ %79 = OpFAdd %16 %76 %78
+ %82 = OpFAdd %16 %81 %79
+ OpStore %80 %82
+ OpReturn
+ OpFunctionEnd
+)";
+
+protobufs::Fact MakeSynonymFact(uint32_t first, uint32_t second) {
+ protobufs::FactDataSynonym data_synonym_fact;
+ *data_synonym_fact.mutable_data1() = MakeDataDescriptor(first, {});
+ *data_synonym_fact.mutable_data2() = MakeDataDescriptor(second, {});
+ protobufs::Fact result;
+ *result.mutable_data_synonym_fact() = data_synonym_fact;
+ return result;
+}
+
+// Equips the fact manager with synonym facts for the above shader.
+void SetUpIdSynonyms(FactManager* fact_manager, opt::IRContext* context) {
+ fact_manager->AddFact(MakeSynonymFact(15, 200), context);
+ fact_manager->AddFact(MakeSynonymFact(15, 201), context);
+ fact_manager->AddFact(MakeSynonymFact(15, 202), context);
+ fact_manager->AddFact(MakeSynonymFact(55, 203), context);
+ fact_manager->AddFact(MakeSynonymFact(54, 204), context);
+ fact_manager->AddFact(MakeSynonymFact(74, 205), context);
+ fact_manager->AddFact(MakeSynonymFact(78, 206), context);
+ fact_manager->AddFact(MakeSynonymFact(84, 207), context);
+ fact_manager->AddFact(MakeSynonymFact(33, 208), context);
+ fact_manager->AddFact(MakeSynonymFact(12, 209), context);
+ fact_manager->AddFact(MakeSynonymFact(19, 210), context);
+}
+
+TEST(TransformationReplaceIdWithSynonymTest, IllegalTransformations) {
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context =
+ BuildModule(env, consumer, kComplexShader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+ SetUpIdSynonyms(&fact_manager, context.get());
+
+ // %202 cannot replace %15 as in-operand 0 of %300, since %202 does not
+ // dominate %300.
+ auto synonym_does_not_dominate_use = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(15, MakeInstructionDescriptor(300, SpvOpIAdd, 0), 0),
+ 202);
+ ASSERT_FALSE(
+ synonym_does_not_dominate_use.IsApplicable(context.get(), fact_manager));
+
+ // %202 cannot replace %15 as in-operand 2 of %301, since this is the OpPhi's
+ // incoming value for block %72, and %202 does not dominate %72.
+ auto synonym_does_not_dominate_use_op_phi =
+ TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(15, MakeInstructionDescriptor(301, SpvOpPhi, 0),
+ 2),
+ 202);
+ ASSERT_FALSE(synonym_does_not_dominate_use_op_phi.IsApplicable(context.get(),
+ fact_manager));
+
+ // %200 is not a synonym for %84
+ auto id_in_use_is_not_synonymous = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 84, MakeInstructionDescriptor(67, SpvOpSGreaterThan, 0), 0),
+ 200);
+ ASSERT_FALSE(
+ id_in_use_is_not_synonymous.IsApplicable(context.get(), fact_manager));
+
+ // %86 is not a synonym for anything (and in particular not for %74)
+ auto id_has_no_synonyms = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(86, MakeInstructionDescriptor(84, SpvOpPhi, 0), 2),
+ 74);
+ ASSERT_FALSE(id_has_no_synonyms.IsApplicable(context.get(), fact_manager));
+
+ // This would lead to %207 = 'OpCopyObject %type %207' if it were allowed
+ auto synonym_use_is_in_synonym_definition =
+ TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 84, MakeInstructionDescriptor(207, SpvOpCopyObject, 0), 0),
+ 207);
+ ASSERT_FALSE(synonym_use_is_in_synonym_definition.IsApplicable(context.get(),
+ fact_manager));
+
+ // The id use descriptor does not lead to a use (%84 is not used in the
+ // definition of %207)
+ auto bad_id_use_descriptor = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 84, MakeInstructionDescriptor(200, SpvOpCopyObject, 0), 0),
+ 207);
+ ASSERT_FALSE(bad_id_use_descriptor.IsApplicable(context.get(), fact_manager));
+
+ // This replacement would lead to an access chain into a struct using a
+ // non-constant index.
+ auto bad_access_chain = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 12, MakeInstructionDescriptor(14, SpvOpAccessChain, 0), 1),
+ 209);
+ ASSERT_FALSE(bad_access_chain.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationReplaceIdWithSynonymTest, LegalTransformations) {
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context =
+ BuildModule(env, consumer, kComplexShader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+ SetUpIdSynonyms(&fact_manager, context.get());
+
+ auto global_constant_synonym = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(19, MakeInstructionDescriptor(47, SpvOpStore, 0), 1),
+ 210);
+ ASSERT_TRUE(
+ global_constant_synonym.IsApplicable(context.get(), fact_manager));
+ global_constant_synonym.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ auto replace_vector_access_chain_index = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 54, MakeInstructionDescriptor(55, SpvOpAccessChain, 0), 1),
+ 204);
+ ASSERT_TRUE(replace_vector_access_chain_index.IsApplicable(context.get(),
+ fact_manager));
+ replace_vector_access_chain_index.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // This is an interesting case because it replaces something that is being
+ // copied with something that is already a synonym.
+ auto regular_replacement = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 15, MakeInstructionDescriptor(202, SpvOpCopyObject, 0), 0),
+ 201);
+ ASSERT_TRUE(regular_replacement.IsApplicable(context.get(), fact_manager));
+ regular_replacement.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ auto regular_replacement2 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(55, MakeInstructionDescriptor(203, SpvOpStore, 0), 0),
+ 203);
+ ASSERT_TRUE(regular_replacement2.IsApplicable(context.get(), fact_manager));
+ regular_replacement2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ auto good_op_phi = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(74, MakeInstructionDescriptor(86, SpvOpPhi, 0), 2),
+ 205);
+ ASSERT_TRUE(good_op_phi.IsApplicable(context.get(), fact_manager));
+ good_op_phi.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ const std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %42
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "buf"
+ OpMemberName %9 0 "a"
+ OpMemberName %9 1 "b"
+ OpMemberName %9 2 "c"
+ OpName %11 ""
+ OpName %42 "color"
+ OpMemberDecorate %9 0 Offset 0
+ OpMemberDecorate %9 1 Offset 4
+ OpMemberDecorate %9 2 Offset 8
+ OpDecorate %9 Block
+ OpDecorate %11 DescriptorSet 0
+ OpDecorate %11 Binding 0
+ OpDecorate %42 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %9 = OpTypeStruct %6 %6 %6
+ %10 = OpTypePointer Uniform %9
+ %11 = OpVariable %10 Uniform
+ %12 = OpConstant %6 0
+ %13 = OpTypePointer Uniform %6
+ %16 = OpTypeFloat 32
+ %19 = OpConstant %16 0
+ %26 = OpConstant %6 1
+ %29 = OpTypeBool
+ %32 = OpConstant %6 4
+ %40 = OpTypeVector %16 4
+ %41 = OpTypePointer Output %40
+ %42 = OpVariable %41 Output
+ %44 = OpTypeInt 32 0
+ %45 = OpConstant %44 0
+ %46 = OpTypePointer Output %16
+ %50 = OpConstant %44 1
+ %54 = OpConstant %44 2
+ %58 = OpConstant %44 3
+ %64 = OpConstant %6 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %209 = OpCopyObject %6 %12
+ %14 = OpAccessChain %13 %11 %12
+ %15 = OpLoad %6 %14
+ %200 = OpCopyObject %6 %15
+ OpBranch %20
+ %20 = OpLabel
+ %84 = OpPhi %6 %15 %5 %86 %69
+ %27 = OpAccessChain %13 %11 %26
+ %28 = OpLoad %6 %27
+ %207 = OpCopyObject %6 %84
+ %201 = OpCopyObject %6 %15
+ %30 = OpSLessThan %29 %84 %28
+ OpLoopMerge %22 %69 None
+ OpBranchConditional %30 %21 %22
+ %21 = OpLabel
+ %33 = OpSMod %6 %84 %32
+ %208 = OpCopyObject %6 %33
+ OpSelectionMerge %39 None
+ OpSwitch %33 %38 0 %34 1 %35 2 %36 3 %37
+ %38 = OpLabel
+ %202 = OpCopyObject %6 %201
+ OpBranch %39
+ %34 = OpLabel
+ %210 = OpCopyObject %16 %19
+ %47 = OpAccessChain %46 %42 %45
+ OpStore %47 %210
+ OpBranch %39
+ %35 = OpLabel
+ %51 = OpAccessChain %46 %42 %50
+ OpStore %51 %19
+ OpBranch %39
+ %36 = OpLabel
+ %204 = OpCopyObject %44 %54
+ %55 = OpAccessChain %46 %42 %204
+ %203 = OpCopyObject %46 %55
+ OpStore %203 %19
+ OpBranch %39
+ %37 = OpLabel
+ %59 = OpAccessChain %46 %42 %58
+ OpStore %59 %19
+ OpBranch %39
+ %39 = OpLabel
+ %300 = OpIAdd %6 %15 %15
+ %65 = OpAccessChain %13 %11 %64
+ %66 = OpLoad %6 %65
+ %67 = OpSGreaterThan %29 %84 %66
+ OpSelectionMerge %69 None
+ OpBranchConditional %67 %68 %72
+ %68 = OpLabel
+ %71 = OpIAdd %6 %84 %26
+ OpBranch %69
+ %72 = OpLabel
+ %74 = OpIAdd %6 %84 %64
+ %205 = OpCopyObject %6 %74
+ OpBranch %69
+ %69 = OpLabel
+ %86 = OpPhi %6 %71 %68 %205 %72
+ %301 = OpPhi %6 %71 %68 %15 %72
+ OpBranch %20
+ %22 = OpLabel
+ %75 = OpAccessChain %46 %42 %50
+ %76 = OpLoad %16 %75
+ %78 = OpConvertSToF %16 %84
+ %80 = OpAccessChain %46 %42 %45
+ %206 = OpCopyObject %16 %78
+ %81 = OpLoad %16 %80
+ %79 = OpFAdd %16 %76 %78
+ %82 = OpFAdd %16 %81 %79
+ OpStore %80 %82
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationReplaceIdWithSynonymTest, SynonymsOfVariables) {
+ // The following SPIR-V comes from this GLSL, with object copies added:
+ //
+ // #version 310 es
+ //
+ // precision highp int;
+ //
+ // int g;
+ //
+ // void main() {
+ // int l;
+ // l = g;
+ // g = l;
+ // }
+ const std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "l"
+ OpName %10 "g"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpTypePointer Private %6
+ %10 = OpVariable %9 Private
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %100 = OpCopyObject %9 %10
+ %101 = OpCopyObject %7 %8
+ %11 = OpLoad %6 %10
+ OpStore %8 %11
+ %12 = OpLoad %6 %8
+ OpStore %10 %12
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ fact_manager.AddFact(MakeSynonymFact(10, 100), context.get());
+ fact_manager.AddFact(MakeSynonymFact(8, 101), context.get());
+
+ // Replace %10 with %100 in:
+ // %11 = OpLoad %6 %10
+ auto replacement1 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(10, MakeInstructionDescriptor(11, SpvOpLoad, 0), 0),
+ 100);
+ ASSERT_TRUE(replacement1.IsApplicable(context.get(), fact_manager));
+ replacement1.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %8 with %101 in:
+ // OpStore %8 %11
+ auto replacement2 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(8, MakeInstructionDescriptor(11, SpvOpStore, 0), 0),
+ 101);
+ ASSERT_TRUE(replacement2.IsApplicable(context.get(), fact_manager));
+ replacement2.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %8 with %101 in:
+ // %12 = OpLoad %6 %8
+ auto replacement3 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(8, MakeInstructionDescriptor(12, SpvOpLoad, 0), 0),
+ 101);
+ ASSERT_TRUE(replacement3.IsApplicable(context.get(), fact_manager));
+ replacement3.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replace %10 with %100 in:
+ // OpStore %10 %12
+ auto replacement4 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(10, MakeInstructionDescriptor(12, SpvOpStore, 0), 0),
+ 100);
+ ASSERT_TRUE(replacement4.IsApplicable(context.get(), fact_manager));
+ replacement4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ const std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "l"
+ OpName %10 "g"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpTypePointer Private %6
+ %10 = OpVariable %9 Private
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %100 = OpCopyObject %9 %10
+ %101 = OpCopyObject %7 %8
+ %11 = OpLoad %6 %100
+ OpStore %101 %11
+ %12 = OpLoad %6 %101
+ OpStore %100 %12
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationReplaceIdWithSynonymTest,
+ SynonymOfVariableNoGoodInFunctionCall) {
+ // The following SPIR-V comes from this GLSL, with an object copy added:
+ //
+ // #version 310 es
+ //
+ // precision highp int;
+ //
+ // void foo(int x) { }
+ //
+ // void main() {
+ // int a;
+ // a = 2;
+ // foo(a);
+ // }
+ const std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %10 "foo(i1;"
+ OpName %9 "x"
+ OpName %12 "a"
+ OpName %14 "param"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %8 = OpTypeFunction %2 %7
+ %13 = OpConstant %6 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %12 = OpVariable %7 Function
+ %14 = OpVariable %7 Function
+ OpStore %12 %13
+ %15 = OpLoad %6 %12
+ OpStore %14 %15
+ %100 = OpCopyObject %7 %14
+ %16 = OpFunctionCall %2 %10 %14
+ OpReturn
+ OpFunctionEnd
+ %10 = OpFunction %2 None %8
+ %9 = OpFunctionParameter %7
+ %11 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ fact_manager.AddFact(MakeSynonymFact(14, 100), context.get());
+
+ // Replace %14 with %100 in:
+ // %16 = OpFunctionCall %2 %10 %14
+ auto replacement = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 14, MakeInstructionDescriptor(16, SpvOpFunctionCall, 0), 1),
+ 100);
+ ASSERT_FALSE(replacement.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationReplaceIdWithSynonymTest, SynonymsOfAccessChainIndices) {
+ // The following SPIR-V comes from this GLSL, with object copies added:
+ //
+ // #version 310 es
+ //
+ // precision highp float;
+ // precision highp int;
+ //
+ // struct S {
+ // int[3] a;
+ // vec4 b;
+ // bool c;
+ // } d;
+ //
+ // float[20] e;
+ //
+ // struct T {
+ // float f;
+ // S g;
+ // } h;
+ //
+ // T[4] i;
+ //
+ // void main() {
+ // d.a[2] = 10;
+ // d.b[3] = 11.0;
+ // d.c = false;
+ // e[17] = 12.0;
+ // h.f = 13.0;
+ // h.g.a[1] = 14;
+ // h.g.b[0] = 15.0;
+ // h.g.c = true;
+ // i[0].f = 16.0;
+ // i[1].g.a[0] = 17;
+ // i[2].g.b[1] = 18.0;
+ // i[3].g.c = true;
+ // }
+ const std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %13 "S"
+ OpMemberName %13 0 "a"
+ OpMemberName %13 1 "b"
+ OpMemberName %13 2 "c"
+ OpName %15 "d"
+ OpName %31 "e"
+ OpName %35 "T"
+ OpMemberName %35 0 "f"
+ OpMemberName %35 1 "g"
+ OpName %37 "h"
+ OpName %50 "i"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 3
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypeFloat 32
+ %11 = OpTypeVector %10 4
+ %12 = OpTypeBool
+ %13 = OpTypeStruct %9 %11 %12
+ %14 = OpTypePointer Private %13
+ %15 = OpVariable %14 Private
+ %16 = OpConstant %6 0
+ %17 = OpConstant %6 2
+ %18 = OpConstant %6 10
+ %19 = OpTypePointer Private %6
+ %21 = OpConstant %6 1
+ %22 = OpConstant %10 11
+ %23 = OpTypePointer Private %10
+ %25 = OpConstantFalse %12
+ %26 = OpTypePointer Private %12
+ %28 = OpConstant %7 20
+ %29 = OpTypeArray %10 %28
+ %30 = OpTypePointer Private %29
+ %31 = OpVariable %30 Private
+ %32 = OpConstant %6 17
+ %33 = OpConstant %10 12
+ %35 = OpTypeStruct %10 %13
+ %36 = OpTypePointer Private %35
+ %37 = OpVariable %36 Private
+ %38 = OpConstant %10 13
+ %40 = OpConstant %6 14
+ %42 = OpConstant %10 15
+ %43 = OpConstant %7 0
+ %45 = OpConstantTrue %12
+ %47 = OpConstant %7 4
+ %48 = OpTypeArray %35 %47
+ %49 = OpTypePointer Private %48
+ %50 = OpVariable %49 Private
+ %51 = OpConstant %10 16
+ %54 = OpConstant %10 18
+ %55 = OpConstant %7 1
+ %57 = OpConstant %6 3
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+
+ %100 = OpCopyObject %6 %16 ; 0
+ %101 = OpCopyObject %6 %21 ; 1
+ %102 = OpCopyObject %6 %17 ; 2
+ %103 = OpCopyObject %6 %57 ; 3
+ %104 = OpCopyObject %6 %18 ; 10
+ %105 = OpCopyObject %6 %40 ; 14
+ %106 = OpCopyObject %6 %32 ; 17
+ %107 = OpCopyObject %7 %43 ; 0
+ %108 = OpCopyObject %7 %55 ; 1
+ %109 = OpCopyObject %7 %8 ; 3
+ %110 = OpCopyObject %7 %47 ; 4
+ %111 = OpCopyObject %7 %28 ; 20
+ %112 = OpCopyObject %12 %45 ; true
+
+ %20 = OpAccessChain %19 %15 %16 %17
+ OpStore %20 %18
+ %24 = OpAccessChain %23 %15 %21 %8
+ OpStore %24 %22
+ %27 = OpAccessChain %26 %15 %17
+ OpStore %27 %25
+ %34 = OpAccessChain %23 %31 %32
+ OpStore %34 %33
+ %39 = OpAccessChain %23 %37 %16
+ OpStore %39 %38
+ %41 = OpAccessChain %19 %37 %21 %16 %21
+ OpStore %41 %40
+ %44 = OpAccessChain %23 %37 %21 %21 %43
+ OpStore %44 %42
+ %46 = OpAccessChain %26 %37 %21 %17
+ OpStore %46 %45
+ %52 = OpAccessChain %23 %50 %16 %16
+ OpStore %52 %51
+ %53 = OpAccessChain %19 %50 %21 %21 %16 %16
+ OpStore %53 %32
+ %56 = OpAccessChain %23 %50 %17 %21 %21 %55
+ OpStore %56 %54
+ %58 = OpAccessChain %26 %50 %57 %21 %17
+ OpStore %58 %45
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // Add synonym facts corresponding to the OpCopyObject operations that have
+ // been applied to all constants in the module.
+ fact_manager.AddFact(MakeSynonymFact(16, 100), context.get());
+ fact_manager.AddFact(MakeSynonymFact(21, 101), context.get());
+ fact_manager.AddFact(MakeSynonymFact(17, 102), context.get());
+ fact_manager.AddFact(MakeSynonymFact(57, 103), context.get());
+ fact_manager.AddFact(MakeSynonymFact(18, 104), context.get());
+ fact_manager.AddFact(MakeSynonymFact(40, 105), context.get());
+ fact_manager.AddFact(MakeSynonymFact(32, 106), context.get());
+ fact_manager.AddFact(MakeSynonymFact(43, 107), context.get());
+ fact_manager.AddFact(MakeSynonymFact(55, 108), context.get());
+ fact_manager.AddFact(MakeSynonymFact(8, 109), context.get());
+ fact_manager.AddFact(MakeSynonymFact(47, 110), context.get());
+ fact_manager.AddFact(MakeSynonymFact(28, 111), context.get());
+ fact_manager.AddFact(MakeSynonymFact(45, 112), context.get());
+
+ // Replacements of the form %16 -> %100
+
+ // %20 = OpAccessChain %19 %15 *%16* %17
+ // Corresponds to d.*a*[2]
+ // The index %16 used for a cannot be replaced
+ auto replacement1 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 16, MakeInstructionDescriptor(20, SpvOpAccessChain, 0), 1),
+ 100);
+ ASSERT_FALSE(replacement1.IsApplicable(context.get(), fact_manager));
+
+ // %39 = OpAccessChain %23 %37 *%16*
+ // Corresponds to h.*f*
+ // The index %16 used for f cannot be replaced
+ auto replacement2 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 16, MakeInstructionDescriptor(39, SpvOpAccessChain, 0), 1),
+ 100);
+ ASSERT_FALSE(replacement2.IsApplicable(context.get(), fact_manager));
+
+ // %41 = OpAccessChain %19 %37 %21 *%16* %21
+ // Corresponds to h.g.*a*[1]
+ // The index %16 used for a cannot be replaced
+ auto replacement3 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 16, MakeInstructionDescriptor(41, SpvOpAccessChain, 0), 2),
+ 100);
+ ASSERT_FALSE(replacement3.IsApplicable(context.get(), fact_manager));
+
+ // %52 = OpAccessChain %23 %50 *%16* %16
+ // Corresponds to i[*0*].f
+ // The index %16 used for 0 *can* be replaced
+ auto replacement4 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 16, MakeInstructionDescriptor(52, SpvOpAccessChain, 0), 1),
+ 100);
+ ASSERT_TRUE(replacement4.IsApplicable(context.get(), fact_manager));
+ replacement4.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // %52 = OpAccessChain %23 %50 %16 *%16*
+ // Corresponds to i[0].*f*
+ // The index %16 used for f cannot be replaced
+ auto replacement5 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 16, MakeInstructionDescriptor(52, SpvOpAccessChain, 0), 2),
+ 100);
+ ASSERT_FALSE(replacement5.IsApplicable(context.get(), fact_manager));
+
+ // %53 = OpAccessChain %19 %50 %21 %21 *%16* %16
+ // Corresponds to i[1].g.*a*[0]
+ // The index %16 used for a cannot be replaced
+ auto replacement6 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 16, MakeInstructionDescriptor(53, SpvOpAccessChain, 0), 3),
+ 100);
+ ASSERT_FALSE(replacement6.IsApplicable(context.get(), fact_manager));
+
+ // %53 = OpAccessChain %19 %50 %21 %21 %16 *%16*
+ // Corresponds to i[1].g.a[*0*]
+ // The index %16 used for 0 *can* be replaced
+ auto replacement7 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 16, MakeInstructionDescriptor(53, SpvOpAccessChain, 0), 4),
+ 100);
+ ASSERT_TRUE(replacement7.IsApplicable(context.get(), fact_manager));
+ replacement7.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replacements of the form %21 -> %101
+
+ // %24 = OpAccessChain %23 %15 *%21* %8
+ // Corresponds to d.*b*[3]
+ // The index %24 used for b cannot be replaced
+ auto replacement8 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(24, SpvOpAccessChain, 0), 1),
+ 101);
+ ASSERT_FALSE(replacement8.IsApplicable(context.get(), fact_manager));
+
+ // %41 = OpAccessChain %19 %37 *%21* %16 %21
+ // Corresponds to h.*g*.a[1]
+ // The index %24 used for g cannot be replaced
+ auto replacement9 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(41, SpvOpAccessChain, 0), 1),
+ 101);
+ ASSERT_FALSE(replacement9.IsApplicable(context.get(), fact_manager));
+
+ // %41 = OpAccessChain %19 %37 %21 %16 *%21*
+ // Corresponds to h.g.a[*1*]
+ // The index %24 used for 1 *can* be replaced
+ auto replacement10 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(41, SpvOpAccessChain, 0), 3),
+ 101);
+ ASSERT_TRUE(replacement10.IsApplicable(context.get(), fact_manager));
+ replacement10.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // %44 = OpAccessChain %23 %37 *%21* %21 %43
+ // Corresponds to h.*g*.b[0]
+ // The index %24 used for g cannot be replaced
+ auto replacement11 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(44, SpvOpAccessChain, 0), 1),
+ 101);
+ ASSERT_FALSE(replacement11.IsApplicable(context.get(), fact_manager));
+
+ // %44 = OpAccessChain %23 %37 %21 *%21* %43
+ // Corresponds to h.g.*b*[0]
+ // The index %24 used for b cannot be replaced
+ auto replacement12 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(44, SpvOpAccessChain, 0), 2),
+ 101);
+ ASSERT_FALSE(replacement12.IsApplicable(context.get(), fact_manager));
+
+ // %46 = OpAccessChain %26 %37 *%21* %17
+ // Corresponds to h.*g*.c
+ // The index %24 used for g cannot be replaced
+ auto replacement13 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), 1),
+ 101);
+ ASSERT_FALSE(replacement13.IsApplicable(context.get(), fact_manager));
+
+ // %53 = OpAccessChain %19 %50 *%21* %21 %16 %16
+ // Corresponds to i[*1*].g.a[0]
+ // The index %24 used for 1 *can* be replaced
+ auto replacement14 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(53, SpvOpAccessChain, 0), 1),
+ 101);
+ ASSERT_TRUE(replacement14.IsApplicable(context.get(), fact_manager));
+ replacement14.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // %53 = OpAccessChain %19 %50 %21 *%21* %16 %16
+ // Corresponds to i[1].*g*.a[0]
+ // The index %24 used for g cannot be replaced
+ auto replacement15 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(53, SpvOpAccessChain, 0), 2),
+ 101);
+ ASSERT_FALSE(replacement15.IsApplicable(context.get(), fact_manager));
+
+ // %56 = OpAccessChain %23 %50 %17 *%21* %21 %55
+ // Corresponds to i[2].*g*.b[1]
+ // The index %24 used for g cannot be replaced
+ auto replacement16 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(56, SpvOpAccessChain, 0), 2),
+ 101);
+ ASSERT_FALSE(replacement16.IsApplicable(context.get(), fact_manager));
+
+ // %56 = OpAccessChain %23 %50 %17 %21 *%21* %55
+ // Corresponds to i[2].g.*b*[1]
+ // The index %24 used for b cannot be replaced
+ auto replacement17 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(56, SpvOpAccessChain, 0), 3),
+ 101);
+ ASSERT_FALSE(replacement17.IsApplicable(context.get(), fact_manager));
+
+ // %58 = OpAccessChain %26 %50 %57 *%21* %17
+ // Corresponds to i[3].*g*.c
+ // The index %24 used for g cannot be replaced
+ auto replacement18 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 21, MakeInstructionDescriptor(58, SpvOpAccessChain, 0), 2),
+ 101);
+ ASSERT_FALSE(replacement18.IsApplicable(context.get(), fact_manager));
+
+ // Replacements of the form %17 -> %102
+
+ // %20 = OpAccessChain %19 %15 %16 %17
+ // Corresponds to d.a[*2*]
+ // The index %17 used for 2 *can* be replaced
+ auto replacement19 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 17, MakeInstructionDescriptor(20, SpvOpAccessChain, 0), 2),
+ 102);
+ ASSERT_TRUE(replacement19.IsApplicable(context.get(), fact_manager));
+ replacement19.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // %27 = OpAccessChain %26 %15 %17
+ // Corresponds to d.c
+ // The index %17 used for c cannot be replaced
+ auto replacement20 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 17, MakeInstructionDescriptor(27, SpvOpAccessChain, 0), 1),
+ 102);
+ ASSERT_FALSE(replacement20.IsApplicable(context.get(), fact_manager));
+
+ // %46 = OpAccessChain %26 %37 %21 %17
+ // Corresponds to h.g.*c*
+ // The index %17 used for c cannot be replaced
+ auto replacement21 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 17, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), 2),
+ 102);
+ ASSERT_FALSE(replacement21.IsApplicable(context.get(), fact_manager));
+
+ // %56 = OpAccessChain %23 %50 %17 %21 %21 %55
+ // Corresponds to i[*2*].g.b[1]
+ // The index %17 used for 2 *can* be replaced
+ auto replacement22 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 17, MakeInstructionDescriptor(56, SpvOpAccessChain, 0), 1),
+ 102);
+ ASSERT_TRUE(replacement22.IsApplicable(context.get(), fact_manager));
+ replacement22.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // %58 = OpAccessChain %26 %50 %57 %21 %17
+ // Corresponds to i[3].g.*c*
+ // The index %17 used for c cannot be replaced
+ auto replacement23 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 17, MakeInstructionDescriptor(58, SpvOpAccessChain, 0), 3),
+ 102);
+ ASSERT_FALSE(replacement23.IsApplicable(context.get(), fact_manager));
+
+ // Replacements of the form %57 -> %103
+
+ // %58 = OpAccessChain %26 %50 *%57* %21 %17
+ // Corresponds to i[*3*].g.c
+ // The index %57 used for 3 *can* be replaced
+ auto replacement24 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 57, MakeInstructionDescriptor(58, SpvOpAccessChain, 0), 1),
+ 103);
+ ASSERT_TRUE(replacement24.IsApplicable(context.get(), fact_manager));
+ replacement24.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replacements of the form %32 -> %106
+
+ // %34 = OpAccessChain %23 %31 *%32*
+ // Corresponds to e[*17*]
+ // The index %32 used for 17 *can* be replaced
+ auto replacement25 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 32, MakeInstructionDescriptor(34, SpvOpAccessChain, 0), 1),
+ 106);
+ ASSERT_TRUE(replacement25.IsApplicable(context.get(), fact_manager));
+ replacement25.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replacements of the form %43 -> %107
+
+ // %44 = OpAccessChain %23 %37 %21 %21 *%43*
+ // Corresponds to h.g.b[*0*]
+ // The index %43 used for 0 *can* be replaced
+ auto replacement26 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 43, MakeInstructionDescriptor(44, SpvOpAccessChain, 0), 3),
+ 107);
+ ASSERT_TRUE(replacement26.IsApplicable(context.get(), fact_manager));
+ replacement26.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replacements of the form %55 -> %108
+
+ // %56 = OpAccessChain %23 %50 %17 %21 %21 *%55*
+ // Corresponds to i[2].g.b[*1*]
+ // The index %55 used for 1 *can* be replaced
+ auto replacement27 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(
+ 55, MakeInstructionDescriptor(56, SpvOpAccessChain, 0), 4),
+ 108);
+ ASSERT_TRUE(replacement27.IsApplicable(context.get(), fact_manager));
+ replacement27.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ // Replacements of the form %8 -> %109
+
+ // %24 = OpAccessChain %23 %15 %21 *%8*
+ // Corresponds to d.b[*3*]
+ // The index %8 used for 3 *can* be replaced
+ auto replacement28 = TransformationReplaceIdWithSynonym(
+ MakeIdUseDescriptor(8, MakeInstructionDescriptor(24, SpvOpAccessChain, 0),
+ 2),
+ 109);
+ ASSERT_TRUE(replacement28.IsApplicable(context.get(), fact_manager));
+ replacement28.Apply(context.get(), &fact_manager);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ const std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %13 "S"
+ OpMemberName %13 0 "a"
+ OpMemberName %13 1 "b"
+ OpMemberName %13 2 "c"
+ OpName %15 "d"
+ OpName %31 "e"
+ OpName %35 "T"
+ OpMemberName %35 0 "f"
+ OpMemberName %35 1 "g"
+ OpName %37 "h"
+ OpName %50 "i"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 3
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypeFloat 32
+ %11 = OpTypeVector %10 4
+ %12 = OpTypeBool
+ %13 = OpTypeStruct %9 %11 %12
+ %14 = OpTypePointer Private %13
+ %15 = OpVariable %14 Private
+ %16 = OpConstant %6 0
+ %17 = OpConstant %6 2
+ %18 = OpConstant %6 10
+ %19 = OpTypePointer Private %6
+ %21 = OpConstant %6 1
+ %22 = OpConstant %10 11
+ %23 = OpTypePointer Private %10
+ %25 = OpConstantFalse %12
+ %26 = OpTypePointer Private %12
+ %28 = OpConstant %7 20
+ %29 = OpTypeArray %10 %28
+ %30 = OpTypePointer Private %29
+ %31 = OpVariable %30 Private
+ %32 = OpConstant %6 17
+ %33 = OpConstant %10 12
+ %35 = OpTypeStruct %10 %13
+ %36 = OpTypePointer Private %35
+ %37 = OpVariable %36 Private
+ %38 = OpConstant %10 13
+ %40 = OpConstant %6 14
+ %42 = OpConstant %10 15
+ %43 = OpConstant %7 0
+ %45 = OpConstantTrue %12
+ %47 = OpConstant %7 4
+ %48 = OpTypeArray %35 %47
+ %49 = OpTypePointer Private %48
+ %50 = OpVariable %49 Private
+ %51 = OpConstant %10 16
+ %54 = OpConstant %10 18
+ %55 = OpConstant %7 1
+ %57 = OpConstant %6 3
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+
+ %100 = OpCopyObject %6 %16 ; 0
+ %101 = OpCopyObject %6 %21 ; 1
+ %102 = OpCopyObject %6 %17 ; 2
+ %103 = OpCopyObject %6 %57 ; 3
+ %104 = OpCopyObject %6 %18 ; 10
+ %105 = OpCopyObject %6 %40 ; 14
+ %106 = OpCopyObject %6 %32 ; 17
+ %107 = OpCopyObject %7 %43 ; 0
+ %108 = OpCopyObject %7 %55 ; 1
+ %109 = OpCopyObject %7 %8 ; 3
+ %110 = OpCopyObject %7 %47 ; 4
+ %111 = OpCopyObject %7 %28 ; 20
+ %112 = OpCopyObject %12 %45 ; true
+
+ %20 = OpAccessChain %19 %15 %16 %102
+ OpStore %20 %18
+ %24 = OpAccessChain %23 %15 %21 %109
+ OpStore %24 %22
+ %27 = OpAccessChain %26 %15 %17
+ OpStore %27 %25
+ %34 = OpAccessChain %23 %31 %106
+ OpStore %34 %33
+ %39 = OpAccessChain %23 %37 %16
+ OpStore %39 %38
+ %41 = OpAccessChain %19 %37 %21 %16 %101
+ OpStore %41 %40
+ %44 = OpAccessChain %23 %37 %21 %21 %107
+ OpStore %44 %42
+ %46 = OpAccessChain %26 %37 %21 %17
+ OpStore %46 %45
+ %52 = OpAccessChain %23 %50 %100 %16
+ OpStore %52 %51
+ %53 = OpAccessChain %19 %50 %101 %21 %16 %100
+ OpStore %53 %32
+ %56 = OpAccessChain %23 %50 %102 %21 %21 %108
+ OpStore %56 %54
+ %58 = OpAccessChain %26 %50 %103 %21 %17
+ OpStore %58 %45
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/transformation_set_function_control_test.cpp b/test/fuzz/transformation_set_function_control_test.cpp
new file mode 100644
index 0000000..536e965
--- /dev/null
+++ b/test/fuzz/transformation_set_function_control_test.cpp
@@ -0,0 +1,251 @@
+// 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/fuzz/transformation_set_function_control.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationSetFunctionControlTest, VariousScenarios) {
+ // This is a simple transformation; this test captures the important things
+ // to check for.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %54
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %11 "foo(i1;i1;"
+ OpName %9 "a"
+ OpName %10 "b"
+ OpName %13 "bar("
+ OpName %17 "baz(i1;"
+ OpName %16 "x"
+ OpName %21 "boo(i1;i1;"
+ OpName %19 "a"
+ OpName %20 "b"
+ OpName %29 "g"
+ OpName %42 "param"
+ OpName %44 "param"
+ OpName %45 "param"
+ OpName %48 "param"
+ OpName %49 "param"
+ OpName %54 "color"
+ OpDecorate %54 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %8 = OpTypeFunction %6 %7 %7
+ %15 = OpTypeFunction %6 %7
+ %28 = OpTypePointer Private %6
+ %29 = OpVariable %28 Private
+ %30 = OpConstant %6 2
+ %31 = OpConstant %6 5
+ %51 = OpTypeFloat 32
+ %52 = OpTypeVector %51 4
+ %53 = OpTypePointer Output %52
+ %54 = OpVariable %53 Output
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %42 = OpVariable %7 Function
+ %44 = OpVariable %7 Function
+ %45 = OpVariable %7 Function
+ %48 = OpVariable %7 Function
+ %49 = OpVariable %7 Function
+ %41 = OpFunctionCall %2 %13
+ OpStore %42 %30
+ %43 = OpFunctionCall %6 %17 %42
+ OpStore %44 %31
+ %46 = OpLoad %6 %29
+ OpStore %45 %46
+ %47 = OpFunctionCall %6 %21 %44 %45
+ OpStore %48 %43
+ OpStore %49 %47
+ %50 = OpFunctionCall %6 %11 %48 %49
+ OpReturn
+ OpFunctionEnd
+ %11 = OpFunction %6 Const %8
+ %9 = OpFunctionParameter %7
+ %10 = OpFunctionParameter %7
+ %12 = OpLabel
+ %23 = OpLoad %6 %9
+ %24 = OpLoad %6 %10
+ %25 = OpIAdd %6 %23 %24
+ OpReturnValue %25
+ OpFunctionEnd
+ %13 = OpFunction %2 Inline %3
+ %14 = OpLabel
+ OpStore %29 %30
+ OpReturn
+ OpFunctionEnd
+ %17 = OpFunction %6 Pure|DontInline %15
+ %16 = OpFunctionParameter %7
+ %18 = OpLabel
+ %32 = OpLoad %6 %16
+ %33 = OpIAdd %6 %31 %32
+ OpReturnValue %33
+ OpFunctionEnd
+ %21 = OpFunction %6 DontInline %8
+ %19 = OpFunctionParameter %7
+ %20 = OpFunctionParameter %7
+ %22 = OpLabel
+ %36 = OpLoad %6 %19
+ %37 = OpLoad %6 %20
+ %38 = OpIMul %6 %36 %37
+ OpReturnValue %38
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+
+ FactManager fact_manager;
+
+ // %36 is not a function
+ ASSERT_FALSE(TransformationSetFunctionControl(36, SpvFunctionControlMaskNone)
+ .IsApplicable(context.get(), fact_manager));
+ // Cannot add the Pure function control to %4 as it did not already have it
+ ASSERT_FALSE(TransformationSetFunctionControl(4, SpvFunctionControlPureMask)
+ .IsApplicable(context.get(), fact_manager));
+ // Cannot add the Const function control to %21 as it did not already
+ // have it
+ ASSERT_FALSE(TransformationSetFunctionControl(21, SpvFunctionControlConstMask)
+ .IsApplicable(context.get(), fact_manager));
+
+ // Set to None, removing Const
+ TransformationSetFunctionControl transformation1(11,
+ SpvFunctionControlMaskNone);
+ ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+ transformation1.Apply(context.get(), &fact_manager);
+
+ // Set to Inline; silly to do it on an entry point, but it is allowed
+ TransformationSetFunctionControl transformation2(
+ 4, SpvFunctionControlInlineMask);
+ ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+ transformation2.Apply(context.get(), &fact_manager);
+
+ // Set to Pure, removing DontInline
+ TransformationSetFunctionControl transformation3(17,
+ SpvFunctionControlPureMask);
+ ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+ transformation3.Apply(context.get(), &fact_manager);
+
+ // Change from Inline to DontInline
+ TransformationSetFunctionControl transformation4(
+ 13, SpvFunctionControlDontInlineMask);
+ ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+ transformation4.Apply(context.get(), &fact_manager);
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %54
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %11 "foo(i1;i1;"
+ OpName %9 "a"
+ OpName %10 "b"
+ OpName %13 "bar("
+ OpName %17 "baz(i1;"
+ OpName %16 "x"
+ OpName %21 "boo(i1;i1;"
+ OpName %19 "a"
+ OpName %20 "b"
+ OpName %29 "g"
+ OpName %42 "param"
+ OpName %44 "param"
+ OpName %45 "param"
+ OpName %48 "param"
+ OpName %49 "param"
+ OpName %54 "color"
+ OpDecorate %54 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %8 = OpTypeFunction %6 %7 %7
+ %15 = OpTypeFunction %6 %7
+ %28 = OpTypePointer Private %6
+ %29 = OpVariable %28 Private
+ %30 = OpConstant %6 2
+ %31 = OpConstant %6 5
+ %51 = OpTypeFloat 32
+ %52 = OpTypeVector %51 4
+ %53 = OpTypePointer Output %52
+ %54 = OpVariable %53 Output
+ %4 = OpFunction %2 Inline %3
+ %5 = OpLabel
+ %42 = OpVariable %7 Function
+ %44 = OpVariable %7 Function
+ %45 = OpVariable %7 Function
+ %48 = OpVariable %7 Function
+ %49 = OpVariable %7 Function
+ %41 = OpFunctionCall %2 %13
+ OpStore %42 %30
+ %43 = OpFunctionCall %6 %17 %42
+ OpStore %44 %31
+ %46 = OpLoad %6 %29
+ OpStore %45 %46
+ %47 = OpFunctionCall %6 %21 %44 %45
+ OpStore %48 %43
+ OpStore %49 %47
+ %50 = OpFunctionCall %6 %11 %48 %49
+ OpReturn
+ OpFunctionEnd
+ %11 = OpFunction %6 None %8
+ %9 = OpFunctionParameter %7
+ %10 = OpFunctionParameter %7
+ %12 = OpLabel
+ %23 = OpLoad %6 %9
+ %24 = OpLoad %6 %10
+ %25 = OpIAdd %6 %23 %24
+ OpReturnValue %25
+ OpFunctionEnd
+ %13 = OpFunction %2 DontInline %3
+ %14 = OpLabel
+ OpStore %29 %30
+ OpReturn
+ OpFunctionEnd
+ %17 = OpFunction %6 Pure %15
+ %16 = OpFunctionParameter %7
+ %18 = OpLabel
+ %32 = OpLoad %6 %16
+ %33 = OpIAdd %6 %31 %32
+ OpReturnValue %33
+ OpFunctionEnd
+ %21 = OpFunction %6 DontInline %8
+ %19 = OpFunctionParameter %7
+ %20 = OpFunctionParameter %7
+ %22 = OpLabel
+ %36 = OpLoad %6 %19
+ %37 = OpLoad %6 %20
+ %38 = OpIMul %6 %36 %37
+ OpReturnValue %38
+ OpFunctionEnd
+ )";
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/transformation_set_loop_control_test.cpp b/test/fuzz/transformation_set_loop_control_test.cpp
new file mode 100644
index 0000000..83953ec
--- /dev/null
+++ b/test/fuzz/transformation_set_loop_control_test.cpp
@@ -0,0 +1,968 @@
+// 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/fuzz/transformation_set_loop_control.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationSetLoopControlTest, VariousScenarios) {
+ // This test features loops with various different controls, and goes through
+ // a number of acceptable and unacceptable transformations to those controls.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %16 = OpConstant %6 100
+ %17 = OpTypeBool
+ %20 = OpConstant %6 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %22 = OpVariable %7 Function
+ %32 = OpVariable %7 Function
+ %42 = OpVariable %7 Function
+ %52 = OpVariable %7 Function
+ %62 = OpVariable %7 Function
+ %72 = OpVariable %7 Function
+ %82 = OpVariable %7 Function
+ %92 = OpVariable %7 Function
+ %102 = OpVariable %7 Function
+ %112 = OpVariable %7 Function
+ %122 = OpVariable %7 Function
+ OpStore %8 %9
+ OpBranch %10
+ %10 = OpLabel
+ %132 = OpPhi %6 %9 %5 %21 %13
+ OpLoopMerge %12 %13 None
+ OpBranch %14
+ %14 = OpLabel
+ %18 = OpSLessThan %17 %132 %16
+ OpBranchConditional %18 %11 %12
+ %11 = OpLabel
+ OpBranch %13
+ %13 = OpLabel
+ %21 = OpIAdd %6 %132 %20
+ OpStore %8 %21
+ OpBranch %10
+ %12 = OpLabel
+ OpStore %22 %9
+ OpBranch %23
+ %23 = OpLabel
+ %133 = OpPhi %6 %9 %12 %31 %26
+ OpLoopMerge %25 %26 Unroll
+ OpBranch %27
+ %27 = OpLabel
+ %29 = OpSLessThan %17 %133 %16
+ OpBranchConditional %29 %24 %25
+ %24 = OpLabel
+ OpBranch %26
+ %26 = OpLabel
+ %31 = OpIAdd %6 %133 %20
+ OpStore %22 %31
+ OpBranch %23
+ %25 = OpLabel
+ OpStore %32 %9
+ OpBranch %33
+ %33 = OpLabel
+ %134 = OpPhi %6 %9 %25 %41 %36
+ OpLoopMerge %35 %36 DontUnroll
+ OpBranch %37
+ %37 = OpLabel
+ %39 = OpSLessThan %17 %134 %16
+ OpBranchConditional %39 %34 %35
+ %34 = OpLabel
+ OpBranch %36
+ %36 = OpLabel
+ %41 = OpIAdd %6 %134 %20
+ OpStore %32 %41
+ OpBranch %33
+ %35 = OpLabel
+ OpStore %42 %9
+ OpBranch %43
+ %43 = OpLabel
+ %135 = OpPhi %6 %9 %35 %51 %46
+ OpLoopMerge %45 %46 DependencyInfinite
+ OpBranch %47
+ %47 = OpLabel
+ %49 = OpSLessThan %17 %135 %16
+ OpBranchConditional %49 %44 %45
+ %44 = OpLabel
+ OpBranch %46
+ %46 = OpLabel
+ %51 = OpIAdd %6 %135 %20
+ OpStore %42 %51
+ OpBranch %43
+ %45 = OpLabel
+ OpStore %52 %9
+ OpBranch %53
+ %53 = OpLabel
+ %136 = OpPhi %6 %9 %45 %61 %56
+ OpLoopMerge %55 %56 DependencyLength 3
+ OpBranch %57
+ %57 = OpLabel
+ %59 = OpSLessThan %17 %136 %16
+ OpBranchConditional %59 %54 %55
+ %54 = OpLabel
+ OpBranch %56
+ %56 = OpLabel
+ %61 = OpIAdd %6 %136 %20
+ OpStore %52 %61
+ OpBranch %53
+ %55 = OpLabel
+ OpStore %62 %9
+ OpBranch %63
+ %63 = OpLabel
+ %137 = OpPhi %6 %9 %55 %71 %66
+ OpLoopMerge %65 %66 MinIterations 10
+ OpBranch %67
+ %67 = OpLabel
+ %69 = OpSLessThan %17 %137 %16
+ OpBranchConditional %69 %64 %65
+ %64 = OpLabel
+ OpBranch %66
+ %66 = OpLabel
+ %71 = OpIAdd %6 %137 %20
+ OpStore %62 %71
+ OpBranch %63
+ %65 = OpLabel
+ OpStore %72 %9
+ OpBranch %73
+ %73 = OpLabel
+ %138 = OpPhi %6 %9 %65 %81 %76
+ OpLoopMerge %75 %76 MaxIterations 50
+ OpBranch %77
+ %77 = OpLabel
+ %79 = OpSLessThan %17 %138 %16
+ OpBranchConditional %79 %74 %75
+ %74 = OpLabel
+ OpBranch %76
+ %76 = OpLabel
+ %81 = OpIAdd %6 %138 %20
+ OpStore %72 %81
+ OpBranch %73
+ %75 = OpLabel
+ OpStore %82 %9
+ OpBranch %83
+ %83 = OpLabel
+ %139 = OpPhi %6 %9 %75 %91 %86
+ OpLoopMerge %85 %86 IterationMultiple 4
+ OpBranch %87
+ %87 = OpLabel
+ %89 = OpSLessThan %17 %139 %16
+ OpBranchConditional %89 %84 %85
+ %84 = OpLabel
+ OpBranch %86
+ %86 = OpLabel
+ %91 = OpIAdd %6 %139 %20
+ OpStore %82 %91
+ OpBranch %83
+ %85 = OpLabel
+ OpStore %92 %9
+ OpBranch %93
+ %93 = OpLabel
+ %140 = OpPhi %6 %9 %85 %101 %96
+ OpLoopMerge %95 %96 PeelCount 2
+ OpBranch %97
+ %97 = OpLabel
+ %99 = OpSLessThan %17 %140 %16
+ OpBranchConditional %99 %94 %95
+ %94 = OpLabel
+ OpBranch %96
+ %96 = OpLabel
+ %101 = OpIAdd %6 %140 %20
+ OpStore %92 %101
+ OpBranch %93
+ %95 = OpLabel
+ OpStore %102 %9
+ OpBranch %103
+ %103 = OpLabel
+ %141 = OpPhi %6 %9 %95 %111 %106
+ OpLoopMerge %105 %106 PartialCount 3
+ OpBranch %107
+ %107 = OpLabel
+ %109 = OpSLessThan %17 %141 %16
+ OpBranchConditional %109 %104 %105
+ %104 = OpLabel
+ OpBranch %106
+ %106 = OpLabel
+ %111 = OpIAdd %6 %141 %20
+ OpStore %102 %111
+ OpBranch %103
+ %105 = OpLabel
+ OpStore %112 %9
+ OpBranch %113
+ %113 = OpLabel
+ %142 = OpPhi %6 %9 %105 %121 %116
+ OpLoopMerge %115 %116 Unroll|PeelCount|PartialCount 3 4
+ OpBranch %117
+ %117 = OpLabel
+ %119 = OpSLessThan %17 %142 %16
+ OpBranchConditional %119 %114 %115
+ %114 = OpLabel
+ OpBranch %116
+ %116 = OpLabel
+ %121 = OpIAdd %6 %142 %20
+ OpStore %112 %121
+ OpBranch %113
+ %115 = OpLabel
+ OpStore %122 %9
+ OpBranch %123
+ %123 = OpLabel
+ %143 = OpPhi %6 %9 %115 %131 %126
+ OpLoopMerge %125 %126 DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount 2 5 90 4 7 14
+ OpBranch %127
+ %127 = OpLabel
+ %129 = OpSLessThan %17 %143 %16
+ OpBranchConditional %129 %124 %125
+ %124 = OpLabel
+ OpBranch %126
+ %126 = OpLabel
+ %131 = OpIAdd %6 %143 %20
+ OpStore %122 %131
+ OpBranch %123
+ %125 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_4;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // These are the loop headers together with the selection controls of their
+ // merge instructions:
+ // %10 None
+ // %23 Unroll
+ // %33 DontUnroll
+ // %43 DependencyInfinite
+ // %53 DependencyLength 3
+ // %63 MinIterations 10
+ // %73 MaxIterations 50
+ // %83 IterationMultiple 4
+ // %93 PeelCount 2
+ // %103 PartialCount 3
+ // %113 Unroll|PeelCount|PartialCount 3 4
+ // %123
+ // DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount
+ // 2 5 90 4 7 14
+
+ ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(10, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(
+ 10, SpvLoopControlDependencyInfiniteMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(10, SpvLoopControlDependencyLengthMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(10, SpvLoopControlMinIterationsMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(10, SpvLoopControlMaxIterationsMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(
+ 10, SpvLoopControlIterationMultipleMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 3)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 0, 3)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 3, 3)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(
+ 10,
+ SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
+ 3, 3)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(10,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlPeelCountMask |
+ SpvLoopControlPartialCountMask,
+ 3, 3)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(10,
+ SpvLoopControlDontUnrollMask |
+ SpvLoopControlPeelCountMask |
+ SpvLoopControlPartialCountMask,
+ 3, 3)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(
+ 23,
+ SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
+ 3, 3)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(23, SpvLoopControlMaxIterationsMask, 2, 3)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(33, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(33, SpvLoopControlMinIterationsMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(
+ 33, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(33,
+ SpvLoopControlDontUnrollMask |
+ SpvLoopControlPartialCountMask,
+ 0, 10)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(43, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(
+ 43,
+ SpvLoopControlMaskNone | SpvLoopControlDependencyInfiniteMask,
+ 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(
+ 43, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask,
+ 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(
+ 43,
+ SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask,
+ 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(43,
+ SpvLoopControlDependencyInfiniteMask |
+ SpvLoopControlDependencyLengthMask,
+ 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(
+ 43, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(53, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(53, SpvLoopControlMaxIterationsMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(
+ 53, SpvLoopControlMaskNone | SpvLoopControlDependencyLengthMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(
+ 53, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask,
+ 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(
+ 53, SpvLoopControlDontUnrollMask | SpvLoopControlDependencyLengthMask,
+ 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(53,
+ SpvLoopControlDependencyInfiniteMask |
+ SpvLoopControlDependencyLengthMask,
+ 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(
+ 53,
+ SpvLoopControlUnrollMask | SpvLoopControlDependencyLengthMask |
+ SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
+ 5, 3)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(63, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(63,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlMinIterationsMask |
+ SpvLoopControlPeelCountMask |
+ SpvLoopControlPartialCountMask,
+ 5, 3)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(63,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlMinIterationsMask |
+ SpvLoopControlPeelCountMask,
+ 23, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(
+ 63,
+ SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
+ SpvLoopControlPeelCountMask,
+ 2, 23)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(73, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(
+ 73,
+ SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
+ SpvLoopControlPeelCountMask |
+ SpvLoopControlPartialCountMask,
+ 5, 3)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(73,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlMaxIterationsMask |
+ SpvLoopControlPeelCountMask,
+ 23, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(
+ 73,
+ SpvLoopControlUnrollMask | SpvLoopControlMaxIterationsMask |
+ SpvLoopControlPeelCountMask,
+ 2, 23)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(
+ 83,
+ SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
+ SpvLoopControlPeelCountMask |
+ SpvLoopControlPartialCountMask,
+ 5, 3)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(83,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlIterationMultipleMask |
+ SpvLoopControlPeelCountMask,
+ 23, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(83,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlIterationMultipleMask |
+ SpvLoopControlPeelCountMask,
+ 2, 23)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(93, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 8)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(93, SpvLoopControlPartialCountMask, 0, 8)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(
+ 93,
+ SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
+ 16, 8)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(103, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(103,
+ SpvLoopControlDontUnrollMask |
+ SpvLoopControlPartialCountMask,
+ 0, 60)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(113, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(
+ 113,
+ SpvLoopControlIterationMultipleMask | SpvLoopControlPeelCountMask, 12,
+ 0)
+ .IsApplicable(context.get(), fact_manager));
+
+ ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlMaskNone, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(123, SpvLoopControlDontUnrollMask, 0, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(
+ TransformationSetLoopControl(
+ 123,
+ SpvLoopControlMinIterationsMask | SpvLoopControlMaxIterationsMask |
+ SpvLoopControlIterationMultipleMask |
+ SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
+ 7, 8)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(TransformationSetLoopControl(123,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlMinIterationsMask |
+ SpvLoopControlMaxIterationsMask |
+ SpvLoopControlPartialCountMask,
+ 0, 9)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSetLoopControl(
+ 123,
+ SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
+ SpvLoopControlMaxIterationsMask |
+ SpvLoopControlPartialCountMask,
+ 7, 9)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSetLoopControl(
+ 123,
+ SpvLoopControlDontUnrollMask | SpvLoopControlMinIterationsMask |
+ SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask,
+ 7, 9)
+ .IsApplicable(context.get(), fact_manager));
+
+ TransformationSetLoopControl(10,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlPeelCountMask |
+ SpvLoopControlPartialCountMask,
+ 3, 3)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(
+ 43, SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask,
+ 0, 0)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(63,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlMinIterationsMask |
+ SpvLoopControlPeelCountMask,
+ 23, 0)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(73,
+ SpvLoopControlUnrollMask |
+ SpvLoopControlMaxIterationsMask |
+ SpvLoopControlPeelCountMask,
+ 23, 0)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(
+ 93, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 16, 8)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0)
+ .Apply(context.get(), &fact_manager);
+ TransformationSetLoopControl(
+ 123,
+ SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
+ SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask,
+ 0, 9)
+ .Apply(context.get(), &fact_manager);
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %16 = OpConstant %6 100
+ %17 = OpTypeBool
+ %20 = OpConstant %6 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %22 = OpVariable %7 Function
+ %32 = OpVariable %7 Function
+ %42 = OpVariable %7 Function
+ %52 = OpVariable %7 Function
+ %62 = OpVariable %7 Function
+ %72 = OpVariable %7 Function
+ %82 = OpVariable %7 Function
+ %92 = OpVariable %7 Function
+ %102 = OpVariable %7 Function
+ %112 = OpVariable %7 Function
+ %122 = OpVariable %7 Function
+ OpStore %8 %9
+ OpBranch %10
+ %10 = OpLabel
+ %132 = OpPhi %6 %9 %5 %21 %13
+ OpLoopMerge %12 %13 Unroll|PeelCount|PartialCount 3 3
+ OpBranch %14
+ %14 = OpLabel
+ %18 = OpSLessThan %17 %132 %16
+ OpBranchConditional %18 %11 %12
+ %11 = OpLabel
+ OpBranch %13
+ %13 = OpLabel
+ %21 = OpIAdd %6 %132 %20
+ OpStore %8 %21
+ OpBranch %10
+ %12 = OpLabel
+ OpStore %22 %9
+ OpBranch %23
+ %23 = OpLabel
+ %133 = OpPhi %6 %9 %12 %31 %26
+ OpLoopMerge %25 %26 DontUnroll
+ OpBranch %27
+ %27 = OpLabel
+ %29 = OpSLessThan %17 %133 %16
+ OpBranchConditional %29 %24 %25
+ %24 = OpLabel
+ OpBranch %26
+ %26 = OpLabel
+ %31 = OpIAdd %6 %133 %20
+ OpStore %22 %31
+ OpBranch %23
+ %25 = OpLabel
+ OpStore %32 %9
+ OpBranch %33
+ %33 = OpLabel
+ %134 = OpPhi %6 %9 %25 %41 %36
+ OpLoopMerge %35 %36 Unroll
+ OpBranch %37
+ %37 = OpLabel
+ %39 = OpSLessThan %17 %134 %16
+ OpBranchConditional %39 %34 %35
+ %34 = OpLabel
+ OpBranch %36
+ %36 = OpLabel
+ %41 = OpIAdd %6 %134 %20
+ OpStore %32 %41
+ OpBranch %33
+ %35 = OpLabel
+ OpStore %42 %9
+ OpBranch %43
+ %43 = OpLabel
+ %135 = OpPhi %6 %9 %35 %51 %46
+ OpLoopMerge %45 %46 DontUnroll|DependencyInfinite
+ OpBranch %47
+ %47 = OpLabel
+ %49 = OpSLessThan %17 %135 %16
+ OpBranchConditional %49 %44 %45
+ %44 = OpLabel
+ OpBranch %46
+ %46 = OpLabel
+ %51 = OpIAdd %6 %135 %20
+ OpStore %42 %51
+ OpBranch %43
+ %45 = OpLabel
+ OpStore %52 %9
+ OpBranch %53
+ %53 = OpLabel
+ %136 = OpPhi %6 %9 %45 %61 %56
+ OpLoopMerge %55 %56 None
+ OpBranch %57
+ %57 = OpLabel
+ %59 = OpSLessThan %17 %136 %16
+ OpBranchConditional %59 %54 %55
+ %54 = OpLabel
+ OpBranch %56
+ %56 = OpLabel
+ %61 = OpIAdd %6 %136 %20
+ OpStore %52 %61
+ OpBranch %53
+ %55 = OpLabel
+ OpStore %62 %9
+ OpBranch %63
+ %63 = OpLabel
+ %137 = OpPhi %6 %9 %55 %71 %66
+ OpLoopMerge %65 %66 Unroll|MinIterations|PeelCount 10 23
+ OpBranch %67
+ %67 = OpLabel
+ %69 = OpSLessThan %17 %137 %16
+ OpBranchConditional %69 %64 %65
+ %64 = OpLabel
+ OpBranch %66
+ %66 = OpLabel
+ %71 = OpIAdd %6 %137 %20
+ OpStore %62 %71
+ OpBranch %63
+ %65 = OpLabel
+ OpStore %72 %9
+ OpBranch %73
+ %73 = OpLabel
+ %138 = OpPhi %6 %9 %65 %81 %76
+ OpLoopMerge %75 %76 Unroll|MaxIterations|PeelCount 50 23
+ OpBranch %77
+ %77 = OpLabel
+ %79 = OpSLessThan %17 %138 %16
+ OpBranchConditional %79 %74 %75
+ %74 = OpLabel
+ OpBranch %76
+ %76 = OpLabel
+ %81 = OpIAdd %6 %138 %20
+ OpStore %72 %81
+ OpBranch %73
+ %75 = OpLabel
+ OpStore %82 %9
+ OpBranch %83
+ %83 = OpLabel
+ %139 = OpPhi %6 %9 %75 %91 %86
+ OpLoopMerge %85 %86 DontUnroll
+ OpBranch %87
+ %87 = OpLabel
+ %89 = OpSLessThan %17 %139 %16
+ OpBranchConditional %89 %84 %85
+ %84 = OpLabel
+ OpBranch %86
+ %86 = OpLabel
+ %91 = OpIAdd %6 %139 %20
+ OpStore %82 %91
+ OpBranch %83
+ %85 = OpLabel
+ OpStore %92 %9
+ OpBranch %93
+ %93 = OpLabel
+ %140 = OpPhi %6 %9 %85 %101 %96
+ OpLoopMerge %95 %96 PeelCount|PartialCount 16 8
+ OpBranch %97
+ %97 = OpLabel
+ %99 = OpSLessThan %17 %140 %16
+ OpBranchConditional %99 %94 %95
+ %94 = OpLabel
+ OpBranch %96
+ %96 = OpLabel
+ %101 = OpIAdd %6 %140 %20
+ OpStore %92 %101
+ OpBranch %93
+ %95 = OpLabel
+ OpStore %102 %9
+ OpBranch %103
+ %103 = OpLabel
+ %141 = OpPhi %6 %9 %95 %111 %106
+ OpLoopMerge %105 %106 PartialCount 60
+ OpBranch %107
+ %107 = OpLabel
+ %109 = OpSLessThan %17 %141 %16
+ OpBranchConditional %109 %104 %105
+ %104 = OpLabel
+ OpBranch %106
+ %106 = OpLabel
+ %111 = OpIAdd %6 %141 %20
+ OpStore %102 %111
+ OpBranch %103
+ %105 = OpLabel
+ OpStore %112 %9
+ OpBranch %113
+ %113 = OpLabel
+ %142 = OpPhi %6 %9 %105 %121 %116
+ OpLoopMerge %115 %116 PeelCount 12
+ OpBranch %117
+ %117 = OpLabel
+ %119 = OpSLessThan %17 %142 %16
+ OpBranchConditional %119 %114 %115
+ %114 = OpLabel
+ OpBranch %116
+ %116 = OpLabel
+ %121 = OpIAdd %6 %142 %20
+ OpStore %112 %121
+ OpBranch %113
+ %115 = OpLabel
+ OpStore %122 %9
+ OpBranch %123
+ %123 = OpLabel
+ %143 = OpPhi %6 %9 %115 %131 %126
+ OpLoopMerge %125 %126 Unroll|MinIterations|MaxIterations|PartialCount 5 90 9
+ OpBranch %127
+ %127 = OpLabel
+ %129 = OpSLessThan %17 %143 %16
+ OpBranchConditional %129 %124 %125
+ %124 = OpLabel
+ OpBranch %126
+ %126 = OpLabel
+ %131 = OpIAdd %6 %143 %20
+ OpStore %122 %131
+ OpBranch %123
+ %125 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationSetLoopControlTest, CheckSPIRVVersionsRespected) {
+ // This test checks that we do not allow introducing PeelCount and
+ // PartialCount loop controls if the SPIR-V version being used does not
+ // support them.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "i"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %16 = OpConstant %6 10
+ %17 = OpTypeBool
+ %20 = OpConstant %6 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ OpStore %8 %9
+ OpBranch %10
+ %10 = OpLabel
+ OpLoopMerge %12 %13 None
+ OpBranch %14
+ %14 = OpLabel
+ %15 = OpLoad %6 %8
+ %18 = OpSLessThan %17 %15 %16
+ OpBranchConditional %18 %11 %12
+ %11 = OpLabel
+ OpBranch %13
+ %13 = OpLabel
+ %19 = OpLoad %6 %8
+ %21 = OpIAdd %6 %19 %20
+ OpStore %8 %21
+ OpBranch %10
+ %12 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto consumer = nullptr;
+ const auto context_1_0 =
+ BuildModule(SPV_ENV_UNIVERSAL_1_0, consumer, shader, kFuzzAssembleOption);
+ const auto context_1_1 =
+ BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer, shader, kFuzzAssembleOption);
+ const auto context_1_2 =
+ BuildModule(SPV_ENV_UNIVERSAL_1_2, consumer, shader, kFuzzAssembleOption);
+ const auto context_1_3 =
+ BuildModule(SPV_ENV_UNIVERSAL_1_3, consumer, shader, kFuzzAssembleOption);
+ const auto context_1_4 =
+ BuildModule(SPV_ENV_UNIVERSAL_1_4, consumer, shader, kFuzzAssembleOption);
+ const auto context_1_5 =
+ BuildModule(SPV_ENV_UNIVERSAL_1_5, consumer, shader, kFuzzAssembleOption);
+
+ FactManager fact_manager;
+
+ TransformationSetLoopControl set_peel_and_partial(
+ 10, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 4, 4);
+
+ // PeelCount and PartialCount were introduced in SPIRV 1.4, so are not valid
+ // in the context of older versions.
+ ASSERT_FALSE(
+ set_peel_and_partial.IsApplicable(context_1_0.get(), fact_manager));
+ ASSERT_FALSE(
+ set_peel_and_partial.IsApplicable(context_1_1.get(), fact_manager));
+ ASSERT_FALSE(
+ set_peel_and_partial.IsApplicable(context_1_2.get(), fact_manager));
+ ASSERT_FALSE(
+ set_peel_and_partial.IsApplicable(context_1_3.get(), fact_manager));
+
+ ASSERT_TRUE(
+ set_peel_and_partial.IsApplicable(context_1_4.get(), fact_manager));
+ ASSERT_TRUE(
+ set_peel_and_partial.IsApplicable(context_1_5.get(), fact_manager));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/transformation_set_memory_operands_mask_test.cpp b/test/fuzz/transformation_set_memory_operands_mask_test.cpp
new file mode 100644
index 0000000..ad4dc25
--- /dev/null
+++ b/test/fuzz/transformation_set_memory_operands_mask_test.cpp
@@ -0,0 +1,432 @@
+// 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/fuzz/transformation_set_memory_operands_mask.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationSetMemoryOperandsMaskTest, PreSpirv14) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %7 "Point3D"
+ OpMemberName %7 0 "x"
+ OpMemberName %7 1 "y"
+ OpMemberName %7 2 "z"
+ OpName %12 "global_points"
+ OpName %15 "block"
+ OpMemberName %15 0 "in_points"
+ OpMemberName %15 1 "in_point"
+ OpName %17 ""
+ OpName %133 "local_points"
+ OpMemberDecorate %7 0 Offset 0
+ OpMemberDecorate %7 1 Offset 4
+ OpMemberDecorate %7 2 Offset 8
+ OpDecorate %10 ArrayStride 16
+ OpMemberDecorate %15 0 Offset 0
+ OpMemberDecorate %15 1 Offset 192
+ OpDecorate %15 Block
+ OpDecorate %17 DescriptorSet 0
+ OpDecorate %17 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeStruct %6 %6 %6
+ %8 = OpTypeInt 32 0
+ %9 = OpConstant %8 12
+ %10 = OpTypeArray %7 %9
+ %11 = OpTypePointer Private %10
+ %12 = OpVariable %11 Private
+ %15 = OpTypeStruct %10 %7
+ %16 = OpTypePointer Uniform %15
+ %17 = OpVariable %16 Uniform
+ %18 = OpTypeInt 32 1
+ %19 = OpConstant %18 0
+ %20 = OpTypePointer Uniform %10
+ %24 = OpTypePointer Private %7
+ %27 = OpTypePointer Private %6
+ %30 = OpConstant %18 1
+ %132 = OpTypePointer Function %10
+ %135 = OpTypePointer Uniform %7
+ %145 = OpTypePointer Function %7
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %133 = OpVariable %132 Function
+ %21 = OpAccessChain %20 %17 %19
+ OpCopyMemory %12 %21 Aligned 16
+ OpCopyMemory %133 %12 Volatile
+ %136 = OpAccessChain %135 %17 %30
+ %138 = OpAccessChain %24 %12 %19
+ OpCopyMemory %138 %136 None
+ %146 = OpAccessChain %145 %133 %30
+ %147 = OpLoad %7 %146 Volatile|Nontemporal|Aligned 16
+ %148 = OpAccessChain %24 %12 %19
+ OpStore %148 %147 Nontemporal
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // Not OK: the instruction is not a memory access.
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(21, SpvOpAccessChain, 0),
+ SpvMemoryAccessMaskNone, 0)
+ .IsApplicable(context.get(), fact_manager));
+
+ // Not OK to remove Aligned
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(147, SpvOpLoad, 0),
+ SpvMemoryAccessVolatileMask | SpvMemoryAccessNontemporalMask,
+ 0)
+ .IsApplicable(context.get(), fact_manager));
+
+ TransformationSetMemoryOperandsMask transformation1(
+ MakeInstructionDescriptor(147, SpvOpLoad, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+ transformation1.Apply(context.get(), &fact_manager);
+
+ // Not OK to remove Aligned
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+ SpvMemoryAccessMaskNone, 0)
+ .IsApplicable(context.get(), fact_manager));
+
+ // OK: leaves the mask as is
+ ASSERT_TRUE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+ SpvMemoryAccessAlignedMask, 0)
+ .IsApplicable(context.get(), fact_manager));
+
+ // OK: adds Nontemporal and Volatile
+ TransformationSetMemoryOperandsMask transformation2(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask |
+ SpvMemoryAccessVolatileMask,
+ 0);
+ ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+ transformation2.Apply(context.get(), &fact_manager);
+
+ // Not OK to remove Volatile
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+ SpvMemoryAccessNontemporalMask, 0)
+ .IsApplicable(context.get(), fact_manager));
+
+ // Not OK to add Aligned
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0)
+ .IsApplicable(context.get(), fact_manager));
+
+ // OK: adds Nontemporal
+ TransformationSetMemoryOperandsMask transformation3(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+ SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+ transformation3.Apply(context.get(), &fact_manager);
+
+ // OK: adds Nontemporal and Volatile
+ TransformationSetMemoryOperandsMask transformation4(
+ MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
+ SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+ transformation4.Apply(context.get(), &fact_manager);
+
+ // OK: removes Nontemporal, adds Volatile
+ TransformationSetMemoryOperandsMask transformation5(
+ MakeInstructionDescriptor(148, SpvOpStore, 0),
+ SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
+ transformation5.Apply(context.get(), &fact_manager);
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %7 "Point3D"
+ OpMemberName %7 0 "x"
+ OpMemberName %7 1 "y"
+ OpMemberName %7 2 "z"
+ OpName %12 "global_points"
+ OpName %15 "block"
+ OpMemberName %15 0 "in_points"
+ OpMemberName %15 1 "in_point"
+ OpName %17 ""
+ OpName %133 "local_points"
+ OpMemberDecorate %7 0 Offset 0
+ OpMemberDecorate %7 1 Offset 4
+ OpMemberDecorate %7 2 Offset 8
+ OpDecorate %10 ArrayStride 16
+ OpMemberDecorate %15 0 Offset 0
+ OpMemberDecorate %15 1 Offset 192
+ OpDecorate %15 Block
+ OpDecorate %17 DescriptorSet 0
+ OpDecorate %17 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeStruct %6 %6 %6
+ %8 = OpTypeInt 32 0
+ %9 = OpConstant %8 12
+ %10 = OpTypeArray %7 %9
+ %11 = OpTypePointer Private %10
+ %12 = OpVariable %11 Private
+ %15 = OpTypeStruct %10 %7
+ %16 = OpTypePointer Uniform %15
+ %17 = OpVariable %16 Uniform
+ %18 = OpTypeInt 32 1
+ %19 = OpConstant %18 0
+ %20 = OpTypePointer Uniform %10
+ %24 = OpTypePointer Private %7
+ %27 = OpTypePointer Private %6
+ %30 = OpConstant %18 1
+ %132 = OpTypePointer Function %10
+ %135 = OpTypePointer Uniform %7
+ %145 = OpTypePointer Function %7
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %133 = OpVariable %132 Function
+ %21 = OpAccessChain %20 %17 %19
+ OpCopyMemory %12 %21 Aligned|Nontemporal|Volatile 16
+ OpCopyMemory %133 %12 Nontemporal|Volatile
+ %136 = OpAccessChain %135 %17 %30
+ %138 = OpAccessChain %24 %12 %19
+ OpCopyMemory %138 %136 Nontemporal|Volatile
+ %146 = OpAccessChain %145 %133 %30
+ %147 = OpLoad %7 %146 Aligned|Volatile 16
+ %148 = OpAccessChain %24 %12 %19
+ OpStore %148 %147 Volatile
+ OpReturn
+ OpFunctionEnd
+ )";
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationSetMemoryOperandsMaskTest, Spirv14) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %12 %17
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %7 "Point3D"
+ OpMemberName %7 0 "x"
+ OpMemberName %7 1 "y"
+ OpMemberName %7 2 "z"
+ OpName %12 "global_points"
+ OpName %15 "block"
+ OpMemberName %15 0 "in_points"
+ OpMemberName %15 1 "in_point"
+ OpName %17 ""
+ OpName %133 "local_points"
+ OpMemberDecorate %7 0 Offset 0
+ OpMemberDecorate %7 1 Offset 4
+ OpMemberDecorate %7 2 Offset 8
+ OpDecorate %10 ArrayStride 16
+ OpMemberDecorate %15 0 Offset 0
+ OpMemberDecorate %15 1 Offset 192
+ OpDecorate %15 Block
+ OpDecorate %17 DescriptorSet 0
+ OpDecorate %17 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeStruct %6 %6 %6
+ %8 = OpTypeInt 32 0
+ %9 = OpConstant %8 12
+ %10 = OpTypeArray %7 %9
+ %11 = OpTypePointer Private %10
+ %12 = OpVariable %11 Private
+ %15 = OpTypeStruct %10 %7
+ %16 = OpTypePointer Uniform %15
+ %17 = OpVariable %16 Uniform
+ %18 = OpTypeInt 32 1
+ %19 = OpConstant %18 0
+ %20 = OpTypePointer Uniform %10
+ %24 = OpTypePointer Private %7
+ %27 = OpTypePointer Private %6
+ %30 = OpConstant %18 1
+ %132 = OpTypePointer Function %10
+ %135 = OpTypePointer Uniform %7
+ %145 = OpTypePointer Function %7
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %133 = OpVariable %132 Function
+ %21 = OpAccessChain %20 %17 %19
+ OpCopyMemory %12 %21 Aligned 16 Nontemporal|Aligned 16
+ OpCopyMemory %133 %12 Volatile
+ %136 = OpAccessChain %135 %17 %30
+ %138 = OpAccessChain %24 %12 %19
+ OpCopyMemory %138 %136 None Aligned 16
+ OpCopyMemory %138 %136 Aligned 16
+ %146 = OpAccessChain %145 %133 %30
+ %147 = OpLoad %7 %146 Volatile|Nontemporal|Aligned 16
+ %148 = OpAccessChain %24 %12 %19
+ OpStore %148 %147 Nontemporal
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_4;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ TransformationSetMemoryOperandsMask transformation1(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 1);
+ // Bad: cannot remove aligned
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+ SpvMemoryAccessVolatileMask, 1)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+ transformation1.Apply(context.get(), &fact_manager);
+
+ TransformationSetMemoryOperandsMask transformation2(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+ SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
+ // Bad: cannot remove volatile
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+ SpvMemoryAccessNontemporalMask, 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+ transformation2.Apply(context.get(), &fact_manager);
+
+ TransformationSetMemoryOperandsMask transformation3(
+ MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 1);
+ // Bad: the first mask is None, so Aligned cannot be added to it.
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask,
+ 0)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+ transformation3.Apply(context.get(), &fact_manager);
+
+ TransformationSetMemoryOperandsMask transformation4(
+ MakeInstructionDescriptor(138, SpvOpCopyMemory, 1),
+ SpvMemoryAccessVolatileMask, 1);
+ ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+ transformation4.Apply(context.get(), &fact_manager);
+
+ TransformationSetMemoryOperandsMask transformation5(
+ MakeInstructionDescriptor(147, SpvOpLoad, 0),
+ SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask, 0);
+ ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
+ transformation5.Apply(context.get(), &fact_manager);
+
+ TransformationSetMemoryOperandsMask transformation6(
+ MakeInstructionDescriptor(148, SpvOpStore, 0), SpvMemoryAccessMaskNone,
+ 0);
+ ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager));
+ transformation6.Apply(context.get(), &fact_manager);
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %12 %17
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %7 "Point3D"
+ OpMemberName %7 0 "x"
+ OpMemberName %7 1 "y"
+ OpMemberName %7 2 "z"
+ OpName %12 "global_points"
+ OpName %15 "block"
+ OpMemberName %15 0 "in_points"
+ OpMemberName %15 1 "in_point"
+ OpName %17 ""
+ OpName %133 "local_points"
+ OpMemberDecorate %7 0 Offset 0
+ OpMemberDecorate %7 1 Offset 4
+ OpMemberDecorate %7 2 Offset 8
+ OpDecorate %10 ArrayStride 16
+ OpMemberDecorate %15 0 Offset 0
+ OpMemberDecorate %15 1 Offset 192
+ OpDecorate %15 Block
+ OpDecorate %17 DescriptorSet 0
+ OpDecorate %17 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeStruct %6 %6 %6
+ %8 = OpTypeInt 32 0
+ %9 = OpConstant %8 12
+ %10 = OpTypeArray %7 %9
+ %11 = OpTypePointer Private %10
+ %12 = OpVariable %11 Private
+ %15 = OpTypeStruct %10 %7
+ %16 = OpTypePointer Uniform %15
+ %17 = OpVariable %16 Uniform
+ %18 = OpTypeInt 32 1
+ %19 = OpConstant %18 0
+ %20 = OpTypePointer Uniform %10
+ %24 = OpTypePointer Private %7
+ %27 = OpTypePointer Private %6
+ %30 = OpConstant %18 1
+ %132 = OpTypePointer Function %10
+ %135 = OpTypePointer Uniform %7
+ %145 = OpTypePointer Function %7
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %133 = OpVariable %132 Function
+ %21 = OpAccessChain %20 %17 %19
+ OpCopyMemory %12 %21 Aligned 16 Aligned|Volatile 16
+ OpCopyMemory %133 %12 Volatile Nontemporal|Volatile
+ %136 = OpAccessChain %135 %17 %30
+ %138 = OpAccessChain %24 %12 %19
+ OpCopyMemory %138 %136 None Aligned|Nontemporal 16
+ OpCopyMemory %138 %136 Aligned 16 Volatile
+ %146 = OpAccessChain %145 %133 %30
+ %147 = OpLoad %7 %146 Volatile|Aligned 16
+ %148 = OpAccessChain %24 %12 %19
+ OpStore %148 %147 None
+ OpReturn
+ OpFunctionEnd
+ )";
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/transformation_set_selection_control_test.cpp b/test/fuzz/transformation_set_selection_control_test.cpp
new file mode 100644
index 0000000..9696417
--- /dev/null
+++ b/test/fuzz/transformation_set_selection_control_test.cpp
@@ -0,0 +1,219 @@
+// 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/fuzz/transformation_set_selection_control.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationSetSelectionControlTest, VariousScenarios) {
+ // This is a simple transformation; this test captures the important things
+ // to check for.
+
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "i"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %16 = OpConstant %6 10
+ %17 = OpTypeBool
+ %20 = OpConstant %6 3
+ %25 = OpConstant %6 1
+ %28 = OpConstant %6 2
+ %38 = OpConstant %6 4
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ OpStore %8 %9
+ OpBranch %10
+ %10 = OpLabel
+ OpLoopMerge %12 %13 None
+ OpBranch %14
+ %14 = OpLabel
+ %15 = OpLoad %6 %8
+ %18 = OpSLessThan %17 %15 %16
+ OpBranchConditional %18 %11 %12
+ %11 = OpLabel
+ %19 = OpLoad %6 %8
+ %21 = OpSGreaterThan %17 %19 %20
+ OpSelectionMerge %23 Flatten
+ OpBranchConditional %21 %22 %23
+ %22 = OpLabel
+ %24 = OpLoad %6 %8
+ %26 = OpIAdd %6 %24 %25
+ OpStore %8 %26
+ OpBranch %23
+ %23 = OpLabel
+ %27 = OpLoad %6 %8
+ %29 = OpSLessThan %17 %27 %28
+ OpSelectionMerge %31 DontFlatten
+ OpBranchConditional %29 %30 %31
+ %30 = OpLabel
+ %32 = OpLoad %6 %8
+ %33 = OpISub %6 %32 %25
+ OpStore %8 %33
+ OpBranch %31
+ %31 = OpLabel
+ %34 = OpLoad %6 %8
+ OpSelectionMerge %37 None
+ OpSwitch %34 %36 0 %35
+ %36 = OpLabel
+ OpBranch %37
+ %35 = OpLabel
+ %39 = OpLoad %6 %8
+ %40 = OpIAdd %6 %39 %38
+ OpStore %8 %40
+ OpBranch %36
+ %37 = OpLabel
+ OpBranch %13
+ %13 = OpLabel
+ %43 = OpLoad %6 %8
+ %44 = OpIAdd %6 %43 %25
+ OpStore %8 %44
+ OpBranch %10
+ %12 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+
+ FactManager fact_manager;
+
+ // %44 is not a block
+ ASSERT_FALSE(
+ TransformationSetSelectionControl(44, SpvSelectionControlFlattenMask)
+ .IsApplicable(context.get(), fact_manager));
+ // %13 does not end with OpSelectionMerge
+ ASSERT_FALSE(
+ TransformationSetSelectionControl(13, SpvSelectionControlMaskNone)
+ .IsApplicable(context.get(), fact_manager));
+ // %10 ends in OpLoopMerge, not OpSelectionMerge
+ ASSERT_FALSE(
+ TransformationSetSelectionControl(10, SpvSelectionControlMaskNone)
+ .IsApplicable(context.get(), fact_manager));
+
+ TransformationSetSelectionControl transformation1(
+ 11, SpvSelectionControlDontFlattenMask);
+ ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+ transformation1.Apply(context.get(), &fact_manager);
+
+ TransformationSetSelectionControl transformation2(
+ 23, SpvSelectionControlFlattenMask);
+ ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+ transformation2.Apply(context.get(), &fact_manager);
+
+ TransformationSetSelectionControl transformation3(
+ 31, SpvSelectionControlMaskNone);
+ ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+ transformation3.Apply(context.get(), &fact_manager);
+
+ TransformationSetSelectionControl transformation4(
+ 31, SpvSelectionControlFlattenMask);
+ ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+ transformation4.Apply(context.get(), &fact_manager);
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "i"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 0
+ %16 = OpConstant %6 10
+ %17 = OpTypeBool
+ %20 = OpConstant %6 3
+ %25 = OpConstant %6 1
+ %28 = OpConstant %6 2
+ %38 = OpConstant %6 4
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ OpStore %8 %9
+ OpBranch %10
+ %10 = OpLabel
+ OpLoopMerge %12 %13 None
+ OpBranch %14
+ %14 = OpLabel
+ %15 = OpLoad %6 %8
+ %18 = OpSLessThan %17 %15 %16
+ OpBranchConditional %18 %11 %12
+ %11 = OpLabel
+ %19 = OpLoad %6 %8
+ %21 = OpSGreaterThan %17 %19 %20
+ OpSelectionMerge %23 DontFlatten
+ OpBranchConditional %21 %22 %23
+ %22 = OpLabel
+ %24 = OpLoad %6 %8
+ %26 = OpIAdd %6 %24 %25
+ OpStore %8 %26
+ OpBranch %23
+ %23 = OpLabel
+ %27 = OpLoad %6 %8
+ %29 = OpSLessThan %17 %27 %28
+ OpSelectionMerge %31 Flatten
+ OpBranchConditional %29 %30 %31
+ %30 = OpLabel
+ %32 = OpLoad %6 %8
+ %33 = OpISub %6 %32 %25
+ OpStore %8 %33
+ OpBranch %31
+ %31 = OpLabel
+ %34 = OpLoad %6 %8
+ OpSelectionMerge %37 Flatten
+ OpSwitch %34 %36 0 %35
+ %36 = OpLabel
+ OpBranch %37
+ %35 = OpLabel
+ %39 = OpLoad %6 %8
+ %40 = OpIAdd %6 %39 %38
+ OpStore %8 %40
+ OpBranch %36
+ %37 = OpLabel
+ OpBranch %13
+ %13 = OpLabel
+ %43 = OpLoad %6 %8
+ %44 = OpIAdd %6 %43 %25
+ OpStore %8 %44
+ OpBranch %10
+ %12 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzz/transformation_split_block_test.cpp b/test/fuzz/transformation_split_block_test.cpp
index d33ccba..d162e07 100644
--- a/test/fuzz/transformation_split_block_test.cpp
+++ b/test/fuzz/transformation_split_block_test.cpp
@@ -13,6 +13,7 @@
// limitations under the License.
#include "source/fuzz/transformation_split_block.h"
+#include "source/fuzz/instruction_descriptor.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
@@ -90,44 +91,55 @@
FactManager fact_manager;
// No split before OpVariable
- ASSERT_FALSE(TransformationSplitBlock(8, 0, 100).IsApplicable(context.get(),
- fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(8, 1, 100).IsApplicable(context.get(),
- fact_manager));
+ ASSERT_FALSE(TransformationSplitBlock(
+ MakeInstructionDescriptor(8, SpvOpVariable, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSplitBlock(
+ MakeInstructionDescriptor(8, SpvOpVariable, 1), 100)
+ .IsApplicable(context.get(), fact_manager));
// No split before OpLabel
- ASSERT_FALSE(TransformationSplitBlock(14, 0, 100)
+ ASSERT_FALSE(TransformationSplitBlock(
+ MakeInstructionDescriptor(14, SpvOpLabel, 0), 100)
.IsApplicable(context.get(), fact_manager));
// No split if base instruction is outside a function
- ASSERT_FALSE(TransformationSplitBlock(1, 0, 100).IsApplicable(context.get(),
- fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(1, 4, 100).IsApplicable(context.get(),
- fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(1, 35, 100)
+ ASSERT_FALSE(
+ TransformationSplitBlock(MakeInstructionDescriptor(1, SpvOpLabel, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSplitBlock(
+ MakeInstructionDescriptor(1, SpvOpExecutionMode, 0), 100)
.IsApplicable(context.get(), fact_manager));
// No split if block is loop header
- ASSERT_FALSE(TransformationSplitBlock(27, 0, 100)
- .IsApplicable(context.get(), fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(27, 1, 100)
- .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100)
+ .IsApplicable(context.get(), fact_manager));
// No split if base instruction does not exist
- ASSERT_FALSE(TransformationSplitBlock(88, 0, 100)
- .IsApplicable(context.get(), fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(88, 22, 100)
+ ASSERT_FALSE(
+ TransformationSplitBlock(MakeInstructionDescriptor(88, SpvOpIAdd, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSplitBlock(
+ MakeInstructionDescriptor(88, SpvOpIMul, 22), 100)
.IsApplicable(context.get(), fact_manager));
- // No split if offset is too large (goes into another block)
- ASSERT_FALSE(TransformationSplitBlock(18, 3, 100)
- .IsApplicable(context.get(), fact_manager));
+ // No split if too many instructions with the desired opcode are skipped
+ ASSERT_FALSE(
+ TransformationSplitBlock(
+ MakeInstructionDescriptor(18, SpvOpBranchConditional, 1), 100)
+ .IsApplicable(context.get(), fact_manager));
// No split if id in use
- ASSERT_FALSE(TransformationSplitBlock(18, 0, 27).IsApplicable(context.get(),
- fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(18, 0, 14).IsApplicable(context.get(),
- fact_manager));
+ ASSERT_FALSE(TransformationSplitBlock(
+ MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 27)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSplitBlock(
+ MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 14)
+ .IsApplicable(context.get(), fact_manager));
}
TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
@@ -188,7 +200,8 @@
FactManager fact_manager;
- auto split_1 = TransformationSplitBlock(5, 3, 100);
+ auto split_1 = TransformationSplitBlock(
+ MakeInstructionDescriptor(5, SpvOpStore, 0), 100);
ASSERT_TRUE(split_1.IsApplicable(context.get(), fact_manager));
split_1.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
@@ -235,7 +248,8 @@
)";
ASSERT_TRUE(IsEqual(env, after_split_1, context.get()));
- auto split_2 = TransformationSplitBlock(11, 1, 101);
+ auto split_2 = TransformationSplitBlock(
+ MakeInstructionDescriptor(11, SpvOpStore, 0), 101);
ASSERT_TRUE(split_2.IsApplicable(context.get(), fact_manager));
split_2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
@@ -284,7 +298,8 @@
)";
ASSERT_TRUE(IsEqual(env, after_split_2, context.get()));
- auto split_3 = TransformationSplitBlock(14, 0, 102);
+ auto split_3 = TransformationSplitBlock(
+ MakeInstructionDescriptor(14, SpvOpLoad, 0), 102);
ASSERT_TRUE(split_3.IsApplicable(context.get(), fact_manager));
split_3.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
@@ -399,12 +414,17 @@
FactManager fact_manager;
// Illegal to split between the merge and the conditional branch.
- ASSERT_FALSE(TransformationSplitBlock(14, 2, 100)
- .IsApplicable(context.get(), fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(12, 3, 100)
- .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSplitBlock(
+ MakeInstructionDescriptor(14, SpvOpBranchConditional, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSplitBlock(
+ MakeInstructionDescriptor(12, SpvOpBranchConditional, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
- auto split = TransformationSplitBlock(14, 1, 100);
+ auto split = TransformationSplitBlock(
+ MakeInstructionDescriptor(14, SpvOpSelectionMerge, 0), 100);
ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
split.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
@@ -523,12 +543,15 @@
FactManager fact_manager;
// Illegal to split between the merge and the conditional branch.
- ASSERT_FALSE(TransformationSplitBlock(9, 2, 100).IsApplicable(context.get(),
- fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(15, 3, 100)
+ ASSERT_FALSE(TransformationSplitBlock(
+ MakeInstructionDescriptor(9, SpvOpSwitch, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(TransformationSplitBlock(
+ MakeInstructionDescriptor(15, SpvOpSwitch, 0), 100)
.IsApplicable(context.get(), fact_manager));
- auto split = TransformationSplitBlock(9, 1, 100);
+ auto split = TransformationSplitBlock(
+ MakeInstructionDescriptor(9, SpvOpSelectionMerge, 0), 100);
ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
split.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
@@ -654,12 +677,15 @@
// We cannot split before OpPhi instructions, since the number of incoming
// blocks may not appropriately match after splitting.
- ASSERT_FALSE(TransformationSplitBlock(26, 0, 100)
- .IsApplicable(context.get(), fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(27, 0, 100)
- .IsApplicable(context.get(), fact_manager));
- ASSERT_FALSE(TransformationSplitBlock(27, 1, 100)
- .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSplitBlock(MakeInstructionDescriptor(26, SpvOpPhi, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100)
+ .IsApplicable(context.get(), fact_manager));
}
TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) {
@@ -687,12 +713,12 @@
%10 = OpVariable %7 Function
OpStore %8 %9
%11 = OpLoad %6 %8
- OpBranch %20
- %20 = OpLabel
- %21 = OpPhi %6 %11 %5
- OpStore %10 %21
- OpReturn
- OpFunctionEnd
+ OpBranch %20
+ %20 = OpLabel
+ %21 = OpPhi %6 %11 %5
+ OpStore %10 %21
+ OpReturn
+ OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
@@ -701,9 +727,13 @@
FactManager fact_manager;
- ASSERT_TRUE(TransformationSplitBlock(21, 0, 100)
- .IsApplicable(context.get(), fact_manager));
- auto split = TransformationSplitBlock(20, 1, 100);
+ ASSERT_TRUE(
+ TransformationSplitBlock(MakeInstructionDescriptor(21, SpvOpPhi, 0), 100)
+ .IsApplicable(context.get(), fact_manager));
+ // An equivalent transformation to the above, just described with respect to a
+ // different base instruction.
+ auto split =
+ TransformationSplitBlock(MakeInstructionDescriptor(20, SpvOpPhi, 0), 100);
ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
split.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
@@ -732,14 +762,14 @@
%10 = OpVariable %7 Function
OpStore %8 %9
%11 = OpLoad %6 %8
- OpBranch %20
- %20 = OpLabel
- OpBranch %100
- %100 = OpLabel
- %21 = OpPhi %6 %11 %20
- OpStore %10 %21
- OpReturn
- OpFunctionEnd
+ OpBranch %20
+ %20 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ %21 = OpPhi %6 %11 %20
+ OpStore %10 %21
+ OpReturn
+ OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_split, context.get()));
}
diff --git a/test/fuzz/transformation_vector_shuffle_test.cpp b/test/fuzz/transformation_vector_shuffle_test.cpp
new file mode 100644
index 0000000..385c38b
--- /dev/null
+++ b/test/fuzz/transformation_vector_shuffle_test.cpp
@@ -0,0 +1,532 @@
+// 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/fuzz/transformation_vector_shuffle.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationVectorShuffle, BasicTest) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeBool
+ %7 = OpTypeVector %6 2
+ %10 = OpConstantTrue %6
+ %11 = OpConstantFalse %6
+ %12 = OpConstantComposite %7 %10 %11
+ %112 = OpUndef %7
+ %13 = OpTypeVector %6 3
+ %16 = OpConstantComposite %13 %10 %11 %10
+ %17 = OpTypeVector %6 4
+ %20 = OpConstantComposite %17 %10 %11 %10 %11
+ %21 = OpTypeInt 32 1
+ %22 = OpTypeVector %21 2
+ %25 = OpConstant %21 1
+ %26 = OpConstant %21 0
+ %27 = OpConstantComposite %22 %25 %26
+ %28 = OpTypeVector %21 3
+ %31 = OpConstantComposite %28 %25 %26 %25
+ %32 = OpTypeVector %21 4
+ %33 = OpTypePointer Function %32
+ %35 = OpConstantComposite %32 %25 %26 %25 %26
+ %36 = OpTypeInt 32 0
+ %37 = OpTypeVector %36 2
+ %40 = OpConstant %36 1
+ %41 = OpConstant %36 0
+ %42 = OpConstantComposite %37 %40 %41
+ %43 = OpTypeVector %36 3
+ %46 = OpConstantComposite %43 %40 %41 %40
+ %47 = OpTypeVector %36 4
+ %50 = OpConstantComposite %47 %40 %41 %40 %41
+ %51 = OpTypeFloat 32
+ %55 = OpConstant %51 1
+ %56 = OpConstant %51 0
+ %58 = OpTypeVector %51 3
+ %61 = OpConstantComposite %58 %55 %56 %55
+ %62 = OpTypeVector %51 4
+ %65 = OpConstantComposite %62 %55 %56 %55 %56
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpSelectionMerge %100 None
+ OpBranchConditional %10 %101 %102
+ %101 = OpLabel
+ %103 = OpCompositeConstruct %62 %55 %55 %55 %56
+ OpBranch %100
+ %102 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_4;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
+ MakeDataDescriptor(12, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}),
+ MakeDataDescriptor(12, {1}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
+ MakeDataDescriptor(16, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}),
+ MakeDataDescriptor(16, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
+ MakeDataDescriptor(16, {2}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
+ MakeDataDescriptor(20, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}),
+ MakeDataDescriptor(20, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
+ MakeDataDescriptor(20, {2}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}),
+ MakeDataDescriptor(20, {3}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
+ MakeDataDescriptor(27, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}),
+ MakeDataDescriptor(27, {1}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
+ MakeDataDescriptor(31, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}),
+ MakeDataDescriptor(31, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
+ MakeDataDescriptor(31, {2}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
+ MakeDataDescriptor(35, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}),
+ MakeDataDescriptor(35, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
+ MakeDataDescriptor(35, {2}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}),
+ MakeDataDescriptor(35, {3}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
+ MakeDataDescriptor(42, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}),
+ MakeDataDescriptor(42, {1}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
+ MakeDataDescriptor(46, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}),
+ MakeDataDescriptor(46, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
+ MakeDataDescriptor(46, {2}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
+ MakeDataDescriptor(50, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}),
+ MakeDataDescriptor(50, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
+ MakeDataDescriptor(50, {2}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}),
+ MakeDataDescriptor(50, {3}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}),
+ MakeDataDescriptor(61, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(56, {}),
+ MakeDataDescriptor(61, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}),
+ MakeDataDescriptor(61, {2}), context.get());
+
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}),
+ MakeDataDescriptor(65, {0}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(56, {}),
+ MakeDataDescriptor(65, {1}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}),
+ MakeDataDescriptor(65, {2}), context.get());
+ fact_manager.AddFactDataSynonym(MakeDataDescriptor(56, {}),
+ MakeDataDescriptor(65, {3}), context.get());
+
+ // %103 does not dominate the return instruction.
+ ASSERT_FALSE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 103, 65,
+ {3, 5, 7})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Illegal to shuffle a bvec2 and a vec3
+ ASSERT_FALSE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 112, 61,
+ {0, 2, 4})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Illegal to shuffle an ivec2 and a uvec4
+ ASSERT_FALSE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 50,
+ {1, 3, 5})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Vector 1 does not exist
+ ASSERT_FALSE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 300, 50,
+ {1, 3, 5})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Vector 2 does not exist
+ ASSERT_FALSE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 300,
+ {1, 3, 5})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Index out of range
+ ASSERT_FALSE(
+ TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0, 20})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Too many indices
+ ASSERT_FALSE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112,
+ {0, 1, 0, 1, 0, 1, 0, 1})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Too few indices
+ ASSERT_FALSE(
+ TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Too few indices again
+ ASSERT_FALSE(
+ TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Indices define unknown type: we do not have vec2
+ ASSERT_FALSE(
+ TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 65, 65, {0, 1})
+ .IsApplicable(context.get(), fact_manager));
+
+ // The instruction to insert before does not exist
+ ASSERT_FALSE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpCompositeConstruct, 1),
+ 201, 20, 12, {0xFFFFFFFF, 3, 5})
+ .IsApplicable(context.get(), fact_manager));
+
+ // The 'fresh' id is already in use
+ ASSERT_FALSE(
+ TransformationVectorShuffle(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 12, 12, 112, {})
+ .IsApplicable(context.get(), fact_manager));
+
+ protobufs::DataDescriptor temp_dd;
+
+ TransformationVectorShuffle transformation1(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {1, 0});
+ ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+ transformation1.Apply(context.get(), &fact_manager);
+ temp_dd = MakeDataDescriptor(200, {0});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(200, {1});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {}), temp_dd,
+ context.get()));
+
+ TransformationVectorShuffle transformation2(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 201, 20, 12,
+ {0xFFFFFFFF, 3, 5});
+ ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+ transformation2.Apply(context.get(), &fact_manager);
+ temp_dd = MakeDataDescriptor(201, {1});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(201, {2});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}), temp_dd,
+ context.get()));
+
+ TransformationVectorShuffle transformation3(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 202, 27, 35, {5, 4, 1});
+ ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+ transformation3.Apply(context.get(), &fact_manager);
+ temp_dd = MakeDataDescriptor(202, {0});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(26, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(202, {1});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(25, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(202, {2});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(26, {}), temp_dd,
+ context.get()));
+
+ TransformationVectorShuffle transformation4(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 203, 42, 46, {0, 1});
+ ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+ transformation4.Apply(context.get(), &fact_manager);
+ temp_dd = MakeDataDescriptor(203, {0});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(203, {1});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd,
+ context.get()));
+
+ TransformationVectorShuffle transformation5(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 204, 42, 46, {2, 3, 4});
+ ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
+ transformation5.Apply(context.get(), &fact_manager);
+ temp_dd = MakeDataDescriptor(204, {0});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(204, {1});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(204, {2});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
+ context.get()));
+
+ TransformationVectorShuffle transformation6(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 205, 42, 42,
+ {0, 1, 2, 3});
+ ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager));
+ transformation6.Apply(context.get(), &fact_manager);
+ temp_dd = MakeDataDescriptor(205, {0});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(205, {1});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(205, {2});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
+ context.get()));
+ temp_dd = MakeDataDescriptor(205, {3});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd,
+ context.get()));
+
+ // swizzle vec4 from vec4 and vec4 using some undefs
+ TransformationVectorShuffle transformation7(
+ MakeInstructionDescriptor(100, SpvOpReturn, 0), 206, 65, 65,
+ {0xFFFFFFFF, 3, 6, 0xFFFFFFFF});
+ ASSERT_TRUE(transformation7.IsApplicable(context.get(), fact_manager));
+ transformation7.Apply(context.get(), &fact_manager);
+ temp_dd = MakeDataDescriptor(206, {1});
+ ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}), temp_dd,
+ context.get()));
+
+ std::string after_transformation = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeBool
+ %7 = OpTypeVector %6 2
+ %10 = OpConstantTrue %6
+ %11 = OpConstantFalse %6
+ %12 = OpConstantComposite %7 %10 %11
+ %112 = OpUndef %7
+ %13 = OpTypeVector %6 3
+ %16 = OpConstantComposite %13 %10 %11 %10
+ %17 = OpTypeVector %6 4
+ %20 = OpConstantComposite %17 %10 %11 %10 %11
+ %21 = OpTypeInt 32 1
+ %22 = OpTypeVector %21 2
+ %25 = OpConstant %21 1
+ %26 = OpConstant %21 0
+ %27 = OpConstantComposite %22 %25 %26
+ %28 = OpTypeVector %21 3
+ %31 = OpConstantComposite %28 %25 %26 %25
+ %32 = OpTypeVector %21 4
+ %33 = OpTypePointer Function %32
+ %35 = OpConstantComposite %32 %25 %26 %25 %26
+ %36 = OpTypeInt 32 0
+ %37 = OpTypeVector %36 2
+ %40 = OpConstant %36 1
+ %41 = OpConstant %36 0
+ %42 = OpConstantComposite %37 %40 %41
+ %43 = OpTypeVector %36 3
+ %46 = OpConstantComposite %43 %40 %41 %40
+ %47 = OpTypeVector %36 4
+ %50 = OpConstantComposite %47 %40 %41 %40 %41
+ %51 = OpTypeFloat 32
+ %55 = OpConstant %51 1
+ %56 = OpConstant %51 0
+ %58 = OpTypeVector %51 3
+ %61 = OpConstantComposite %58 %55 %56 %55
+ %62 = OpTypeVector %51 4
+ %65 = OpConstantComposite %62 %55 %56 %55 %56
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpSelectionMerge %100 None
+ OpBranchConditional %10 %101 %102
+ %101 = OpLabel
+ %103 = OpCompositeConstruct %62 %55 %55 %55 %56
+ OpBranch %100
+ %102 = OpLabel
+ OpBranch %100
+ %100 = OpLabel
+ %200 = OpVectorShuffle %7 %12 %112 1 0
+ %201 = OpVectorShuffle %13 %20 %12 0xFFFFFFFF 3 5
+ %202 = OpVectorShuffle %28 %27 %35 5 4 1
+ %203 = OpVectorShuffle %37 %42 %46 0 1
+ %204 = OpVectorShuffle %43 %42 %46 2 3 4
+ %205 = OpVectorShuffle %47 %42 %42 0 1 2 3
+ %206 = OpVectorShuffle %62 %65 %65 0xFFFFFFFF 3 6 0xFFFFFFFF
+ OpReturn
+ OpFunctionEnd
+ )";
+ ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationVectorShuffleTest, IllegalInsertionPoints) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %51 %27
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %25 "buf"
+ OpMemberName %25 0 "value"
+ OpName %27 ""
+ OpName %51 "color"
+ OpMemberDecorate %25 0 Offset 0
+ OpDecorate %25 Block
+ OpDecorate %27 DescriptorSet 0
+ OpDecorate %27 Binding 0
+ OpDecorate %51 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 4
+ %150 = OpTypeVector %6 2
+ %10 = OpConstant %6 0.300000012
+ %11 = OpConstant %6 0.400000006
+ %12 = OpConstant %6 0.5
+ %13 = OpConstant %6 1
+ %14 = OpConstantComposite %7 %10 %11 %12 %13
+ %15 = OpTypeInt 32 1
+ %18 = OpConstant %15 0
+ %25 = OpTypeStruct %6
+ %26 = OpTypePointer Uniform %25
+ %27 = OpVariable %26 Uniform
+ %28 = OpTypePointer Uniform %6
+ %32 = OpTypeBool
+ %103 = OpConstantTrue %32
+ %34 = OpConstant %6 0.100000001
+ %48 = OpConstant %15 1
+ %50 = OpTypePointer Output %7
+ %51 = OpVariable %50 Output
+ %100 = OpTypePointer Function %6
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %101 = OpVariable %100 Function
+ %102 = OpVariable %100 Function
+ OpBranch %19
+ %19 = OpLabel
+ %60 = OpPhi %7 %14 %5 %58 %20
+ %59 = OpPhi %15 %18 %5 %49 %20
+ %29 = OpAccessChain %28 %27 %18
+ %30 = OpLoad %6 %29
+ %31 = OpConvertFToS %15 %30
+ %33 = OpSLessThan %32 %59 %31
+ OpLoopMerge %21 %20 None
+ OpBranchConditional %33 %20 %21
+ %20 = OpLabel
+ %39 = OpCompositeExtract %6 %60 0
+ %40 = OpFAdd %6 %39 %34
+ %55 = OpCompositeInsert %7 %40 %60 0
+ %44 = OpCompositeExtract %6 %60 1
+ %45 = OpFSub %6 %44 %34
+ %58 = OpCompositeInsert %7 %45 %55 1
+ %49 = OpIAdd %15 %59 %48
+ OpBranch %19
+ %21 = OpLabel
+ OpStore %51 %60
+ OpSelectionMerge %105 None
+ OpBranchConditional %103 %104 %105
+ %104 = OpLabel
+ OpBranch %105
+ %105 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_4;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager fact_manager;
+
+ // Cannot insert before the OpVariables of a function.
+ ASSERT_FALSE(
+ TransformationVectorShuffle(
+ MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, 14, {0, 1})
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationVectorShuffle(
+ MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, 14, {1, 2})
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationVectorShuffle(
+ MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, 14, {1, 2})
+ .IsApplicable(context.get(), fact_manager));
+ // OK to insert right after the OpVariables.
+ ASSERT_FALSE(
+ TransformationVectorShuffle(
+ MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, 14, {1, 1})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Cannot insert before the OpPhis of a block.
+ ASSERT_FALSE(
+ TransformationVectorShuffle(MakeInstructionDescriptor(60, SpvOpPhi, 0),
+ 200, 14, 14, {2, 0})
+ .IsApplicable(context.get(), fact_manager));
+ ASSERT_FALSE(
+ TransformationVectorShuffle(MakeInstructionDescriptor(59, SpvOpPhi, 0),
+ 200, 14, 14, {3, 0})
+ .IsApplicable(context.get(), fact_manager));
+ // OK to insert after the OpPhis.
+ ASSERT_TRUE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14,
+ 14, {3, 4})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Cannot insert before OpLoopMerge
+ ASSERT_FALSE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(33, SpvOpBranchConditional, 0),
+ 200, 14, 14, {3})
+ .IsApplicable(context.get(), fact_manager));
+
+ // Cannot insert before OpSelectionMerge
+ ASSERT_FALSE(TransformationVectorShuffle(
+ MakeInstructionDescriptor(21, SpvOpBranchConditional, 0),
+ 200, 14, 14, {2})
+ .IsApplicable(context.get(), fact_manager));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/test/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn
index c565e11..be1258a 100644
--- a/test/fuzzers/BUILD.gn
+++ b/test/fuzzers/BUILD.gn
@@ -33,7 +33,9 @@
testonly = true
deps = [
+ ":spvtools_as_fuzzer",
":spvtools_binary_parser_fuzzer",
+ ":spvtools_dis_fuzzer",
":spvtools_opt_legalization_fuzzer",
":spvtools_opt_performance_fuzzer",
":spvtools_opt_size_fuzzer",
@@ -66,12 +68,24 @@
}
}
+spvtools_fuzzer("spvtools_as_fuzzer_src") {
+ sources = [
+ "spvtools_as_fuzzer.cpp",
+ ]
+}
+
spvtools_fuzzer("spvtools_binary_parser_fuzzer_src") {
sources = [
"spvtools_binary_parser_fuzzer.cpp",
]
}
+spvtools_fuzzer("spvtools_dis_fuzzer_src") {
+ sources = [
+ "spvtools_dis_fuzzer.cpp",
+ ]
+}
+
spvtools_fuzzer("spvtools_opt_performance_fuzzer_src") {
sources = [
"spvtools_opt_performance_fuzzer.cpp",
@@ -116,6 +130,15 @@
}
if (!build_with_chromium || use_fuzzing_engine) {
+ fuzzer_test("spvtools_as_fuzzer") {
+ sources = []
+ deps = [
+ ":spvtools_as_fuzzer_src",
+ ]
+ # Intentionally doesn't use the seed corpus, because it consumes
+ # part of the input as not part of the file.
+ }
+
fuzzer_test("spvtools_binary_parser_fuzzer") {
sources = []
deps = [
@@ -125,6 +148,15 @@
# part of the input as not part of the file.
}
+ fuzzer_test("spvtools_dis_fuzzer") {
+ sources = []
+ deps = [
+ ":spvtools_dis_fuzzer_src",
+ ]
+ # Intentionally doesn't use the seed corpus, because it consumes
+ # part of the input as not part of the file.
+ }
+
fuzzer_test("spvtools_opt_performance_fuzzer") {
sources = []
deps = [
diff --git a/test/fuzzers/spvtools_as_fuzzer.cpp b/test/fuzzers/spvtools_as_fuzzer.cpp
new file mode 100644
index 0000000..1b1de00
--- /dev/null
+++ b/test/fuzzers/spvtools_as_fuzzer.cpp
@@ -0,0 +1,70 @@
+// 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 <cstring> // memcpy
+#include <vector>
+
+#include "source/spirv_target_env.h"
+#include "spirv-tools/libspirv.hpp"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size < sizeof(spv_target_env) + 1) return 0;
+
+ const spv_context context =
+ spvContextCreate(*reinterpret_cast<const spv_target_env*>(data));
+ if (context == nullptr) return 0;
+
+ data += sizeof(spv_target_env);
+ size -= sizeof(spv_target_env);
+
+ std::vector<uint32_t> input;
+
+ std::vector<char> input_str;
+ size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char);
+ input_str.resize(char_count);
+ memcpy(input_str.data(), input.data(), input.size() * sizeof(uint32_t));
+
+ spv_binary binary;
+ spv_diagnostic diagnostic = nullptr;
+ spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(),
+ SPV_TEXT_TO_BINARY_OPTION_NONE, &binary,
+ &diagnostic);
+ if (diagnostic) {
+ spvDiagnosticPrint(diagnostic);
+ spvDiagnosticDestroy(diagnostic);
+ diagnostic = nullptr;
+ }
+
+ if (binary) {
+ spvBinaryDestroy(binary);
+ binary = nullptr;
+ }
+
+ spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(),
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS,
+ &binary, &diagnostic);
+ if (diagnostic) {
+ spvDiagnosticPrint(diagnostic);
+ spvDiagnosticDestroy(diagnostic);
+ diagnostic = nullptr;
+ }
+
+ if (binary) {
+ spvBinaryDestroy(binary);
+ binary = nullptr;
+ }
+
+ return 0;
+}
diff --git a/test/fuzzers/spvtools_dis_fuzzer.cpp b/test/fuzzers/spvtools_dis_fuzzer.cpp
new file mode 100644
index 0000000..ca9a52d
--- /dev/null
+++ b/test/fuzzers/spvtools_dis_fuzzer.cpp
@@ -0,0 +1,71 @@
+// 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 <cstring> // memcpy
+#include <vector>
+
+#include "source/spirv_target_env.h"
+#include "spirv-tools/libspirv.hpp"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size < sizeof(spv_target_env) + 1) return 0;
+
+ const spv_context context =
+ spvContextCreate(*reinterpret_cast<const spv_target_env*>(data));
+ if (context == nullptr) return 0;
+
+ data += sizeof(spv_target_env);
+ size -= sizeof(spv_target_env);
+
+ 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;
+ }
+
+ std::vector<char> input_str;
+ size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char);
+ input_str.resize(char_count);
+ memcpy(input_str.data(), input.data(), input.size() * sizeof(uint32_t));
+
+ spv_text text = nullptr;
+ spv_diagnostic diagnostic = nullptr;
+
+ for (uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE;
+ options <
+ (SPV_BINARY_TO_TEXT_OPTION_PRINT | SPV_BINARY_TO_TEXT_OPTION_COLOR |
+ SPV_BINARY_TO_TEXT_OPTION_INDENT |
+ SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET |
+ SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
+ SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
+ options++) {
+ spvBinaryToText(context, input.data(), input.size(), options, &text,
+ &diagnostic);
+ if (diagnostic) {
+ spvDiagnosticDestroy(diagnostic);
+ diagnostic = nullptr;
+ }
+
+ if (text) {
+ spvTextDestroy(text);
+ text = nullptr;
+ }
+ }
+
+ spvContextDestroy(context);
+ return 0;
+}
diff --git a/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp b/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp
index 0b2ecc3..9371c0d 100644
--- a/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp
+++ b/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp
@@ -18,7 +18,7 @@
#include "spirv-tools/optimizer.hpp"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0);
+ spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1);
optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
const spv_position_t&, const char*) {});
diff --git a/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp b/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp
index 1e44857..78ddbb7 100644
--- a/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp
+++ b/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp
@@ -18,7 +18,7 @@
#include "spirv-tools/optimizer.hpp"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1);
+ spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0);
optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
const spv_position_t&, const char*) {});
diff --git a/test/operand_capabilities_test.cpp b/test/operand_capabilities_test.cpp
index 5b06527..1195597 100644
--- a/test/operand_capabilities_test.cpp
+++ b/test/operand_capabilities_test.cpp
@@ -494,8 +494,8 @@
CASE3(BUILT_IN, BuiltInPrimitiveId, Geometry, Tessellation,
RayTracingNV),
CASE2(BUILT_IN, BuiltInInvocationId, Geometry, Tessellation),
- CASE1(BUILT_IN, BuiltInLayer, Geometry),
- CASE1(BUILT_IN, BuiltInViewportIndex, MultiViewport), // Bug 15234
+ CASE2(BUILT_IN, BuiltInLayer, Geometry, ShaderViewportIndexLayerEXT),
+ CASE2(BUILT_IN, BuiltInViewportIndex, MultiViewport, ShaderViewportIndexLayerEXT), // Bug 15234
CASE1(BUILT_IN, BuiltInTessLevelOuter, Tessellation),
CASE1(BUILT_IN, BuiltInTessLevelInner, Tessellation),
CASE1(BUILT_IN, BuiltInTessCoord, Tessellation),
@@ -532,6 +532,18 @@
// clang-format on
})));
+INSTANTIATE_TEST_SUITE_P(
+ BuiltInV1_5, EnumCapabilityTest,
+ Combine(
+ Values(SPV_ENV_UNIVERSAL_1_5),
+ ValuesIn(std::vector<EnumCapabilityCase>{
+ // SPIR-V 1.5 adds new capabilities to enable these two builtins.
+ CASE3(BUILT_IN, BuiltInLayer, Geometry, ShaderLayer,
+ ShaderViewportIndexLayerEXT),
+ CASE3(BUILT_IN, BuiltInViewportIndex, MultiViewport,
+ ShaderViewportIndex, ShaderViewportIndexLayerEXT),
+ })));
+
// See SPIR-V Section 3.22 Selection Control
INSTANTIATE_TEST_SUITE_P(
SelectionControl, EnumCapabilityTest,
diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt
index 47ce41f..327f265 100644
--- a/test/opt/CMakeLists.txt
+++ b/test/opt/CMakeLists.txt
@@ -28,6 +28,7 @@
compact_ids_test.cpp
constants_test.cpp
constant_manager_test.cpp
+ convert_relaxed_to_half_test.cpp
copy_prop_array_test.cpp
dead_branch_elim_test.cpp
dead_insert_elim_test.cpp
@@ -80,6 +81,7 @@
reduce_load_size_test.cpp
redundancy_elimination_test.cpp
register_liveness.cpp
+ relax_float_ops_test.cpp
replace_invalid_opc_test.cpp
scalar_analysis.cpp
scalar_replacement_test.cpp
diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp
index 3a7fc27..9e5197d 100644
--- a/test/opt/aggressive_dead_code_elim_test.cpp
+++ b/test/opt/aggressive_dead_code_elim_test.cpp
@@ -6645,11 +6645,11 @@
const std::string predefs1 =
R"(OpCapability Shader
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpExtension "SPV_EXT_physical_storage_buffer"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 450
@@ -6668,7 +6668,7 @@
OpMemberDecorate %blockType 0 Offset 0
OpMemberDecorate %blockType 1 Offset 8
OpDecorate %blockType Block
-OpDecorate %b AliasedPointerEXT
+OpDecorate %b AliasedPointer
OpMemberDecorate %rootBlock 0 Offset 0
OpDecorate %rootBlock Block
OpDecorate %r DescriptorSet 0
@@ -6695,50 +6695,50 @@
const std::string predefs2_before =
R"(%void = OpTypeVoid
%3 = OpTypeFunction %void
-OpTypeForwardPointer %_ptr_PhysicalStorageBufferEXT_blockType PhysicalStorageBufferEXT
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer
%int = OpTypeInt 32 1
-%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBufferEXT_blockType
-%_ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer PhysicalStorageBufferEXT %blockType
-%_ptr_Function__ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer Function %_ptr_PhysicalStorageBufferEXT_blockType
-%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBufferEXT_blockType
+%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType
+%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType
+%_ptr_Function__ptr_PhysicalStorageBuffer_blockType = OpTypePointer Function %_ptr_PhysicalStorageBuffer_blockType
+%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType
%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock
%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer
%int_0 = OpConstant %int 0
-%_ptr_StorageBuffer__ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBufferEXT_blockType
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType
%int_1 = OpConstant %int 1
-%_ptr_PhysicalStorageBufferEXT__ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer PhysicalStorageBufferEXT %_ptr_PhysicalStorageBufferEXT_blockType
+%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
%int_531 = OpConstant %int 531
-%_ptr_PhysicalStorageBufferEXT_int = OpTypePointer PhysicalStorageBufferEXT %int
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
)";
const std::string predefs2_after =
R"(%void = OpTypeVoid
%8 = OpTypeFunction %void
-OpTypeForwardPointer %_ptr_PhysicalStorageBufferEXT_blockType PhysicalStorageBufferEXT
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer
%int = OpTypeInt 32 1
-%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBufferEXT_blockType
-%_ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer PhysicalStorageBufferEXT %blockType
-%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBufferEXT_blockType
+%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType
+%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType
+%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType
%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock
%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer
%int_0 = OpConstant %int 0
-%_ptr_StorageBuffer__ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBufferEXT_blockType
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType
%int_1 = OpConstant %int 1
-%_ptr_PhysicalStorageBufferEXT__ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer PhysicalStorageBufferEXT %_ptr_PhysicalStorageBufferEXT_blockType
+%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
%int_531 = OpConstant %int 531
-%_ptr_PhysicalStorageBufferEXT_int = OpTypePointer PhysicalStorageBufferEXT %int
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
)";
const std::string func_before =
R"(%main = OpFunction %void None %3
%5 = OpLabel
-%b = OpVariable %_ptr_Function__ptr_PhysicalStorageBufferEXT_blockType Function
-%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBufferEXT_blockType %r %int_0
-%17 = OpLoad %_ptr_PhysicalStorageBufferEXT_blockType %16
-%21 = OpAccessChain %_ptr_PhysicalStorageBufferEXT__ptr_PhysicalStorageBufferEXT_blockType %17 %int_1
-%22 = OpLoad %_ptr_PhysicalStorageBufferEXT_blockType %21 Aligned 8
+%b = OpVariable %_ptr_Function__ptr_PhysicalStorageBuffer_blockType Function
+%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0
+%17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16
+%21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1
+%22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
OpStore %b %22
-%26 = OpAccessChain %_ptr_PhysicalStorageBufferEXT_int %22 %int_0
+%26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
OpStore %26 %int_531 Aligned 16
OpReturn
OpFunctionEnd
@@ -6747,11 +6747,11 @@
const std::string func_after =
R"(%main = OpFunction %void None %8
%19 = OpLabel
-%20 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBufferEXT_blockType %r %int_0
-%21 = OpLoad %_ptr_PhysicalStorageBufferEXT_blockType %20
-%22 = OpAccessChain %_ptr_PhysicalStorageBufferEXT__ptr_PhysicalStorageBufferEXT_blockType %21 %int_1
-%23 = OpLoad %_ptr_PhysicalStorageBufferEXT_blockType %22 Aligned 8
-%24 = OpAccessChain %_ptr_PhysicalStorageBufferEXT_int %23 %int_0
+%20 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0
+%21 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %20
+%22 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %21 %int_1
+%23 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %22 Aligned 8
+%24 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %23 %int_0
OpStore %24 %int_531 Aligned 16
OpReturn
OpFunctionEnd
diff --git a/test/opt/amd_ext_to_khr.cpp b/test/opt/amd_ext_to_khr.cpp
index 7a6d4b4..d943d34 100644
--- a/test/opt/amd_ext_to_khr.cpp
+++ b/test/opt/amd_ext_to_khr.cpp
@@ -233,6 +233,7 @@
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
}
+
TEST_F(AmdExtToKhrTest, ReplaceWriteInvocationAMD) {
const std::string text = R"(
; CHECK: OpCapability Shader
@@ -269,6 +270,585 @@
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
}
+TEST_F(AmdExtToKhrTest, ReplaceFMin3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeFloat 32
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] FMin [[x]] [[y]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] FMin [[temp]] [[z]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %float
+ %8 = OpUndef %float
+ %9 = OpUndef %float
+ %10 = OpExtInst %float %ext FMin3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceSMin3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeInt 32 1
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] SMin [[x]] [[y]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] SMin [[temp]] [[z]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %int
+ %8 = OpUndef %int
+ %9 = OpUndef %int
+ %10 = OpExtInst %int %ext SMin3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceUMin3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeInt 32 0
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[x]] [[y]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[temp]] [[z]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %uint
+ %8 = OpUndef %uint
+ %9 = OpUndef %uint
+ %10 = OpExtInst %uint %ext UMin3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceFMax3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeFloat 32
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] FMax [[x]] [[y]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] FMax [[temp]] [[z]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %float
+ %8 = OpUndef %float
+ %9 = OpUndef %float
+ %10 = OpExtInst %float %ext FMax3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceSMax3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeInt 32 1
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] SMax [[x]] [[y]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] SMax [[temp]] [[z]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %int
+ %8 = OpUndef %int
+ %9 = OpUndef %int
+ %10 = OpExtInst %int %ext SMax3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceUMax3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeInt 32 0
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[x]] [[y]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[temp]] [[z]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %uint
+ %8 = OpUndef %uint
+ %9 = OpUndef %uint
+ %10 = OpExtInst %uint %ext UMax3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceVecUMax3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeVector
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[x]] [[y]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[temp]] [[z]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %vec = OpTypeVector %uint 4
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %vec
+ %8 = OpUndef %vec
+ %9 = OpUndef %vec
+ %10 = OpExtInst %vec %ext UMax3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceFMid3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeFloat 32
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] FMin [[y]] [[z]]
+; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] FMax [[y]] [[z]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] FClamp [[x]] [[min]] [[max]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %float
+ %8 = OpUndef %float
+ %9 = OpUndef %float
+ %10 = OpExtInst %float %ext FMid3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceSMid3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeInt 32 1
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] SMin [[y]] [[z]]
+; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] SMax [[y]] [[z]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] SClamp [[x]] [[min]] [[max]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %int
+ %8 = OpUndef %int
+ %9 = OpUndef %int
+ %10 = OpExtInst %int %ext SMid3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceUMid3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeInt 32 0
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[y]] [[z]]
+; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[y]] [[z]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UClamp [[x]] [[min]] [[max]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %uint
+ %8 = OpUndef %uint
+ %9 = OpUndef %uint
+ %10 = OpExtInst %uint %ext UMid3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceVecUMid3AMD) {
+ const std::string text = R"(
+; CHECK: OpCapability Shader
+; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
+; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
+; CHECK: [[type:%\w+]] = OpTypeVector
+; CHECK: OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
+; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[y]] [[z]]
+; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[y]] [[z]]
+; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UClamp [[x]] [[min]] [[max]]
+ OpCapability Shader
+ OpExtension "SPV_AMD_shader_trinary_minmax"
+ %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "func"
+ OpExecutionMode %1 OriginUpperLeft
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %vec = OpTypeVector %uint 3
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %uint_3 = OpConstant %uint 3
+ %1 = OpFunction %void None %3
+ %6 = OpLabel
+ %7 = OpUndef %vec
+ %8 = OpUndef %vec
+ %9 = OpUndef %vec
+ %10 = OpExtInst %vec %ext UMid3AMD %7 %8 %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceCubeFaceCoordAMD) {
+ // Sorry for the Check test. The code sequence is so long, I do not think
+ // that a match test would be anymore legible. This tests the replacement of
+ // the CubeFaceCoordAMD instruction.
+ const std::string before = R"(
+ OpCapability Shader
+ OpExtension "SPV_KHR_storage_buffer_storage_class"
+ OpExtension "SPV_AMD_gcn_shader"
+ %1 = OpExtInstImport "SPV_AMD_gcn_shader"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %2 "main"
+ OpExecutionMode %2 LocalSize 1 1 1
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+ %v3float = OpTypeVector %float 3
+ %2 = OpFunction %void None %4
+ %8 = OpLabel
+ %9 = OpUndef %v3float
+ %10 = OpExtInst %v2float %1 CubeFaceCoordAMD %9
+ OpReturn
+ OpFunctionEnd
+)";
+
+ const std::string after = R"(OpCapability Shader
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+%12 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %2 "main"
+OpExecutionMode %2 LocalSize 1 1 1
+%void = OpTypeVoid
+%4 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v2float = OpTypeVector %float 2
+%v3float = OpTypeVector %float 3
+%bool = OpTypeBool
+%float_0 = OpConstant %float 0
+%float_2 = OpConstant %float 2
+%float_0_5 = OpConstant %float 0.5
+%16 = OpConstantComposite %v2float %float_0_5 %float_0_5
+%2 = OpFunction %void None %4
+%8 = OpLabel
+%9 = OpUndef %v3float
+%17 = OpCompositeExtract %float %9 0
+%18 = OpCompositeExtract %float %9 1
+%19 = OpCompositeExtract %float %9 2
+%20 = OpFNegate %float %17
+%21 = OpFNegate %float %18
+%22 = OpFNegate %float %19
+%23 = OpExtInst %float %12 FAbs %17
+%24 = OpExtInst %float %12 FAbs %18
+%25 = OpExtInst %float %12 FAbs %19
+%26 = OpFOrdLessThan %bool %19 %float_0
+%27 = OpFOrdLessThan %bool %18 %float_0
+%28 = OpFOrdLessThan %bool %17 %float_0
+%29 = OpExtInst %float %12 FMax %23 %24
+%30 = OpExtInst %float %12 FMax %25 %29
+%31 = OpFMul %float %float_2 %30
+%32 = OpFOrdGreaterThanEqual %bool %25 %29
+%33 = OpLogicalNot %bool %32
+%34 = OpFOrdGreaterThanEqual %bool %24 %23
+%35 = OpLogicalAnd %bool %33 %34
+%36 = OpSelect %float %26 %20 %17
+%37 = OpSelect %float %28 %19 %22
+%38 = OpSelect %float %35 %17 %37
+%39 = OpSelect %float %32 %36 %38
+%40 = OpSelect %float %27 %22 %19
+%41 = OpSelect %float %35 %40 %21
+%42 = OpCompositeConstruct %v2float %39 %41
+%43 = OpCompositeConstruct %v2float %31 %31
+%44 = OpFDiv %v2float %42 %43
+%10 = OpFAdd %v2float %44 %16
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndCheck<AmdExtensionToKhrPass>(before, after, true);
+}
+
+TEST_F(AmdExtToKhrTest, ReplaceCubeFaceIndexAMD) {
+ // Sorry for the Check test. The code sequence is so long, I do not think
+ // that a match test would be anymore legible. This tests the replacement of
+ // the CubeFaceIndexAMD instruction.
+ const std::string before = R"(OpCapability Shader
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpExtension "SPV_AMD_gcn_shader"
+%1 = OpExtInstImport "SPV_AMD_gcn_shader"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %2 "main"
+OpExecutionMode %2 LocalSize 1 1 1
+%void = OpTypeVoid
+%4 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v3float = OpTypeVector %float 3
+%2 = OpFunction %void None %4
+%7 = OpLabel
+%8 = OpUndef %v3float
+%9 = OpExtInst %float %1 CubeFaceIndexAMD %8
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string after = R"(OpCapability Shader
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+%11 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %2 "main"
+OpExecutionMode %2 LocalSize 1 1 1
+%void = OpTypeVoid
+%4 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v3float = OpTypeVector %float 3
+%bool = OpTypeBool
+%float_0 = OpConstant %float 0
+%float_1 = OpConstant %float 1
+%float_2 = OpConstant %float 2
+%float_3 = OpConstant %float 3
+%float_4 = OpConstant %float 4
+%float_5 = OpConstant %float 5
+%2 = OpFunction %void None %4
+%7 = OpLabel
+%8 = OpUndef %v3float
+%18 = OpCompositeExtract %float %8 0
+%19 = OpCompositeExtract %float %8 1
+%20 = OpCompositeExtract %float %8 2
+%21 = OpExtInst %float %11 FAbs %18
+%22 = OpExtInst %float %11 FAbs %19
+%23 = OpExtInst %float %11 FAbs %20
+%24 = OpFOrdLessThan %bool %20 %float_0
+%25 = OpFOrdLessThan %bool %19 %float_0
+%26 = OpFOrdLessThan %bool %18 %float_0
+%27 = OpExtInst %float %11 FMax %21 %22
+%28 = OpFOrdGreaterThanEqual %bool %23 %27
+%29 = OpFOrdGreaterThanEqual %bool %22 %21
+%30 = OpSelect %float %24 %float_5 %float_4
+%31 = OpSelect %float %25 %float_3 %float_2
+%32 = OpSelect %float %26 %float_1 %float_0
+%33 = OpSelect %float %29 %31 %32
+%9 = OpSelect %float %28 %30 %33
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndCheck<AmdExtensionToKhrPass>(before, after, true);
+}
+
TEST_F(AmdExtToKhrTest, SetVersion) {
const std::string text = R"(
OpCapability Shader
diff --git a/test/opt/ccp_test.cpp b/test/opt/ccp_test.cpp
index 2ee7cce..920c0f4 100644
--- a/test/opt/ccp_test.cpp
+++ b/test/opt/ccp_test.cpp
@@ -570,10 +570,10 @@
%10 = OpSpecConstantFalse %bool
%main = OpFunction %void None %4
%11 = OpLabel
- %12 = OpBranchConditional %10 %l1 %l2
- %l1 = OpLabel
+ OpBranchConditional %10 %L1 %L2
+ %L1 = OpLabel
OpReturn
- %l2 = OpLabel
+ %L2 = OpLabel
OpReturn
OpFunctionEnd
)";
diff --git a/test/opt/constant_manager_test.cpp b/test/opt/constant_manager_test.cpp
index 57dea65..14e14ec 100644
--- a/test/opt/constant_manager_test.cpp
+++ b/test/opt/constant_manager_test.cpp
@@ -82,6 +82,28 @@
EXPECT_EQ(const_inst_2->result_id(), 4);
}
+TEST_F(ConstantManagerTest, GetDefiningInstructionIdOverflow) {
+ const std::string text = R"(
+%1 = OpTypeInt 32 0
+%3 = OpConstant %1 1
+%4 = OpConstant %1 2
+ )";
+
+ std::unique_ptr<IRContext> context =
+ BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ ASSERT_NE(context, nullptr);
+
+ // Set the id bound to the max, so the new constant cannot be generated.
+ context->module()->SetIdBound(context->max_id_bound());
+
+ Type* int_type = context->get_type_mgr()->GetType(1);
+ IntConstant int_constant(int_type->AsInteger(), {3});
+ Instruction* inst =
+ context->get_constant_mgr()->GetDefiningInstruction(&int_constant, 1);
+ EXPECT_EQ(inst, nullptr);
+}
+
} // namespace
} // namespace analysis
} // namespace opt
diff --git a/test/opt/convert_relaxed_to_half_test.cpp b/test/opt/convert_relaxed_to_half_test.cpp
new file mode 100644
index 0000000..3ac8009
--- /dev/null
+++ b/test/opt/convert_relaxed_to_half_test.cpp
@@ -0,0 +1,1227 @@
+// Copyright (c) 2019 Valve Corporation
+// Copyright (c) 2019 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Convert Relaxed to Half tests
+
+#include <string>
+#include <vector>
+
+#include "test/opt/assembly_builder.h"
+#include "test/opt/pass_fixture.h"
+#include "test/opt/pass_utils.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+using ConvertToHalfTest = PassTest<::testing::Test>;
+
+TEST_F(ConvertToHalfTest, ConvertToHalfBasic) {
+ // The resulting SPIR-V was processed with --relax-float-ops.
+ //
+ // clang-format off
+ //
+ // SamplerState g_sSamp : register(s0);
+ // uniform Texture1D <float4> g_tTex1df4 : register(t0);
+ //
+ // struct PS_INPUT
+ // {
+ // float Tex0 : TEXCOORD0;
+ // };
+ //
+ // struct PS_OUTPUT
+ // {
+ // float4 Color : SV_Target0;
+ // };
+ //
+ // cbuffer cbuff{
+ // float c;
+ // }
+ //
+ // PS_OUTPUT main(PS_INPUT i)
+ // {
+ // PS_OUTPUT psout;
+ // psout.Color = g_tTex1df4.Sample(g_sSamp, i.Tex0) * c;
+ // return psout;
+ // }
+ //
+ // clang-format on
+
+ const std::string defs_before =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "c"
+OpName %_ ""
+OpName %i_Tex0 "i.Tex0"
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpMemberDecorate %cbuff 0 Offset 0
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %i_Tex0 Location 0
+OpDecorate %_entryPointOutput_Color Location 0
+OpDecorate %48 RelaxedPrecision
+OpDecorate %63 RelaxedPrecision
+OpDecorate %65 RelaxedPrecision
+OpDecorate %66 RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%19 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+%23 = OpTypeSampler
+%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23
+%g_sSamp = OpVariable %_ptr_UniformConstant_23 UniformConstant
+%27 = OpTypeSampledImage %19
+%cbuff = OpTypeStruct %float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%_ptr_Input_float = OpTypePointer Input %float
+%i_Tex0 = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+)";
+
+ const std::string defs_after =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+OpCapability Float16
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "c"
+OpName %_ ""
+OpName %i_Tex0 "i.Tex0"
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpMemberDecorate %cbuff 0 Offset 0
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %i_Tex0 Location 0
+OpDecorate %_entryPointOutput_Color Location 0
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%19 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+%23 = OpTypeSampler
+%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23
+%g_sSamp = OpVariable %_ptr_UniformConstant_23 UniformConstant
+%27 = OpTypeSampledImage %19
+%cbuff = OpTypeStruct %float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%_ptr_Input_float = OpTypePointer Input %float
+%i_Tex0 = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+%half = OpTypeFloat 16
+%v4half = OpTypeVector %half 4
+)";
+
+ const std::string func_before =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%48 = OpLoad %float %i_Tex0
+%58 = OpLoad %19 %g_tTex1df4
+%59 = OpLoad %23 %g_sSamp
+%60 = OpSampledImage %27 %58 %59
+%63 = OpImageSampleImplicitLod %v4float %60 %48
+%64 = OpAccessChain %_ptr_Uniform_float %_ %int_0
+%65 = OpLoad %float %64
+%66 = OpVectorTimesScalar %v4float %63 %65
+OpStore %_entryPointOutput_Color %66
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string func_after =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%48 = OpLoad %float %i_Tex0
+%58 = OpLoad %19 %g_tTex1df4
+%59 = OpLoad %23 %g_sSamp
+%60 = OpSampledImage %27 %58 %59
+%63 = OpImageSampleImplicitLod %v4float %60 %48
+%64 = OpAccessChain %_ptr_Uniform_float %_ %int_0
+%65 = OpLoad %float %64
+%69 = OpFConvert %v4half %63
+%70 = OpFConvert %half %65
+%66 = OpVectorTimesScalar %v4half %69 %70
+%71 = OpFConvert %v4float %66
+OpStore %_entryPointOutput_Color %71
+OpReturn
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
+ defs_after + func_after, true, true);
+}
+
+TEST_F(ConvertToHalfTest, ConvertToHalfWithDrefSample) {
+ // The resulting SPIR-V was processed with --relax-float-ops.
+ //
+ // clang-format off
+ //
+ // SamplerComparisonState g_sSamp : register(s0);
+ // uniform Texture1D <float4> g_tTex1df4 : register(t0);
+ //
+ // cbuffer cbuff{
+ // float c1;
+ // float c2;
+ // };
+ //
+ // struct PS_INPUT
+ // {
+ // float Tex0 : TEXCOORD0;
+ // float Tex1 : TEXCOORD1;
+ // };
+ //
+ // struct PS_OUTPUT
+ // {
+ // float Color : SV_Target0;
+ // };
+ //
+ // PS_OUTPUT main(PS_INPUT i)
+ // {
+ // PS_OUTPUT psout;
+ // float txval10 = g_tTex1df4.SampleCmp(g_sSamp, i.Tex0 * 0.1, c1 + 0.1);
+ // float txval11 = g_tTex1df4.SampleCmp(g_sSamp, i.Tex1 * 0.2, c2 + 0.2);
+ // float t = txval10 + txval11;
+ // float t2 = t / 2.0;
+ // psout.Color = t2;
+ // return psout;
+ // }
+ //
+ // clang-format on
+
+ const std::string defs_before =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %i_Tex0 %i_Tex1 %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "c1"
+OpMemberName %cbuff 1 "c2"
+OpName %_ ""
+OpName %i_Tex0 "i.Tex0"
+OpName %i_Tex1 "i.Tex1"
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpMemberDecorate %cbuff 0 Offset 0
+OpMemberDecorate %cbuff 1 Offset 4
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %i_Tex0 Location 0
+OpDecorate %i_Tex1 Location 1
+OpDecorate %_entryPointOutput_Color Location 0
+OpDecorate %100 RelaxedPrecision
+OpDecorate %76 RelaxedPrecision
+OpDecorate %79 RelaxedPrecision
+OpDecorate %98 RelaxedPrecision
+OpDecorate %101 RelaxedPrecision
+OpDecorate %110 RelaxedPrecision
+OpDecorate %102 RelaxedPrecision
+OpDecorate %112 RelaxedPrecision
+OpDecorate %104 RelaxedPrecision
+OpDecorate %113 RelaxedPrecision
+OpDecorate %114 RelaxedPrecision
+OpDecorate %116 RelaxedPrecision
+OpDecorate %119 RelaxedPrecision
+OpDecorate %121 RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%16 = OpTypeImage %float 1D 1 0 0 1 Unknown
+%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_16 UniformConstant
+%20 = OpTypeSampler
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+%g_sSamp = OpVariable %_ptr_UniformConstant_20 UniformConstant
+%24 = OpTypeSampledImage %16
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%float_0_100000001 = OpConstant %float 0.100000001
+%cbuff = OpTypeStruct %float %float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%v2float = OpTypeVector %float 2
+%int_1 = OpConstant %int 1
+%float_0_200000003 = OpConstant %float 0.200000003
+%_ptr_Input_float = OpTypePointer Input %float
+%i_Tex0 = OpVariable %_ptr_Input_float Input
+%i_Tex1 = OpVariable %_ptr_Input_float Input
+%_ptr_Output_float = OpTypePointer Output %float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_float Output
+%float_0_5 = OpConstant %float 0.5
+)";
+
+ const std::string defs_after =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+OpCapability Float16
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %i_Tex0 %i_Tex1 %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "c1"
+OpMemberName %cbuff 1 "c2"
+OpName %_ ""
+OpName %i_Tex0 "i.Tex0"
+OpName %i_Tex1 "i.Tex1"
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpMemberDecorate %cbuff 0 Offset 0
+OpMemberDecorate %cbuff 1 Offset 4
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %i_Tex0 Location 0
+OpDecorate %i_Tex1 Location 1
+OpDecorate %_entryPointOutput_Color Location 0
+%void = OpTypeVoid
+%25 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%27 = OpTypeImage %float 1D 1 0 0 1 Unknown
+%_ptr_UniformConstant_27 = OpTypePointer UniformConstant %27
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_27 UniformConstant
+%29 = OpTypeSampler
+%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
+%g_sSamp = OpVariable %_ptr_UniformConstant_29 UniformConstant
+%31 = OpTypeSampledImage %27
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%float_0_100000001 = OpConstant %float 0.100000001
+%cbuff = OpTypeStruct %float %float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%v2float = OpTypeVector %float 2
+%int_1 = OpConstant %int 1
+%float_0_200000003 = OpConstant %float 0.200000003
+%_ptr_Input_float = OpTypePointer Input %float
+%i_Tex0 = OpVariable %_ptr_Input_float Input
+%i_Tex1 = OpVariable %_ptr_Input_float Input
+%_ptr_Output_float = OpTypePointer Output %float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_float Output
+%float_0_5 = OpConstant %float 0.5
+%half = OpTypeFloat 16
+%v2half = OpTypeVector %half 2
+)";
+
+ const std::string func_before =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%76 = OpLoad %float %i_Tex0
+%79 = OpLoad %float %i_Tex1
+%93 = OpLoad %16 %g_tTex1df4
+%94 = OpLoad %20 %g_sSamp
+%95 = OpSampledImage %24 %93 %94
+%98 = OpFMul %float %76 %float_0_100000001
+%99 = OpAccessChain %_ptr_Uniform_float %_ %int_0
+%100 = OpLoad %float %99
+%101 = OpFAdd %float %100 %float_0_100000001
+%102 = OpCompositeConstruct %v2float %98 %101
+%104 = OpImageSampleDrefImplicitLod %float %95 %102 %101
+%105 = OpLoad %16 %g_tTex1df4
+%106 = OpLoad %20 %g_sSamp
+%107 = OpSampledImage %24 %105 %106
+%110 = OpFMul %float %79 %float_0_200000003
+%111 = OpAccessChain %_ptr_Uniform_float %_ %int_1
+%112 = OpLoad %float %111
+%113 = OpFAdd %float %112 %float_0_200000003
+%114 = OpCompositeConstruct %v2float %110 %113
+%116 = OpImageSampleDrefImplicitLod %float %107 %114 %113
+%119 = OpFAdd %float %104 %116
+%121 = OpFMul %float %119 %float_0_5
+OpStore %_entryPointOutput_Color %121
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string func_after =
+ R"(%main = OpFunction %void None %25
+%43 = OpLabel
+%11 = OpLoad %float %i_Tex0
+%12 = OpLoad %float %i_Tex1
+%44 = OpLoad %27 %g_tTex1df4
+%45 = OpLoad %29 %g_sSamp
+%46 = OpSampledImage %31 %44 %45
+%53 = OpFConvert %half %11
+%54 = OpFConvert %half %float_0_100000001
+%13 = OpFMul %half %53 %54
+%47 = OpAccessChain %_ptr_Uniform_float %_ %int_0
+%10 = OpLoad %float %47
+%55 = OpFConvert %half %10
+%56 = OpFConvert %half %float_0_100000001
+%14 = OpFAdd %half %55 %56
+%16 = OpCompositeConstruct %v2half %13 %14
+%58 = OpFConvert %float %14
+%18 = OpImageSampleDrefImplicitLod %float %46 %16 %58
+%48 = OpLoad %27 %g_tTex1df4
+%49 = OpLoad %29 %g_sSamp
+%50 = OpSampledImage %31 %48 %49
+%59 = OpFConvert %half %12
+%60 = OpFConvert %half %float_0_200000003
+%15 = OpFMul %half %59 %60
+%51 = OpAccessChain %_ptr_Uniform_float %_ %int_1
+%17 = OpLoad %float %51
+%61 = OpFConvert %half %17
+%62 = OpFConvert %half %float_0_200000003
+%19 = OpFAdd %half %61 %62
+%20 = OpCompositeConstruct %v2half %15 %19
+%63 = OpFConvert %float %19
+%21 = OpImageSampleDrefImplicitLod %float %50 %20 %63
+%64 = OpFConvert %half %18
+%65 = OpFConvert %half %21
+%22 = OpFAdd %half %64 %65
+%66 = OpFConvert %half %float_0_5
+%23 = OpFMul %half %22 %66
+%67 = OpFConvert %float %23
+OpStore %_entryPointOutput_Color %67
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
+ defs_after + func_after, true, true);
+}
+
+TEST_F(ConvertToHalfTest, ConvertToHalfWithVectorMatrixMult) {
+ // The resulting SPIR-V was processed with --relax-float-ops.
+ //
+ // clang-format off
+ //
+ // SamplerState g_sSamp : register(s0);
+ // uniform Texture1D <float4> g_tTex1df4 : register(t0);
+ //
+ // struct PS_OUTPUT
+ // {
+ // float4 Color : SV_Target0;
+ // };
+ //
+ // cbuffer cbuff{
+ // float4x4 M;
+ // }
+ //
+ // PS_OUTPUT main()
+ // {
+ // PS_OUTPUT psout;
+ // float4 txval10 = g_tTex1df4.Sample(g_sSamp, 0.1);
+ // float4 t = mul(txval10, M);
+ // psout.Color = t;
+ // return psout;
+ //}
+ //
+ // clang-format on
+
+ const std::string defs_before =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "M"
+OpName %_ ""
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpMemberDecorate %cbuff 0 RowMajor
+OpMemberDecorate %cbuff 0 Offset 0
+OpMemberDecorate %cbuff 0 MatrixStride 16
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %_entryPointOutput_Color Location 0
+OpDecorate %56 RelaxedPrecision
+OpDecorate %58 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%14 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_14 UniformConstant
+%18 = OpTypeSampler
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+%g_sSamp = OpVariable %_ptr_UniformConstant_18 UniformConstant
+%22 = OpTypeSampledImage %14
+%float_0_100000001 = OpConstant %float 0.100000001
+%mat4v4float = OpTypeMatrix %v4float 4
+%cbuff = OpTypeStruct %mat4v4float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+)";
+
+ const std::string defs_after =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+OpCapability Float16
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "M"
+OpName %_ ""
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpMemberDecorate %cbuff 0 RowMajor
+OpMemberDecorate %cbuff 0 Offset 0
+OpMemberDecorate %cbuff 0 MatrixStride 16
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %_entryPointOutput_Color Location 0
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%14 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_14 UniformConstant
+%18 = OpTypeSampler
+%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
+%g_sSamp = OpVariable %_ptr_UniformConstant_18 UniformConstant
+%22 = OpTypeSampledImage %14
+%float_0_100000001 = OpConstant %float 0.100000001
+%mat4v4float = OpTypeMatrix %v4float 4
+%cbuff = OpTypeStruct %mat4v4float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+%half = OpTypeFloat 16
+%v4half = OpTypeVector %half 4
+%mat4v4half = OpTypeMatrix %v4half 4
+)";
+
+ const std::string func_before =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%53 = OpLoad %14 %g_tTex1df4
+%54 = OpLoad %18 %g_sSamp
+%55 = OpSampledImage %22 %53 %54
+%56 = OpImageSampleImplicitLod %v4float %55 %float_0_100000001
+%57 = OpAccessChain %_ptr_Uniform_mat4v4float %_ %int_0
+%58 = OpLoad %mat4v4float %57
+%60 = OpMatrixTimesVector %v4float %58 %56
+OpStore %_entryPointOutput_Color %60
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string func_after =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%53 = OpLoad %14 %g_tTex1df4
+%54 = OpLoad %18 %g_sSamp
+%55 = OpSampledImage %22 %53 %54
+%56 = OpImageSampleImplicitLod %v4float %55 %float_0_100000001
+%57 = OpAccessChain %_ptr_Uniform_mat4v4float %_ %int_0
+%58 = OpLoad %mat4v4float %57
+%67 = OpCompositeExtract %v4float %58 0
+%68 = OpFConvert %v4half %67
+%69 = OpCompositeExtract %v4float %58 1
+%70 = OpFConvert %v4half %69
+%71 = OpCompositeExtract %v4float %58 2
+%72 = OpFConvert %v4half %71
+%73 = OpCompositeExtract %v4float %58 3
+%74 = OpFConvert %v4half %73
+%75 = OpCompositeConstruct %mat4v4half %68 %70 %72 %74
+%64 = OpCopyObject %mat4v4float %58
+%65 = OpFConvert %v4half %56
+%60 = OpMatrixTimesVector %v4half %75 %65
+%66 = OpFConvert %v4float %60
+OpStore %_entryPointOutput_Color %66
+OpReturn
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
+ defs_after + func_after, true, true);
+}
+
+TEST_F(ConvertToHalfTest, ConvertToHalfWithPhi) {
+ // The resulting SPIR-V was processed with --relax-float-ops.
+ //
+ // clang-format off
+ //
+ // SamplerState g_sSamp : register(s0);
+ // uniform Texture1D <float4> g_tTex1df4 : register(t0);
+ //
+ // struct PS_OUTPUT
+ // {
+ // float4 Color : SV_Target0;
+ // };
+ //
+ // cbuffer cbuff{
+ // bool b;
+ // float4x4 M;
+ // }
+ //
+ // PS_OUTPUT main()
+ // {
+ // PS_OUTPUT psout;
+ // float4 t;
+ //
+ // if (b)
+ // t = g_tTex1df4.Sample(g_sSamp, 0.1);
+ // else
+ // t = float4(0.0, 0.0, 0.0, 0.0);
+ //
+ // float4 t2 = t * 2.0;
+ // psout.Color = t2;
+ // return psout;
+ // }
+ //
+ // clang-format on
+
+ const std::string defs_before =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "b"
+OpMemberName %cbuff 1 "M"
+OpName %_ ""
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpMemberDecorate %cbuff 0 Offset 0
+OpMemberDecorate %cbuff 1 RowMajor
+OpMemberDecorate %cbuff 1 Offset 16
+OpMemberDecorate %cbuff 1 MatrixStride 16
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpDecorate %_entryPointOutput_Color Location 0
+OpDecorate %72 RelaxedPrecision
+OpDecorate %85 RelaxedPrecision
+OpDecorate %74 RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%uint = OpTypeInt 32 0
+%mat4v4float = OpTypeMatrix %v4float 4
+%cbuff = OpTypeStruct %uint %mat4v4float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%bool = OpTypeBool
+%uint_0 = OpConstant %uint 0
+%29 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_29 UniformConstant
+%33 = OpTypeSampler
+%_ptr_UniformConstant_33 = OpTypePointer UniformConstant %33
+%g_sSamp = OpVariable %_ptr_UniformConstant_33 UniformConstant
+%37 = OpTypeSampledImage %29
+%float_0_100000001 = OpConstant %float 0.100000001
+%float_0 = OpConstant %float 0
+%43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%float_2 = OpConstant %float 2
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+)";
+
+ const std::string defs_after =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+OpCapability Float16
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "b"
+OpMemberName %cbuff 1 "M"
+OpName %_ ""
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpMemberDecorate %cbuff 0 Offset 0
+OpMemberDecorate %cbuff 1 RowMajor
+OpMemberDecorate %cbuff 1 Offset 16
+OpMemberDecorate %cbuff 1 MatrixStride 16
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpDecorate %_entryPointOutput_Color Location 0
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%uint = OpTypeInt 32 0
+%mat4v4float = OpTypeMatrix %v4float 4
+%cbuff = OpTypeStruct %uint %mat4v4float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%bool = OpTypeBool
+%uint_0 = OpConstant %uint 0
+%29 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_29 UniformConstant
+%33 = OpTypeSampler
+%_ptr_UniformConstant_33 = OpTypePointer UniformConstant %33
+%g_sSamp = OpVariable %_ptr_UniformConstant_33 UniformConstant
+%37 = OpTypeSampledImage %29
+%float_0_100000001 = OpConstant %float 0.100000001
+%float_0 = OpConstant %float 0
+%43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%float_2 = OpConstant %float 2
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+%half = OpTypeFloat 16
+%v4half = OpTypeVector %half 4
+)";
+
+ const std::string func_before =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%63 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
+%64 = OpLoad %uint %63
+%65 = OpINotEqual %bool %64 %uint_0
+OpSelectionMerge %66 None
+OpBranchConditional %65 %67 %68
+%67 = OpLabel
+%69 = OpLoad %29 %g_tTex1df4
+%70 = OpLoad %33 %g_sSamp
+%71 = OpSampledImage %37 %69 %70
+%72 = OpImageSampleImplicitLod %v4float %71 %float_0_100000001
+OpBranch %66
+%68 = OpLabel
+OpBranch %66
+%66 = OpLabel
+%85 = OpPhi %v4float %72 %67 %43 %68
+%74 = OpVectorTimesScalar %v4float %85 %float_2
+OpStore %_entryPointOutput_Color %74
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string func_after =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%63 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
+%64 = OpLoad %uint %63
+%65 = OpINotEqual %bool %64 %uint_0
+OpSelectionMerge %66 None
+OpBranchConditional %65 %67 %68
+%67 = OpLabel
+%69 = OpLoad %29 %g_tTex1df4
+%70 = OpLoad %33 %g_sSamp
+%71 = OpSampledImage %37 %69 %70
+%72 = OpImageSampleImplicitLod %v4float %71 %float_0_100000001
+%88 = OpFConvert %v4half %72
+OpBranch %66
+%68 = OpLabel
+%89 = OpFConvert %v4half %43
+OpBranch %66
+%66 = OpLabel
+%85 = OpPhi %v4half %88 %67 %89 %68
+%90 = OpFConvert %half %float_2
+%74 = OpVectorTimesScalar %v4half %85 %90
+%91 = OpFConvert %v4float %74
+OpStore %_entryPointOutput_Color %91
+OpReturn
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
+ defs_after + func_after, true, true);
+}
+
+TEST_F(ConvertToHalfTest, ConvertToHalfWithLoopAndFConvert) {
+ // The resulting SPIR-V was processed with --relax-float-ops.
+ //
+ // The loop causes an FConvert to be generated at the bottom of the loop
+ // for the Phi. The FConvert is later processed and turned into a (dead)
+ // copy.
+ //
+ // clang-format off
+ //
+ // struct PS_OUTPUT
+ // {
+ // float4 Color : SV_Target0;
+ // };
+ //
+ // cbuffer cbuff{
+ // float4 a[10];
+ // }
+ //
+ // PS_OUTPUT main()
+ // {
+ // PS_OUTPUT psout;
+ // float4 t = 0.0;;
+ //
+ // for (int i = 0; i<10; ++i)
+ // t = t + a[i];
+ //
+ // float4 t2 = t / 10.0;
+ // psout.Color = t2;
+ // return psout;
+ // }
+ //
+ // clang-format on
+
+ const std::string defs_before =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "a"
+OpName %_ ""
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %_arr_v4float_uint_10 ArrayStride 16
+OpMemberDecorate %cbuff 0 Offset 0
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 0
+OpDecorate %_entryPointOutput_Color Location 0
+OpDecorate %96 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+OpDecorate %75 RelaxedPrecision
+OpDecorate %76 RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%float_0 = OpConstant %float 0
+%15 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%int_10 = OpConstant %int 10
+%bool = OpTypeBool
+%uint = OpTypeInt 32 0
+%uint_10 = OpConstant %uint 10
+%_arr_v4float_uint_10 = OpTypeArray %v4float %uint_10
+%cbuff = OpTypeStruct %_arr_v4float_uint_10
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%int_1 = OpConstant %int 1
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+%float_0_100000001 = OpConstant %float 0.100000001
+%94 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001
+)";
+
+ const std::string defs_after =
+ R"(OpCapability Shader
+OpCapability Float16
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "a"
+OpName %_ ""
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %_arr_v4float_uint_10 ArrayStride 16
+OpMemberDecorate %cbuff 0 Offset 0
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 0
+OpDecorate %_entryPointOutput_Color Location 0
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%float_0 = OpConstant %float 0
+%15 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%int_10 = OpConstant %int 10
+%bool = OpTypeBool
+%uint = OpTypeInt 32 0
+%uint_10 = OpConstant %uint 10
+%_arr_v4float_uint_10 = OpTypeArray %v4float %uint_10
+%cbuff = OpTypeStruct %_arr_v4float_uint_10
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%int_1 = OpConstant %int 1
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+%float_0_100000001 = OpConstant %float 0.100000001
+%94 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001
+%half = OpTypeFloat 16
+%v4half = OpTypeVector %half 4
+)";
+
+ const std::string func_before =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+OpBranch %65
+%65 = OpLabel
+%96 = OpPhi %v4float %15 %5 %76 %71
+%95 = OpPhi %int %int_0 %5 %78 %71
+%70 = OpSLessThan %bool %95 %int_10
+OpLoopMerge %66 %71 None
+OpBranchConditional %70 %71 %66
+%71 = OpLabel
+%74 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 %95
+%75 = OpLoad %v4float %74
+%76 = OpFAdd %v4float %96 %75
+%78 = OpIAdd %int %95 %int_1
+OpBranch %65
+%66 = OpLabel
+%81 = OpFMul %v4float %96 %94
+OpStore %_entryPointOutput_Color %81
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string func_after =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%99 = OpFConvert %v4half %15
+OpBranch %65
+%65 = OpLabel
+%96 = OpPhi %v4half %99 %5 %76 %71
+%95 = OpPhi %int %int_0 %5 %78 %71
+%70 = OpSLessThan %bool %95 %int_10
+OpLoopMerge %66 %71 None
+OpBranchConditional %70 %71 %66
+%71 = OpLabel
+%74 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 %95
+%75 = OpLoad %v4float %74
+%103 = OpFConvert %v4half %75
+%76 = OpFAdd %v4half %96 %103
+%78 = OpIAdd %int %95 %int_1
+%100 = OpCopyObject %v4half %76
+OpBranch %65
+%66 = OpLabel
+%101 = OpFConvert %v4half %94
+%81 = OpFMul %v4half %96 %101
+%102 = OpFConvert %v4float %81
+OpStore %_entryPointOutput_Color %102
+OpReturn
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
+ defs_after + func_after, true, true);
+}
+
+TEST_F(ConvertToHalfTest, ConvertToHalfWithExtracts) {
+ // The resulting SPIR-V was processed with --relax-float-ops.
+ //
+ // The extra converts in the func_after can be DCE'd.
+ //
+ // clang-format off
+ //
+ // SamplerState g_sSamp : register(s0);
+ // uniform Texture1D <float4> g_tTex1df4 : register(t0);
+ //
+ // struct PS_INPUT
+ // {
+ // float Tex0 : TEXCOORD0;
+ // };
+ //
+ // struct PS_OUTPUT
+ // {
+ // float4 Color : SV_Target0;
+ // };
+ //
+ // cbuffer cbuff{
+ // float c;
+ // }
+ //
+ // PS_OUTPUT main(PS_INPUT i)
+ // {
+ // PS_OUTPUT psout;
+ // float4 tx = g_tTex1df4.Sample(g_sSamp, i.Tex0);
+ // float4 t = float4(tx.y, tx.z, tx.x, tx.w) * c;
+ // psout.Color = t;
+ // return psout;
+ // }
+ //
+ // clang-format on
+
+ const std::string defs_before =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "c"
+OpName %_ ""
+OpName %i_Tex0 "i.Tex0"
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpMemberDecorate %cbuff 0 Offset 0
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %i_Tex0 Location 0
+OpDecorate %_entryPointOutput_Color Location 0
+OpDecorate %65 RelaxedPrecision
+OpDecorate %82 RelaxedPrecision
+OpDecorate %84 RelaxedPrecision
+OpDecorate %86 RelaxedPrecision
+OpDecorate %88 RelaxedPrecision
+OpDecorate %90 RelaxedPrecision
+OpDecorate %91 RelaxedPrecision
+OpDecorate %93 RelaxedPrecision
+OpDecorate %94 RelaxedPrecision
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%17 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_17 UniformConstant
+%21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+%g_sSamp = OpVariable %_ptr_UniformConstant_21 UniformConstant
+%25 = OpTypeSampledImage %17
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%cbuff = OpTypeStruct %float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%_ptr_Input_float = OpTypePointer Input %float
+%i_Tex0 = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+)";
+
+ const std::string defs_after =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+OpCapability Float16
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %cbuff "cbuff"
+OpMemberName %cbuff 0 "c"
+OpName %_ ""
+OpName %i_Tex0 "i.Tex0"
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpMemberDecorate %cbuff 0 Offset 0
+OpDecorate %cbuff Block
+OpDecorate %_ DescriptorSet 0
+OpDecorate %_ Binding 1
+OpDecorate %i_Tex0 Location 0
+OpDecorate %_entryPointOutput_Color Location 0
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%17 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_17 UniformConstant
+%21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+%g_sSamp = OpVariable %_ptr_UniformConstant_21 UniformConstant
+%25 = OpTypeSampledImage %17
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%cbuff = OpTypeStruct %float
+%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff
+%_ = OpVariable %_ptr_Uniform_cbuff Uniform
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%_ptr_Input_float = OpTypePointer Input %float
+%i_Tex0 = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+%half = OpTypeFloat 16
+%v4half = OpTypeVector %half 4
+)";
+
+ const std::string func_before =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%65 = OpLoad %float %i_Tex0
+%77 = OpLoad %17 %g_tTex1df4
+%78 = OpLoad %21 %g_sSamp
+%79 = OpSampledImage %25 %77 %78
+%82 = OpImageSampleImplicitLod %v4float %79 %65
+%84 = OpCompositeExtract %float %82 1
+%86 = OpCompositeExtract %float %82 2
+%88 = OpCompositeExtract %float %82 0
+%90 = OpCompositeExtract %float %82 3
+%91 = OpCompositeConstruct %v4float %84 %86 %88 %90
+%92 = OpAccessChain %_ptr_Uniform_float %_ %int_0
+%93 = OpLoad %float %92
+%94 = OpVectorTimesScalar %v4float %91 %93
+OpStore %_entryPointOutput_Color %94
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string func_after =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%65 = OpLoad %float %i_Tex0
+%77 = OpLoad %17 %g_tTex1df4
+%78 = OpLoad %21 %g_sSamp
+%79 = OpSampledImage %25 %77 %78
+%82 = OpImageSampleImplicitLod %v4float %79 %65
+%97 = OpFConvert %v4half %82
+%84 = OpCompositeExtract %half %97 1
+%98 = OpFConvert %v4half %82
+%86 = OpCompositeExtract %half %98 2
+%99 = OpFConvert %v4half %82
+%88 = OpCompositeExtract %half %99 0
+%100 = OpFConvert %v4half %82
+%90 = OpCompositeExtract %half %100 3
+%91 = OpCompositeConstruct %v4half %84 %86 %88 %90
+%92 = OpAccessChain %_ptr_Uniform_float %_ %int_0
+%93 = OpLoad %float %92
+%101 = OpFConvert %half %93
+%94 = OpVectorTimesScalar %v4half %91 %101
+%102 = OpFConvert %v4float %94
+OpStore %_entryPointOutput_Color %102
+OpReturn
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndCheck<ConvertToHalfPass>(defs_before + func_before,
+ defs_after + func_after, true, true);
+}
+
+} // namespace
+} // namespace opt
+} // namespace spvtools
diff --git a/test/opt/copy_prop_array_test.cpp b/test/opt/copy_prop_array_test.cpp
index 504ae67..1afee9c 100644
--- a/test/opt/copy_prop_array_test.cpp
+++ b/test/opt/copy_prop_array_test.cpp
@@ -1157,7 +1157,7 @@
OpStore %23 %35
%36 = OpAccessChain %_ptr_Function_v4float %23 %24
%37 = OpLoad %v4float %36
-%39 = OpStore %36 %v4const
+ OpStore %36 %v4const
OpStore %out_var_SV_Target %37
OpReturn
OpFunctionEnd
@@ -1571,6 +1571,57 @@
SinglePassRunAndCheck<CopyPropagateArrays>(before, after, true, true);
}
+TEST_F(CopyPropArrayPassTest, IndexIsNullConstnat) {
+ const std::string text = R"(
+; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform
+; CHECK: [[null:%\w+]] = OpConstantNull %uint
+; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_uint_uint_1 [[var]] %uint_0 %uint_0
+; CHECK: OpAccessChain %_ptr_Uniform_uint [[ac1]] [[null]]
+; CHECK-NEXT: OpReturn
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpSource HLSL 600
+ OpDecorate %myCBuffer DescriptorSet 0
+ OpDecorate %myCBuffer Binding 0
+ OpDecorate %_arr_v4float_uint_1 ArrayStride 16
+ OpMemberDecorate %MyConstantBuffer 0 Offset 0
+ OpMemberDecorate %type_myCBuffer 0 Offset 0
+ OpDecorate %type_myCBuffer Block
+ %uint = OpTypeInt 32 0
+ %int_0 = OpConstant %uint 0
+ %uint_1 = OpConstant %uint 1
+%_arr_v4float_uint_1 = OpTypeArray %uint %uint_1
+%MyConstantBuffer = OpTypeStruct %_arr_v4float_uint_1
+%type_myCBuffer = OpTypeStruct %MyConstantBuffer
+%_ptr_Uniform_type_myCBuffer = OpTypePointer Uniform %type_myCBuffer
+%_arr_v4float_uint_1_0 = OpTypeArray %uint %uint_1
+ %void = OpTypeVoid
+ %19 = OpTypeFunction %void
+%_ptr_Function_v4float = OpTypePointer Function %uint
+%_ptr_Uniform_MyConstantBuffer = OpTypePointer Uniform %MyConstantBuffer
+ %myCBuffer = OpVariable %_ptr_Uniform_type_myCBuffer Uniform
+%_ptr_Function__arr_v4float_uint_1_0 = OpTypePointer Function %_arr_v4float_uint_1_0
+ %23 = OpConstantNull %uint
+ %main = OpFunction %void None %19
+ %24 = OpLabel
+ %25 = OpVariable %_ptr_Function__arr_v4float_uint_1_0 Function
+ %26 = OpAccessChain %_ptr_Uniform_MyConstantBuffer %myCBuffer %int_0
+ %27 = OpLoad %MyConstantBuffer %26
+ %28 = OpCompositeExtract %_arr_v4float_uint_1 %27 0
+ %29 = OpCompositeExtract %uint %28 0
+ %30 = OpCompositeConstruct %_arr_v4float_uint_1_0 %29
+ OpStore %25 %30
+ %31 = OpAccessChain %_ptr_Function_v4float %25 %23
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<CopyPropagateArrays>(text, true);
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/decompose_initialized_variables_test.cpp b/test/opt/decompose_initialized_variables_test.cpp
index cdebb3f..06ba59a 100644
--- a/test/opt/decompose_initialized_variables_test.cpp
+++ b/test/opt/decompose_initialized_variables_test.cpp
@@ -24,9 +24,9 @@
using DecomposeInitializedVariablesTest = PassTest<::testing::Test>;
std::string single_entry_header = R"(OpCapability Shader
-OpCapability VulkanMemoryModelKHR
+OpCapability VulkanMemoryModel
OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
+OpMemoryModel Logical Vulkan
OpEntryPoint Vertex %1 "shader"
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
@@ -126,9 +126,9 @@
}
std::string multiple_entry_header = R"(OpCapability Shader
-OpCapability VulkanMemoryModelKHR
+OpCapability VulkanMemoryModel
OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
+OpMemoryModel Logical Vulkan
OpEntryPoint Vertex %1 "vertex"
OpEntryPoint Fragment %2 "fragment"
%uint = OpTypeInt 32 0
diff --git a/test/opt/eliminate_dead_member_test.cpp b/test/opt/eliminate_dead_member_test.cpp
index 7d5db7d..b6925d7 100644
--- a/test/opt/eliminate_dead_member_test.cpp
+++ b/test/opt/eliminate_dead_member_test.cpp
@@ -561,6 +561,7 @@
OpName %main "main"
OpDecorate %_Globals DescriptorSet 0
OpDecorate %_Globals Binding 0
+ OpDecorate %_runtimearr_float ArrayStride 16
OpMemberDecorate %type__Globals 0 Offset 0
OpMemberDecorate %type__Globals 1 Offset 4
OpMemberDecorate %type__Globals 2 Offset 16
diff --git a/test/opt/fold_spec_const_op_composite_test.cpp b/test/opt/fold_spec_const_op_composite_test.cpp
index c96dc8c..7eddf7e 100644
--- a/test/opt/fold_spec_const_op_composite_test.cpp
+++ b/test/opt/fold_spec_const_op_composite_test.cpp
@@ -112,8 +112,12 @@
// clang-format off
// scalar types
"%bool = OpTypeBool",
+ "%ushort = OpTypeInt 16 0",
+ "%short = OpTypeInt 16 1",
"%uint = OpTypeInt 32 0",
"%int = OpTypeInt 32 1",
+ "%ulong = OpTypeInt 64 0",
+ "%long = OpTypeInt 64 1",
"%float = OpTypeFloat 32",
"%double = OpTypeFloat 64",
// vector types
@@ -122,6 +126,8 @@
"%v2int = OpTypeVector %int 2",
"%v3int = OpTypeVector %int 3",
"%v4int = OpTypeVector %int 4",
+ "%v2long = OpTypeVector %long 2",
+ "%v2ulong = OpTypeVector %ulong 2",
"%v2float = OpTypeVector %float 2",
"%v2double = OpTypeVector %double 2",
// variable pointer types
@@ -145,6 +151,8 @@
"%bool_null = OpConstantNull %bool",
"%signed_zero = OpConstant %int 0",
"%unsigned_zero = OpConstant %uint 0",
+ "%long_zero = OpConstant %long 0",
+ "%ulong_zero = OpConstant %ulong 0",
"%signed_one = OpConstant %int 1",
"%unsigned_one = OpConstant %uint 1",
"%signed_two = OpConstant %int 2",
@@ -153,6 +161,7 @@
"%unsigned_three = OpConstant %uint 3",
"%signed_null = OpConstantNull %int",
"%unsigned_null = OpConstantNull %uint",
+ "%signed_minus_one = OpConstant %int -1",
// vector constants:
"%bool_true_vec = OpConstantComposite %v2bool %bool_true %bool_true",
"%bool_false_vec = OpConstantComposite %v2bool %bool_false %bool_false",
@@ -167,6 +176,7 @@
"%unsigned_three_vec = OpConstantComposite %v2uint %unsigned_three %unsigned_three",
"%signed_null_vec = OpConstantNull %v2int",
"%unsigned_null_vec = OpConstantNull %v2uint",
+ "%signed_minus_one_vec = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
"%v4int_0_1_2_3 = OpConstantComposite %v4int %signed_zero %signed_one %signed_two %signed_three",
// clang-format on
};
@@ -345,9 +355,9 @@
// Tests for operations that resulting in different types.
INSTANTIATE_TEST_SUITE_P(
Cast, FoldSpecConstantOpAndCompositePassTest,
- ::testing::ValuesIn(
- std::vector<FoldSpecConstantOpAndCompositePassTestCase>({
- // clang-format off
+ ::testing::ValuesIn(std::vector<
+ FoldSpecConstantOpAndCompositePassTestCase>({
+ // clang-format off
// int -> bool scalar
{
// original
@@ -575,8 +585,108 @@
"%spec_uint_from_null = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
},
},
- // clang-format on
- })));
+
+ // UConvert scalar
+ {
+ // original
+ {
+ "%spec_uint_zero = OpSpecConstantOp %uint UConvert %bool_false",
+ "%spec_uint_one = OpSpecConstantOp %uint UConvert %bool_true",
+ "%spec_ulong_zero = OpSpecConstantOp %ulong UConvert %unsigned_zero",
+ "%spec_ulong_one = OpSpecConstantOp %ulong UConvert %unsigned_one",
+ "%spec_short_zero = OpSpecConstantOp %ushort UConvert %unsigned_zero",
+ "%spec_short_one = OpSpecConstantOp %ushort UConvert %unsigned_one",
+ "%uint_max = OpConstant %uint 4294967295",
+ "%spec_ushort_max = OpSpecConstantOp %ushort UConvert %uint_max",
+ "%uint_0xDDDDDDDD = OpConstant %uint 3722304989",
+ "%spec_ushort_0xDDDD = OpSpecConstantOp %ushort UConvert %uint_0xDDDDDDDD",
+ },
+ // expected
+ {
+ "%spec_uint_zero = OpConstant %uint 0",
+ "%spec_uint_one = OpConstant %uint 1",
+ "%spec_ulong_zero = OpConstant %ulong 0",
+ "%spec_ulong_one = OpConstant %ulong 1",
+ "%spec_short_zero = OpConstant %ushort 0",
+ "%spec_short_one = OpConstant %ushort 1",
+ "%uint_max = OpConstant %uint 4294967295",
+ "%spec_ushort_max = OpConstant %ushort 65535",
+ "%uint_0xDDDDDDDD = OpConstant %uint 3722304989",
+ "%spec_ushort_0xDDDD = OpConstant %ushort 56797",
+ },
+ },
+
+ // SConvert scalar
+ {
+ // original
+ {
+ "%spec_long_zero = OpSpecConstantOp %long SConvert %signed_zero",
+ "%spec_long_one = OpSpecConstantOp %long SConvert %signed_one",
+ "%spec_long_minus_one = OpSpecConstantOp %long SConvert %signed_minus_one",
+ "%spec_short_minus_one_trunc = OpSpecConstantOp %short SConvert %signed_minus_one",
+ "%int_2_to_17_minus_one = OpConstant %int 131071",
+ "%spec_short_minus_one_trunc2 = OpSpecConstantOp %short SConvert %int_2_to_17_minus_one",
+ },
+ // expected
+ {
+ "%spec_long_zero = OpConstant %long 0",
+ "%spec_long_one = OpConstant %long 1",
+ "%spec_long_minus_one = OpConstant %long -1",
+ "%spec_short_minus_one_trunc = OpConstant %short -1",
+ "%int_2_to_17_minus_one = OpConstant %int 131071",
+ "%spec_short_minus_one_trunc2 = OpConstant %short -1",
+ },
+ },
+
+ // UConvert vector
+ {
+ // original
+ {
+ "%spec_v2uint_zero = OpSpecConstantOp %v2uint UConvert %bool_false_vec",
+ "%spec_v2uint_one = OpSpecConstantOp %v2uint UConvert %bool_true_vec",
+ "%spec_v2ulong_zero = OpSpecConstantOp %v2ulong UConvert %unsigned_zero_vec",
+ "%spec_v2ulong_one = OpSpecConstantOp %v2ulong UConvert %unsigned_one_vec",
+ },
+ // expected
+ {
+ "%uint_0 = OpConstant %uint 0",
+ "%uint_0_0 = OpConstant %uint 0",
+ "%spec_v2uint_zero = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
+ "%uint_1 = OpConstant %uint 1",
+ "%uint_1_0 = OpConstant %uint 1",
+ "%spec_v2uint_one = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
+ "%ulong_0 = OpConstant %ulong 0",
+ "%ulong_0_0 = OpConstant %ulong 0",
+ "%spec_v2ulong_zero = OpConstantComposite %v2ulong %ulong_zero %ulong_zero",
+ "%ulong_1 = OpConstant %ulong 1",
+ "%ulong_1_0 = OpConstant %ulong 1",
+ "%spec_v2ulong_one = OpConstantComposite %v2ulong %ulong_1 %ulong_1",
+ },
+ },
+
+ // SConvert vector
+ {
+ // original
+ {
+ "%spec_v2long_zero = OpSpecConstantOp %v2long SConvert %signed_zero_vec",
+ "%spec_v2long_one = OpSpecConstantOp %v2long SConvert %signed_one_vec",
+ "%spec_v2long_minus_one = OpSpecConstantOp %v2long SConvert %signed_minus_one_vec",
+ },
+ // expected
+ {
+ "%long_0 = OpConstant %long 0",
+ "%long_0_0 = OpConstant %long 0",
+ "%spec_v2long_zero = OpConstantComposite %v2long %long_zero %long_zero",
+ "%long_1 = OpConstant %long 1",
+ "%long_1_0 = OpConstant %long 1",
+ "%spec_v2long_one = OpConstantComposite %v2long %long_1 %long_1",
+ "%long_n1 = OpConstant %long -1",
+ "%long_n1_0 = OpConstant %long -1",
+ "%spec_v2long_minus_one = OpConstantComposite %v2long %long_n1 %long_n1",
+ },
+ },
+ // clang-format on
+ })));
// Tests about boolean scalar logical operations and comparison operations with
// scalar int/uint type.
@@ -851,7 +961,7 @@
{
"%int_n1 = OpConstant %int -1",
"%int_n1_0 = OpConstant %int -1",
- "%v2int_minus_1 = OpConstantComposite %v2int %int_n1 %int_n1",
+ "%v2int_minus_1 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
"%int_n2 = OpConstant %int -2",
"%int_n2_0 = OpConstant %int -2",
"%v2int_minus_2 = OpConstantComposite %v2int %int_n2 %int_n2",
@@ -956,13 +1066,13 @@
"%7_srem_3 = OpConstantComposite %v2int %signed_one %signed_one",
"%int_n1 = OpConstant %int -1",
"%int_n1_0 = OpConstant %int -1",
- "%minus_7_srem_3 = OpConstantComposite %v2int %int_n1 %int_n1",
+ "%minus_7_srem_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
"%int_1_1 = OpConstant %int 1",
"%int_1_2 = OpConstant %int 1",
"%7_srem_minus_3 = OpConstantComposite %v2int %signed_one %signed_one",
"%int_n1_1 = OpConstant %int -1",
"%int_n1_2 = OpConstant %int -1",
- "%minus_7_srem_minus_3 = OpConstantComposite %v2int %int_n1 %int_n1",
+ "%minus_7_srem_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
// smod
"%int_1_3 = OpConstant %int 1",
"%int_1_4 = OpConstant %int 1",
@@ -975,7 +1085,7 @@
"%7_smod_minus_3 = OpConstantComposite %v2int %int_n2 %int_n2",
"%int_n1_3 = OpConstant %int -1",
"%int_n1_4 = OpConstant %int -1",
- "%minus_7_smod_minus_3 = OpConstantComposite %v2int %int_n1 %int_n1",
+ "%minus_7_smod_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
// umod
"%uint_1 = OpConstant %uint 1",
"%uint_1_0 = OpConstant %uint 1",
@@ -1018,7 +1128,7 @@
"%unsigned_right_shift_logical = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
"%int_n1 = OpConstant %int -1",
"%int_n1_0 = OpConstant %int -1",
- "%signed_right_shift_arithmetic = OpConstantComposite %v2int %int_n1 %int_n1",
+ "%signed_right_shift_arithmetic = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
},
},
// Skip folding if any vector operands or components of the operands
diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp
index b5998c7..68a7d18 100644
--- a/test/opt/fold_test.cpp
+++ b/test/opt/fold_test.cpp
@@ -222,6 +222,7 @@
%v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2
%v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4
%v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5
+%v2float_0p2_0p5 = OpConstantComposite %v2float %float_0p2 %float_0p5
%v2float_null = OpConstantNull %v2float
%double_n1 = OpConstant %double -1
%105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps.
@@ -231,7 +232,9 @@
%double_2 = OpConstant %double 2
%double_3 = OpConstant %double 3
%double_4 = OpConstant %double 4
+%double_5 = OpConstant %double 5
%double_0p5 = OpConstant %double 0.5
+%double_0p2 = OpConstant %double 0.2
%v2double_0_0 = OpConstantComposite %v2double %double_0 %double_0
%v2double_2_2 = OpConstantComposite %v2double %double_2 %double_2
%v2double_2_3 = OpConstantComposite %v2double %double_2 %double_3
@@ -557,7 +560,155 @@
"%2 = OpSNegate %int %int_min\n" +
"OpReturn\n" +
"OpFunctionEnd",
- 2, std::numeric_limits<int32_t>::min())
+ 2, std::numeric_limits<int32_t>::min()),
+ // Test case 30: fold UMin 3 4
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %uint %1 UMin %uint_3 %uint_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 3),
+ // Test case 31: fold UMin 4 2
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %uint %1 UMin %uint_4 %uint_2\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2),
+ // Test case 32: fold SMin 3 4
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %int %1 UMin %int_3 %int_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 3),
+ // Test case 33: fold SMin 4 2
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %int %1 SMin %int_4 %int_2\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2),
+ // Test case 34: fold UMax 3 4
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 4),
+ // Test case 35: fold UMax 3 2
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_2\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 3),
+ // Test case 36: fold SMax 3 4
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %int %1 UMax %int_3 %int_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 4),
+ // Test case 37: fold SMax 3 2
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %int %1 SMax %int_3 %int_2\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 3),
+ // Test case 38: fold UClamp 2 3 4
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_3 %uint_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 3),
+ // Test case 39: fold UClamp 2 0 4
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2),
+ // Test case 40: fold UClamp 2 0 1
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_1\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1),
+ // Test case 41: fold SClamp 2 3 4
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %int %1 SClamp %int_2 %int_3 %int_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 3),
+ // Test case 42: fold SClamp 2 0 4
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2),
+ // Test case 43: fold SClamp 2 0 1
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_1\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1),
+ // Test case 44: SClamp 1 2 x
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%undef = OpUndef %int\n" +
+ "%2 = OpExtInst %int %1 SClamp %int_1 %int_2 %undef\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2),
+ // Test case 45: SClamp 2 x 1
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%undef = OpUndef %int\n" +
+ "%2 = OpExtInst %int %1 SClamp %int_2 %undef %int_1\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1),
+ // Test case 44: UClamp 1 2 x
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%undef = OpUndef %uint\n" +
+ "%2 = OpExtInst %uint %1 UClamp %uint_1 %uint_2 %undef\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2),
+ // Test case 45: UClamp 2 x 1
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%undef = OpUndef %uint\n" +
+ "%2 = OpExtInst %uint %1 UClamp %uint_2 %undef %uint_1\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1)
));
// clang-format on
@@ -643,6 +794,58 @@
));
// clang-format on
+using FloatVectorInstructionFoldingTest =
+ ::testing::TestWithParam<InstructionFoldingCase<std::vector<float>>>;
+
+TEST_P(FloatVectorInstructionFoldingTest, Case) {
+ const auto& tc = GetParam();
+
+ // Build module.
+ std::unique_ptr<IRContext> context =
+ BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ ASSERT_NE(nullptr, context);
+
+ // Fold the instruction to test.
+ analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
+ Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
+ SpvOp original_opcode = inst->opcode();
+ bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
+
+ // Make sure the instruction folded as expected.
+ EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
+ if (succeeded && inst != nullptr) {
+ EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
+ inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
+ std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
+ EXPECT_THAT(opcodes, Contains(inst->opcode()));
+ analysis::ConstantManager* const_mrg = context->get_constant_mgr();
+ const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
+ EXPECT_NE(result, nullptr);
+ if (result != nullptr) {
+ const std::vector<const analysis::Constant*>& componenets =
+ result->AsVectorConstant()->GetComponents();
+ EXPECT_EQ(componenets.size(), tc.expected_result.size());
+ for (size_t i = 0; i < componenets.size(); i++) {
+ EXPECT_EQ(tc.expected_result[i], componenets[i]->GetFloat());
+ }
+ }
+ }
+}
+
+// clang-format off
+INSTANTIATE_TEST_SUITE_P(TestCase, FloatVectorInstructionFoldingTest,
+::testing::Values(
+ // Test case 0: FMix {2.0, 2.0}, {2.0, 3.0} {0.2,0.5}
+ InstructionFoldingCase<std::vector<float>>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %v2float %1 FMix %v2float_2_3 %v2float_0_0 %v2float_0p2_0p5\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, {1.6f,1.5f})
+));
+// clang-format on
using BooleanInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<bool>>;
@@ -1473,7 +1676,81 @@
"%2 = OpExtInst %float %1 FMix %float_1 %float_4 %float_0p2\n" +
"OpReturn\n" +
"OpFunctionEnd",
- 2, 1.6f)
+ 2, 1.6f),
+ // Test case 21: FMin 1.0 4.0
+ InstructionFoldingCase<float>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %float %1 FMin %float_1 %float_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1.0f),
+ // Test case 22: FMin 4.0 0.2
+ InstructionFoldingCase<float>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %float %1 FMin %float_4 %float_0p2\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 0.2f),
+ // Test case 21: FMax 1.0 4.0
+ InstructionFoldingCase<float>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %float %1 FMax %float_1 %float_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 4.0f),
+ // Test case 22: FMax 1.0 0.2
+ InstructionFoldingCase<float>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %float %1 FMax %float_1 %float_0p2\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1.0f),
+ // Test case 23: FClamp 1.0 0.2 4.0
+ InstructionFoldingCase<float>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %float %1 FClamp %float_1 %float_0p2 %float_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1.0f),
+ // Test case 24: FClamp 0.2 2.0 4.0
+ InstructionFoldingCase<float>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %float %1 FClamp %float_0p2 %float_2 %float_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2.0f),
+ // Test case 25: FClamp 2049.0 2.0 4.0
+ InstructionFoldingCase<float>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %float %1 FClamp %float_2049 %float_2 %float_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 4.0f),
+ // Test case 26: FClamp 1.0 2.0 x
+ InstructionFoldingCase<float>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%undef = OpUndef %float\n" +
+ "%2 = OpExtInst %float %1 FClamp %float_1 %float_2 %undef\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2.0),
+ // Test case 27: FClamp 1.0 x 0.5
+ InstructionFoldingCase<float>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%undef = OpUndef %float\n" +
+ "%2 = OpExtInst %float %1 FClamp %float_1 %undef %float_0p5\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 0.5)
));
// clang-format on
@@ -1616,7 +1893,81 @@
"%2 = OpFNegate %double %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
- 2, -2)
+ 2, -2),
+ // Test case 12: FMin 1.0 4.0
+ InstructionFoldingCase<double>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %double %1 FMin %double_1 %double_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1.0),
+ // Test case 13: FMin 4.0 0.2
+ InstructionFoldingCase<double>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %double %1 FMin %double_4 %double_0p2\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 0.2),
+ // Test case 14: FMax 1.0 4.0
+ InstructionFoldingCase<double>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %double %1 FMax %double_1 %double_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 4.0),
+ // Test case 15: FMax 1.0 0.2
+ InstructionFoldingCase<double>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %double %1 FMax %double_1 %double_0p2\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1.0),
+ // Test case 16: FClamp 1.0 0.2 4.0
+ InstructionFoldingCase<double>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %double %1 FClamp %double_1 %double_0p2 %double_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 1.0),
+ // Test case 17: FClamp 0.2 2.0 4.0
+ InstructionFoldingCase<double>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %double %1 FClamp %double_0p2 %double_2 %double_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2.0),
+ // Test case 18: FClamp 5.0 2.0 4.0
+ InstructionFoldingCase<double>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpExtInst %double %1 FClamp %double_5 %double_2 %double_4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 4.0),
+ // Test case 19: FClamp 1.0 2.0 x
+ InstructionFoldingCase<double>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%undef = OpUndef %double\n" +
+ "%2 = OpExtInst %double %1 FClamp %double_1 %double_2 %undef\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 2.0),
+ // Test case 20: FClamp 1.0 x 0.5
+ InstructionFoldingCase<double>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%undef = OpUndef %double\n" +
+ "%2 = OpExtInst %double %1 FClamp %double_1 %undef %double_0p5\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, 0.5)
));
// clang-format on
@@ -5412,6 +5763,132 @@
4, true)
));
+INSTANTIATE_TEST_SUITE_P(MergeGenericAddSub, MatchingInstructionFoldingTest,
+::testing::Values(
+ // Test case 0: merge of add of sub
+ // (a - b) + b => a
+ InstructionFoldingCase<bool>(
+ Header() +
+ "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
+ "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
+ "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%var0 = OpVariable %_ptr_float Function\n" +
+ "%var1 = OpVariable %_ptr_float Function\n" +
+ "%3 = OpLoad %float %var0\n" +
+ "%4 = OpLoad %float %var1\n" +
+ "%5 = OpFSub %float %3 %4\n" +
+ "%6 = OpFAdd %float %5 %4\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd\n",
+ 6, true),
+ // Test case 1: merge of add of sub
+ // b + (a - b) => a
+ InstructionFoldingCase<bool>(
+ Header() +
+ "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
+ "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
+ "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%var0 = OpVariable %_ptr_float Function\n" +
+ "%var1 = OpVariable %_ptr_float Function\n" +
+ "%3 = OpLoad %float %var0\n" +
+ "%4 = OpLoad %float %var1\n" +
+ "%5 = OpFSub %float %3 %4\n" +
+ "%6 = OpFAdd %float %4 %5\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd\n",
+ 6, true)
+));
+
+INSTANTIATE_TEST_SUITE_P(FactorAddMul, MatchingInstructionFoldingTest,
+::testing::Values(
+ // Test case 0: factor of add of muls
+ // (a * b) + (a * c) => a * (b + c)
+ InstructionFoldingCase<bool>(
+ Header() +
+ "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
+ "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
+ "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
+ "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%var0 = OpVariable %_ptr_float Function\n" +
+ "%var1 = OpVariable %_ptr_float Function\n" +
+ "%var2 = OpVariable %_ptr_float Function\n" +
+ "%4 = OpLoad %float %var0\n" +
+ "%5 = OpLoad %float %var1\n" +
+ "%6 = OpLoad %float %var2\n" +
+ "%7 = OpFMul %float %6 %4\n" +
+ "%8 = OpFMul %float %6 %5\n" +
+ "%9 = OpFAdd %float %7 %8\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd\n",
+ 9, true),
+ // Test case 1: factor of add of muls
+ // (b * a) + (a * c) => a * (b + c)
+ InstructionFoldingCase<bool>(
+ Header() +
+ "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
+ "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
+ "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
+ "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%var0 = OpVariable %_ptr_float Function\n" +
+ "%var1 = OpVariable %_ptr_float Function\n" +
+ "%var2 = OpVariable %_ptr_float Function\n" +
+ "%4 = OpLoad %float %var0\n" +
+ "%5 = OpLoad %float %var1\n" +
+ "%6 = OpLoad %float %var2\n" +
+ "%7 = OpFMul %float %4 %6\n" +
+ "%8 = OpFMul %float %6 %5\n" +
+ "%9 = OpFAdd %float %7 %8\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd\n",
+ 9, true),
+ // Test case 2: factor of add of muls
+ // (a * b) + (c * a) => a * (b + c)
+ InstructionFoldingCase<bool>(
+ Header() +
+ "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
+ "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
+ "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
+ "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%var0 = OpVariable %_ptr_float Function\n" +
+ "%var1 = OpVariable %_ptr_float Function\n" +
+ "%var2 = OpVariable %_ptr_float Function\n" +
+ "%4 = OpLoad %float %var0\n" +
+ "%5 = OpLoad %float %var1\n" +
+ "%6 = OpLoad %float %var2\n" +
+ "%7 = OpFMul %float %6 %4\n" +
+ "%8 = OpFMul %float %5 %6\n" +
+ "%9 = OpFAdd %float %7 %8\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd\n",
+ 9, true),
+ // Test case 3: factor of add of muls
+ // (b * a) + (c * a) => a * (b + c)
+ InstructionFoldingCase<bool>(
+ Header() +
+ "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
+ "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
+ "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
+ "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%var0 = OpVariable %_ptr_float Function\n" +
+ "%var1 = OpVariable %_ptr_float Function\n" +
+ "%var2 = OpVariable %_ptr_float Function\n" +
+ "%4 = OpLoad %float %var0\n" +
+ "%5 = OpLoad %float %var1\n" +
+ "%6 = OpLoad %float %var2\n" +
+ "%7 = OpFMul %float %4 %6\n" +
+ "%8 = OpFMul %float %5 %6\n" +
+ "%9 = OpFAdd %float %7 %8\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd\n",
+ 9, true)
+));
+
INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest,
::testing::Values(
// Test case 0: merge sub of negate
@@ -6581,6 +7058,96 @@
1, false)
));
+std::string ImageOperandsTestBody(const std::string& image_instruction) {
+ std::string body = R"(
+ OpCapability Shader
+ OpCapability ImageGatherExtended
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpDecorate %Texture DescriptorSet 0
+ OpDecorate %Texture Binding 0
+ %int = OpTypeInt 32 1
+ %int_n1 = OpConstant %int -1
+ %5 = OpConstant %int 0
+ %float = OpTypeFloat 32
+ %float_0 = OpConstant %float 0
+%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
+%type_sampled_image = OpTypeSampledImage %type_2d_image
+%type_sampler = OpTypeSampler
+%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
+%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
+ %_ptr_int = OpTypePointer Function %int
+ %v2int = OpTypeVector %int 2
+ %10 = OpTypeVector %float 4
+ %void = OpTypeVoid
+ %22 = OpTypeFunction %void
+ %v2float = OpTypeVector %float 2
+ %v3int = OpTypeVector %int 3
+ %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
+ %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
+ %101 = OpConstantComposite %v2int %int_n1 %int_n1
+ %20 = OpConstantComposite %v2float %float_0 %float_0
+ %main = OpFunction %void None %22
+ %23 = OpLabel
+ %var = OpVariable %_ptr_int Function
+ %88 = OpLoad %type_2d_image %Texture
+ %val = OpLoad %int %var
+ %sampler = OpLoad %type_sampler %gSampler
+ %26 = OpSampledImage %type_sampled_image %88 %sampler
+)" + image_instruction + R"(
+ OpReturn
+ OpFunctionEnd
+)";
+
+ return body;
+}
+
+INSTANTIATE_TEST_SUITE_P(ImageOperandsBitmaskFoldingTest, MatchingInstructionWithNoResultFoldingTest,
+::testing::Values(
+ // Test case 0: OpImageFetch without Offset
+ InstructionFoldingCase<bool>(ImageOperandsTestBody(
+ "%89 = OpImageFetch %10 %88 %101 Lod %5 \n")
+ , 89, false),
+ // Test case 1: OpImageFetch with non-const offset
+ InstructionFoldingCase<bool>(ImageOperandsTestBody(
+ "%89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %val \n")
+ , 89, false),
+ // Test case 2: OpImageFetch with Lod and Offset
+ InstructionFoldingCase<bool>(ImageOperandsTestBody(
+ " %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %101 \n"
+ "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod|ConstOffset %5 %101 \n")
+ , 89, true),
+ // Test case 3: OpImageFetch with Bias and Offset
+ InstructionFoldingCase<bool>(ImageOperandsTestBody(
+ " %89 = OpImageFetch %10 %88 %101 Bias|Offset %5 %101 \n"
+ "; CHECK: %89 = OpImageFetch %10 %88 %101 Bias|ConstOffset %5 %101 \n")
+ , 89, true),
+ // Test case 4: OpImageFetch with Grad and Offset.
+ // Grad adds 2 operands to the instruction.
+ InstructionFoldingCase<bool>(ImageOperandsTestBody(
+ " %89 = OpImageFetch %10 %88 %101 Grad|Offset %5 %5 %101 \n"
+ "; CHECK: %89 = OpImageFetch %10 %88 %101 Grad|ConstOffset %5 %5 %101 \n")
+ , 89, true),
+ // Test case 5: OpImageFetch with Offset and MinLod.
+ // This is an example of a case where the bitmask bit-offset is larger than
+ // that of the Offset.
+ InstructionFoldingCase<bool>(ImageOperandsTestBody(
+ " %89 = OpImageFetch %10 %88 %101 Offset|MinLod %101 %5 \n"
+ "; CHECK: %89 = OpImageFetch %10 %88 %101 ConstOffset|MinLod %101 %5 \n")
+ , 89, true),
+ // Test case 6: OpImageGather with constant Offset
+ InstructionFoldingCase<bool>(ImageOperandsTestBody(
+ " %89 = OpImageGather %10 %26 %20 %5 Offset %101 \n"
+ "; CHECK: %89 = OpImageGather %10 %26 %20 %5 ConstOffset %101 \n")
+ , 89, true),
+ // Test case 7: OpImageWrite with constant Offset
+ InstructionFoldingCase<bool>(ImageOperandsTestBody(
+ " OpImageWrite %88 %5 %101 Offset %101 \n"
+ "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n")
+ , 0 /* No result-id */, true)
+));
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/generate_webgpu_initializers_test.cpp b/test/opt/generate_webgpu_initializers_test.cpp
index f35cf56..4aab2ce 100644
--- a/test/opt/generate_webgpu_initializers_test.cpp
+++ b/test/opt/generate_webgpu_initializers_test.cpp
@@ -46,9 +46,9 @@
std::vector<const char*> result = {
// clang-format off
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
ptr_str.c_str()};
@@ -132,9 +132,9 @@
std::vector<const char*> result = {
// clang-format off
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
ptr_str.c_str(),
@@ -206,9 +206,9 @@
std::vector<const char*> spirv = {
// clang-format off
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
"%_ptr_Private_uint = OpTypePointer Private %uint",
@@ -232,9 +232,9 @@
std::vector<const char*> input_spirv = {
// clang-format off
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
"%uint_2 = OpConstant %uint 2",
@@ -258,9 +258,9 @@
std::vector<const char*> expected_spirv = {
// clang-format off
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
"%uint_2 = OpConstant %uint 2",
@@ -290,9 +290,9 @@
std::vector<const char*> input_spirv = {
// clang-format off
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
"%_struct_3 = OpTypeStruct %uint",
@@ -315,9 +315,9 @@
std::vector<const char*> expected_spirv = {
// clang-format off
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
"%_struct_3 = OpTypeStruct %uint",
diff --git a/test/opt/graphics_robust_access_test.cpp b/test/opt/graphics_robust_access_test.cpp
index 137d0e8..58bd404 100644
--- a/test/opt/graphics_robust_access_test.cpp
+++ b/test/opt/graphics_robust_access_test.cpp
@@ -90,7 +90,7 @@
TEST_F(GraphicsRobustAccessTest,
FailCantProcessPhysicalStorageBuffer64EXTAddressingModel) {
const std::string text = R"(
-; CHECK: Addressing model must be Logical. Found OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+; CHECK: Addressing model must be Logical. Found OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpCapability Shader
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
)";
@@ -199,11 +199,11 @@
const std::string& original,
const std::string& transformed) {
return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" +
- (transformed.size() ? " " : "") + transformed +
+ (transformed.empty() ? "" : " ") + transformed +
"\n ; CHECK-NOT: " + access_chain_inst +
"\n ; CHECK-NEXT: OpReturn"
"\n %ac = " +
- access_chain_inst + " %ptr_ty %var " + (original.size() ? " " : "") +
+ access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") +
original + "\n";
}
@@ -211,11 +211,11 @@
const std::string& original,
const std::string& transformed) {
return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" +
- (transformed.size() ? " " : "") + transformed +
+ (transformed.empty() ? "" : " ") + transformed +
"\n ; CHECK-NOT: " + access_chain_inst +
"\n ; CHECK-NOT: OpReturn"
"\n %ac = " +
- access_chain_inst + " %ptr_ty %var " + (original.size() ? " " : "") +
+ access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") +
original + "\n";
}
@@ -898,7 +898,7 @@
TEST_F(GraphicsRobustAccessTest, ACRTArrayLeastInboundClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
- shaders << ShaderPreambleAC() << "OpMemberDecorate %ssbo_s 0 ArrayStride 4 "
+ shaders << ShaderPreambleAC() << "OpDecorate %rtarr ArrayStride 4 "
<< DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %uint %uint %rtarr
@@ -924,9 +924,8 @@
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << "OpCapability Int16\n"
- << ShaderPreambleAC({"i"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
- << TypesVoid() << TypesShort() << TypesFloat() << R"(
+ << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
+ << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %short %short %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@@ -954,9 +953,8 @@
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << "OpCapability Int16\n"
- << ShaderPreambleAC({"i"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
- << TypesVoid() << TypesShort() << TypesFloat() << R"(
+ << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
+ << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %short %short %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@@ -983,9 +981,8 @@
TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralIntIndexClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
- shaders << ShaderPreambleAC({"i"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
- << TypesVoid() << TypesInt() << TypesFloat() << R"(
+ shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
+ << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %int %int %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@@ -1000,8 +997,9 @@
; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] UClamp %i %int_0 %[[max]]
- )" << MainPrefix()
- << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
+ )"
+ << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
+ << MainSuffix();
SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
}
}
@@ -1009,9 +1007,8 @@
TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUIntIndexClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
- shaders << ShaderPreambleAC({"i"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
- << TypesVoid() << TypesInt() << TypesFloat() << R"(
+ shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
+ << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %int %int %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@@ -1026,8 +1023,9 @@
; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
; CHECK: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1
; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UClamp %i %uint_0 %[[max]]
- )" << MainPrefix()
- << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
+ )"
+ << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
+ << MainSuffix();
SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
}
}
@@ -1036,8 +1034,8 @@
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << "OpCapability Int64" << ShaderPreambleAC({"i"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
- << TypesVoid() << TypesInt() << TypesLong() << TypesFloat() << R"(
+ << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid()
+ << TypesInt() << TypesLong() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %int %int %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@@ -1053,9 +1051,8 @@
; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]]
; CHECK: %[[max:\w+]] = OpISub %long %[[arrlen_ext]] %long_1
; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] UClamp %i %long_0 %[[max]]
- )"
- << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
- << MainSuffix();
+ )" << MainPrefix()
+ << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
}
}
@@ -1064,8 +1061,8 @@
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << "OpCapability Int64" << ShaderPreambleAC({"i"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
- << TypesVoid() << TypesInt() << TypesLong() << TypesFloat() << R"(
+ << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid()
+ << TypesInt() << TypesLong() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %int %int %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@@ -1081,9 +1078,8 @@
; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]]
; CHECK: %[[max:\w+]] = OpISub %ulong %[[arrlen_ext]] %ulong_1
; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] UClamp %i %ulong_0 %[[max]]
- )"
- << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
- << MainSuffix();
+ )" << MainPrefix()
+ << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
}
}
@@ -1095,7 +1091,7 @@
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << ShaderPreambleAC({"i", "j"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 32\n"
+ << "OpDecorate %rtarr ArrayStride 32\n"
<< DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
<< "OpMemberDecorate %rtelem 1 Offset 16\n"
<< TypesVoid() << TypesInt() << TypesFloat() << R"(
@@ -1131,7 +1127,7 @@
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << ShaderPreambleAC({"i", "ssbo_s"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 32\n"
+ << "OpDecorate %rtarr ArrayStride 32\n"
<< DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
<< "OpMemberDecorate %rtelem 1 Offset 16\n"
<< TypesVoid() << TypesInt() << TypesFloat() << R"(
@@ -1175,7 +1171,7 @@
std::ostringstream shaders;
shaders << ShaderPreambleAC({"i", "j", "k", "ssbo_s", "ssbo_pty",
"rtarr_pty", "ac_ssbo", "ac_rtarr"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 32\n"
+ << "OpDecorate %rtarr ArrayStride 32\n"
<< DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
<< "OpMemberDecorate %rtelem 1 Offset 16\n"
<< TypesVoid() << TypesInt() << TypesFloat() << R"(
@@ -1238,7 +1234,7 @@
shaders << ShaderPreambleAC({"i", "j", "k", "bb1", "bb2", "ssbo_s",
"ssbo_pty", "rtarr_pty", "ac_ssbo",
"ac_rtarr"})
- << "OpMemberDecorate %ssbo_s 0 ArrayStride 32\n"
+ << "OpDecorate %rtarr ArrayStride 32\n"
<< DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
<< "OpMemberDecorate %rtelem 1 Offset 16\n"
<< TypesVoid() << TypesInt() << TypesFloat() << R"(
diff --git a/test/opt/if_conversion_test.cpp b/test/opt/if_conversion_test.cpp
index 03932a9..aa5adea 100644
--- a/test/opt/if_conversion_test.cpp
+++ b/test/opt/if_conversion_test.cpp
@@ -375,14 +375,12 @@
OpSelectionMerge %12 None
OpBranchConditional %true %13 %12
%13 = OpLabel
-OpBranchConditional %true %14 %15
+OpBranchConditional %true %14 %12
%14 = OpLabel
OpBranch %12
-%15 = OpLabel
-OpBranch %12
%12 = OpLabel
-%16 = OpPhi %uint %uint_0 %11 %uint_0 %14 %uint_1 %15
-OpStore %2 %16
+%15 = OpPhi %uint %uint_0 %11 %uint_0 %13 %uint_1 %14
+OpStore %2 %15
OpReturn
OpFunctionEnd
)";
diff --git a/test/opt/inline_test.cpp b/test/opt/inline_test.cpp
index 7170812..fac49ca 100644
--- a/test/opt/inline_test.cpp
+++ b/test/opt/inline_test.cpp
@@ -2792,182 +2792,6 @@
}
}
-TEST_F(InlineTest, OpKill) {
- const std::string text = R"(
-; CHECK: OpFunction
-; CHECK-NEXT: OpLabel
-; CHECK-NEXT: OpKill
-; CHECK-NEXT: OpLabel
-; CHECK-NEXT: OpReturn
-; CHECK-NEXT: OpFunctionEnd
-OpCapability Shader
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main"
-OpExecutionMode %main OriginUpperLeft
-%void = OpTypeVoid
-%voidfuncty = OpTypeFunction %void
-%main = OpFunction %void None %voidfuncty
-%1 = OpLabel
-%2 = OpFunctionCall %void %func
-OpReturn
-OpFunctionEnd
-%func = OpFunction %void None %voidfuncty
-%3 = OpLabel
-OpKill
-OpFunctionEnd
-)";
-
- SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
-}
-
-TEST_F(InlineTest, OpKillWithTrailingInstructions) {
- const std::string text = R"(
-; CHECK: OpFunction
-; CHECK-NEXT: OpLabel
-; CHECK-NEXT: [[var:%\w+]] = OpVariable
-; CHECK-NEXT: OpKill
-; CHECK-NEXT: OpLabel
-; CHECK-NEXT: OpStore [[var]]
-; CHECK-NEXT: OpReturn
-; CHECK-NEXT: OpFunctionEnd
-OpCapability Shader
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main"
-OpExecutionMode %main OriginUpperLeft
-%void = OpTypeVoid
-%bool = OpTypeBool
-%true = OpConstantTrue %bool
-%bool_func_ptr = OpTypePointer Function %bool
-%voidfuncty = OpTypeFunction %void
-%main = OpFunction %void None %voidfuncty
-%1 = OpLabel
-%2 = OpVariable %bool_func_ptr Function
-%3 = OpFunctionCall %void %func
-OpStore %2 %true
-OpReturn
-OpFunctionEnd
-%func = OpFunction %void None %voidfuncty
-%4 = OpLabel
-OpKill
-OpFunctionEnd
-)";
-
- SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
-}
-
-TEST_F(InlineTest, OpKillInIf) {
- const std::string text = R"(
-; CHECK: OpFunction
-; CHECK: OpLabel
-; CHECK: [[var:%\w+]] = OpVariable
-; CHECK-NEXT: [[ld:%\w+]] = OpLoad {{%\w+}} [[var]]
-; CHECK-NEXT: OpBranch [[label:%\w+]]
-; CHECK-NEXT: [[label]] = OpLabel
-; CHECK-NEXT: OpLoopMerge [[loop_merge:%\w+]] [[continue:%\w+]] None
-; CHECK-NEXT: OpBranch [[label:%\w+]]
-; CHECK-NEXT: [[label]] = OpLabel
-; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
-; CHECK-NEXT: OpBranchConditional {{%\w+}} [[kill_label:%\w+]] [[label:%\w+]]
-; CHECK-NEXT: [[kill_label]] = OpLabel
-; CHECK-NEXT: OpKill
-; CHECK-NEXT: [[label]] = OpLabel
-; CHECK-NEXT: OpBranch [[loop_merge]]
-; CHECK-NEXT: [[sel_merge]] = OpLabel
-; CHECK-NEXT: OpBranch [[loop_merge]]
-; CHECK-NEXT: [[continue]] = OpLabel
-; CHECK-NEXT: OpBranchConditional
-; CHECK-NEXT: [[loop_merge]] = OpLabel
-; CHECK-NEXT: OpStore [[var]] [[ld]]
-; CHECK-NEXT: OpReturn
-; CHECK-NEXT: OpFunctionEnd
-OpCapability Shader
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main"
-OpExecutionMode %main OriginUpperLeft
-%void = OpTypeVoid
-%bool = OpTypeBool
-%true = OpConstantTrue %bool
-%bool_func_ptr = OpTypePointer Function %bool
-%voidfuncty = OpTypeFunction %void
-%main = OpFunction %void None %voidfuncty
-%1 = OpLabel
-%2 = OpVariable %bool_func_ptr Function
-%3 = OpLoad %bool %2
-%4 = OpFunctionCall %void %func
-OpStore %2 %3
-OpReturn
-OpFunctionEnd
-%func = OpFunction %void None %voidfuncty
-%5 = OpLabel
-OpSelectionMerge %6 None
-OpBranchConditional %true %7 %8
-%7 = OpLabel
-OpKill
-%8 = OpLabel
-OpReturn
-%6 = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
-}
-
-TEST_F(InlineTest, OpKillInLoop) {
- const std::string text = R"(
-; CHECK: OpFunction
-; CHECK: OpLabel
-; CHECK: [[var:%\w+]] = OpVariable
-; CHECK-NEXT: [[ld:%\w+]] = OpLoad {{%\w+}} [[var]]
-; CHECK-NEXT: OpBranch [[loop:%\w+]]
-; CHECK-NEXT: [[loop]] = OpLabel
-; CHECK-NEXT: OpLoopMerge [[loop_merge:%\w+]] [[continue:%\w+]] None
-; CHECK-NEXT: OpBranch [[label:%\w+]]
-; CHECK-NEXT: [[label]] = OpLabel
-; CHECK-NEXT: OpKill
-; CHECK-NEXT: [[loop_merge]] = OpLabel
-; CHECK-NEXT: OpBranch [[label:%\w+]]
-; CHECK-NEXT: [[continue]] = OpLabel
-; CHECK-NEXT: OpBranch [[loop]]
-; CHECK-NEXT: [[label]] = OpLabel
-; CHECK-NEXT: OpStore [[var]] [[ld]]
-; CHECK-NEXT: OpReturn
-; CHECK-NEXT: OpFunctionEnd
-OpCapability Shader
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main"
-OpExecutionMode %main OriginUpperLeft
-%void = OpTypeVoid
-%bool = OpTypeBool
-%true = OpConstantTrue %bool
-%voidfuncty = OpTypeFunction %void
-%bool_func_ptr = OpTypePointer Function %bool
-%main = OpFunction %void None %voidfuncty
-%1 = OpLabel
-%2 = OpVariable %bool_func_ptr Function
-%3 = OpLoad %bool %2
-%4 = OpFunctionCall %void %func
-OpStore %2 %3
-OpReturn
-OpFunctionEnd
-%func = OpFunction %void None %voidfuncty
-%5 = OpLabel
-OpBranch %10
-%10 = OpLabel
-OpLoopMerge %6 %7 None
-OpBranch %8
-%8 = OpLabel
-OpKill
-%6 = OpLabel
-OpReturn
-%7 = OpLabel
-OpBranch %10
-OpFunctionEnd
-)";
-
- SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
-}
-
TEST_F(InlineTest, OpVariableWithInit) {
// Check that there is a store that corresponds to the initializer. This
// test makes sure that is a store to the variable in the loop and before any
@@ -3112,6 +2936,100 @@
SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
}
+TEST_F(InlineTest, DontInlineFuncWithOpKillInContinue) {
+ const std::string test =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 330
+OpName %main "main"
+OpName %kill_ "kill("
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%main = OpFunction %void None %3
+%5 = OpLabel
+OpBranch %9
+%9 = OpLabel
+OpLoopMerge %11 %12 None
+OpBranch %13
+%13 = OpLabel
+OpBranchConditional %true %10 %11
+%10 = OpLabel
+OpBranch %12
+%12 = OpLabel
+%16 = OpFunctionCall %void %kill_
+OpBranch %9
+%11 = OpLabel
+OpReturn
+OpFunctionEnd
+%kill_ = OpFunction %void None %3
+%7 = OpLabel
+OpKill
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
+}
+
+TEST_F(InlineTest, InlineFuncWithOpKillNotInContinue) {
+ const std::string before =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 330
+OpName %main "main"
+OpName %kill_ "kill("
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%main = OpFunction %void None %3
+%5 = OpLabel
+%16 = OpFunctionCall %void %kill_
+OpReturn
+OpFunctionEnd
+%kill_ = OpFunction %void None %3
+%7 = OpLabel
+OpKill
+OpFunctionEnd
+)";
+
+ const std::string after =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 330
+OpName %main "main"
+OpName %kill_ "kill("
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%main = OpFunction %void None %3
+%5 = OpLabel
+OpKill
+%17 = OpLabel
+OpReturn
+OpFunctionEnd
+%kill_ = OpFunction %void None %3
+%7 = OpLabel
+OpKill
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndCheck<InlineExhaustivePass>(before, after, false, true);
+}
+
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// Empty modules
diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp
index 6e1adaa..b4db2d5 100644
--- a/test/opt/inst_bindless_check_test.cpp
+++ b/test/opt/inst_bindless_check_test.cpp
@@ -1915,7 +1915,7 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability RuntimeDescriptorArrayEXT
+OpCapability RuntimeDescriptorArray
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -1968,7 +1968,7 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability RuntimeDescriptorArrayEXT
+OpCapability RuntimeDescriptorArray
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -2647,9 +2647,9 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -2670,9 +2670,9 @@
OpDecorate %uniformBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %16 NonUniformEXT
-OpDecorate %20 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %16 NonUniform
+OpDecorate %20 NonUniform
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -2691,9 +2691,9 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -2715,22 +2715,22 @@
OpDecorate %uniformBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
-OpDecorate %102 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
+OpDecorate %102 NonUniform
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_31 Block
OpMemberDecorate %_struct_31 0 Offset 0
OpDecorate %33 DescriptorSet 7
OpDecorate %33 Binding 1
-OpDecorate %130 NonUniformEXT
+OpDecorate %130 NonUniform
OpDecorate %_struct_55 Block
OpMemberDecorate %_struct_55 0 Offset 0
OpMemberDecorate %_struct_55 1 Offset 4
OpDecorate %57 DescriptorSet 7
OpDecorate %57 Binding 0
OpDecorate %gl_FragCoord BuiltIn FragCoord
-OpDecorate %127 NonUniformEXT
+OpDecorate %127 NonUniform
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -2928,9 +2928,9 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -2951,9 +2951,9 @@
OpDecorate %storageBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %16 NonUniformEXT
-OpDecorate %20 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %16 NonUniform
+OpDecorate %20 NonUniform
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -2972,9 +2972,9 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -2996,22 +2996,22 @@
OpDecorate %storageBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
-OpDecorate %102 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
+OpDecorate %102 NonUniform
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_31 Block
OpMemberDecorate %_struct_31 0 Offset 0
OpDecorate %33 DescriptorSet 7
OpDecorate %33 Binding 1
-OpDecorate %130 NonUniformEXT
+OpDecorate %130 NonUniform
OpDecorate %_struct_55 Block
OpMemberDecorate %_struct_55 0 Offset 0
OpMemberDecorate %_struct_55 1 Offset 4
OpDecorate %57 DescriptorSet 7
OpDecorate %57 Binding 0
OpDecorate %gl_FragCoord BuiltIn FragCoord
-OpDecorate %127 NonUniformEXT
+OpDecorate %127 NonUniform
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -3198,9 +3198,9 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -3221,9 +3221,9 @@
OpDecorate %storageBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %16 NonUniformEXT
-OpDecorate %20 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %16 NonUniform
+OpDecorate %20 NonUniform
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -3242,9 +3242,9 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -3266,22 +3266,22 @@
OpDecorate %storageBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
-OpDecorate %102 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
+OpDecorate %102 NonUniform
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_31 Block
OpMemberDecorate %_struct_31 0 Offset 0
OpDecorate %33 DescriptorSet 7
OpDecorate %33 Binding 1
-OpDecorate %130 NonUniformEXT
+OpDecorate %130 NonUniform
OpDecorate %_struct_55 Block
OpMemberDecorate %_struct_55 0 Offset 0
OpMemberDecorate %_struct_55 1 Offset 4
OpDecorate %57 DescriptorSet 7
OpDecorate %57 Binding 0
OpDecorate %gl_FragCoord BuiltIn FragCoord
-OpDecorate %127 NonUniformEXT
+OpDecorate %127 NonUniform
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -3704,9 +3704,9 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -3726,8 +3726,8 @@
OpDecorate %storageBuffer Binding 4
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %14 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %14 NonUniform
OpDecorate %b Location 1
%void = OpTypeVoid
%3 = OpTypeFunction %void
@@ -3747,9 +3747,9 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -3770,8 +3770,8 @@
OpDecorate %storageBuffer Binding 4
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
OpDecorate %b Location 1
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_31 Block
@@ -3978,8 +3978,8 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -4000,9 +4000,9 @@
OpDecorate %uniformBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %18 NonUniformEXT
-OpDecorate %22 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %18 NonUniform
+OpDecorate %22 NonUniform
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -4023,8 +4023,8 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -4046,10 +4046,10 @@
OpDecorate %uniformBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
-OpDecorate %89 NonUniformEXT
-OpDecorate %120 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
+OpDecorate %89 NonUniform
+OpDecorate %120 NonUniform
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_39 Block
OpMemberDecorate %_struct_39 0 Offset 0
@@ -4061,7 +4061,7 @@
OpMemberDecorate %_struct_98 0 Offset 0
OpDecorate %100 DescriptorSet 7
OpDecorate %100 Binding 1
-OpDecorate %117 NonUniformEXT
+OpDecorate %117 NonUniform
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -6313,7 +6313,7 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability RuntimeDescriptorArrayEXT
+OpCapability RuntimeDescriptorArray
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -6366,7 +6366,7 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability RuntimeDescriptorArrayEXT
+OpCapability RuntimeDescriptorArray
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -6970,9 +6970,9 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -6993,9 +6993,9 @@
OpDecorate %uniformBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %16 NonUniformEXT
-OpDecorate %20 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %16 NonUniform
+OpDecorate %20 NonUniform
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -7014,9 +7014,9 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -7038,22 +7038,22 @@
OpDecorate %uniformBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
-OpDecorate %102 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
+OpDecorate %102 NonUniform
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_31 Block
OpMemberDecorate %_struct_31 0 Offset 0
OpDecorate %33 DescriptorSet 7
OpDecorate %33 Binding 1
-OpDecorate %130 NonUniformEXT
+OpDecorate %130 NonUniform
OpDecorate %_struct_55 Block
OpMemberDecorate %_struct_55 0 Offset 0
OpMemberDecorate %_struct_55 1 Offset 4
OpDecorate %57 DescriptorSet 7
OpDecorate %57 Binding 0
OpDecorate %gl_FragCoord BuiltIn FragCoord
-OpDecorate %127 NonUniformEXT
+OpDecorate %127 NonUniform
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -7251,9 +7251,9 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -7274,9 +7274,9 @@
OpDecorate %storageBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %16 NonUniformEXT
-OpDecorate %20 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %16 NonUniform
+OpDecorate %20 NonUniform
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -7295,9 +7295,9 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -7319,22 +7319,22 @@
OpDecorate %storageBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
-OpDecorate %102 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
+OpDecorate %102 NonUniform
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_31 Block
OpMemberDecorate %_struct_31 0 Offset 0
OpDecorate %33 DescriptorSet 7
OpDecorate %33 Binding 1
-OpDecorate %130 NonUniformEXT
+OpDecorate %130 NonUniform
OpDecorate %_struct_55 Block
OpMemberDecorate %_struct_55 0 Offset 0
OpMemberDecorate %_struct_55 1 Offset 4
OpDecorate %57 DescriptorSet 7
OpDecorate %57 Binding 0
OpDecorate %gl_FragCoord BuiltIn FragCoord
-OpDecorate %127 NonUniformEXT
+OpDecorate %127 NonUniform
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -7521,9 +7521,9 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -7544,9 +7544,9 @@
OpDecorate %storageBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %16 NonUniformEXT
-OpDecorate %20 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %16 NonUniform
+OpDecorate %20 NonUniform
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -7565,9 +7565,9 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -7589,22 +7589,22 @@
OpDecorate %storageBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
-OpDecorate %102 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
+OpDecorate %102 NonUniform
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_31 Block
OpMemberDecorate %_struct_31 0 Offset 0
OpDecorate %33 DescriptorSet 7
OpDecorate %33 Binding 1
-OpDecorate %130 NonUniformEXT
+OpDecorate %130 NonUniform
OpDecorate %_struct_55 Block
OpMemberDecorate %_struct_55 0 Offset 0
OpMemberDecorate %_struct_55 1 Offset 4
OpDecorate %57 DescriptorSet 7
OpDecorate %57 Binding 0
OpDecorate %gl_FragCoord BuiltIn FragCoord
-OpDecorate %127 NonUniformEXT
+OpDecorate %127 NonUniform
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -8027,9 +8027,9 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -8049,8 +8049,8 @@
OpDecorate %storageBuffer Binding 4
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %14 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %14 NonUniform
OpDecorate %b Location 1
%void = OpTypeVoid
%3 = OpTypeFunction %void
@@ -8070,9 +8070,9 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability RuntimeDescriptorArrayEXT
-OpCapability StorageBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability RuntimeDescriptorArray
+OpCapability StorageBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -8093,8 +8093,8 @@
OpDecorate %storageBuffer Binding 4
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
OpDecorate %b Location 1
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_31 Block
@@ -8301,8 +8301,8 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -8323,9 +8323,9 @@
OpDecorate %uniformBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %18 NonUniformEXT
-OpDecorate %22 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %18 NonUniform
+OpDecorate %22 NonUniform
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -8346,8 +8346,8 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
-OpCapability UniformBufferArrayNonUniformIndexingEXT
+OpCapability ShaderNonUniform
+OpCapability UniformBufferArrayNonUniformIndexing
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -8369,10 +8369,10 @@
OpDecorate %uniformBuffer Binding 3
OpDecorate %nu_ii Flat
OpDecorate %nu_ii Location 0
-OpDecorate %nu_ii NonUniformEXT
-OpDecorate %7 NonUniformEXT
-OpDecorate %89 NonUniformEXT
-OpDecorate %120 NonUniformEXT
+OpDecorate %nu_ii NonUniform
+OpDecorate %7 NonUniform
+OpDecorate %89 NonUniform
+OpDecorate %120 NonUniform
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %_struct_39 Block
OpMemberDecorate %_struct_39 0 Offset 0
@@ -8384,7 +8384,7 @@
OpMemberDecorate %_struct_98 0 Offset 0
OpDecorate %100 DescriptorSet 7
OpDecorate %100 Binding 1
-OpDecorate %117 NonUniformEXT
+OpDecorate %117 NonUniform
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
@@ -8575,7 +8575,7 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability RuntimeDescriptorArrayEXT
+OpCapability RuntimeDescriptorArray
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -8622,7 +8622,7 @@
const std::string defs_after =
R"(OpCapability Shader
-OpCapability RuntimeDescriptorArrayEXT
+OpCapability RuntimeDescriptorArray
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
@@ -8895,7 +8895,7 @@
// }
const std::string defs_before =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -8923,7 +8923,7 @@
)";
const std::string defs_after =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -9219,7 +9219,7 @@
// }
const std::string defs_before =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -9247,7 +9247,7 @@
)";
const std::string defs_after =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -9543,7 +9543,7 @@
// }
const std::string defs_before =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -9571,7 +9571,7 @@
)";
const std::string defs_after =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -9867,7 +9867,7 @@
// }
const std::string defs_before =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -9895,7 +9895,7 @@
)";
const std::string defs_after =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -10191,7 +10191,7 @@
// }
const std::string defs_before =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -10219,7 +10219,7 @@
)";
const std::string defs_after =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -10515,7 +10515,7 @@
// }
const std::string defs_before =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -10543,7 +10543,7 @@
)";
const std::string defs_after =
- R"(OpCapability RuntimeDescriptorArrayEXT
+ R"(OpCapability RuntimeDescriptorArray
OpCapability RayTracingNV
OpExtension "SPV_EXT_descriptor_indexing"
OpExtension "SPV_NV_ray_tracing"
@@ -10820,6 +10820,415 @@
true, 7u, 23u, true, true, 2u);
}
+TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) {
+ // Test that same block ops like OpSampledImage are replicated properly
+ // where needed.
+ //
+ // clang-format off
+ //
+ // #version 450 core
+ // #extension GL_EXT_nonuniform_qualifier : enable
+ //
+ // layout(location = 0) in vec2 inTexcoord;
+ // layout(location = 0) out vec4 outColor;
+ //
+ // layout(set = 0, binding = 0) uniform Uniforms {
+ // vec2 var0;
+ // } uniforms;
+ //
+ // layout(set = 0, binding = 1) uniform sampler uniformSampler;
+ // layout(set = 0, binding = 2) uniform texture2D uniformTex;
+ // layout(set = 0, binding = 3) uniform texture2D uniformTexArr[8];
+ //
+ // void main() {
+ // int index = 0;
+ // float x = texture(sampler2D(uniformTexArr[nonuniformEXT(index)], uniformSampler), inTexcoord.xy).x;
+ // float y = texture(sampler2D(uniformTex, uniformSampler), inTexcoord.xy * uniforms.var0.xy).x;
+ // outColor = vec4(x, y, 0.0, 0.0);
+ // }
+ //
+ // clang-format on
+
+ const std::string defs_before =
+ R"(OpCapability Shader
+OpCapability ShaderNonUniformEXT
+OpCapability SampledImageArrayNonUniformIndexingEXT
+OpExtension "SPV_EXT_descriptor_indexing"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %inTexcoord %outColor
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpName %main "main"
+OpName %index "index"
+OpName %x "x"
+OpName %uniformTexArr "uniformTexArr"
+OpName %uniformSampler "uniformSampler"
+OpName %inTexcoord "inTexcoord"
+OpName %y "y"
+OpName %uniformTex "uniformTex"
+OpName %Uniforms "Uniforms"
+OpMemberName %Uniforms 0 "var0"
+OpName %uniforms "uniforms"
+OpName %outColor "outColor"
+OpDecorate %uniformTexArr DescriptorSet 0
+OpDecorate %uniformTexArr Binding 3
+OpDecorate %19 NonUniformEXT
+OpDecorate %22 NonUniformEXT
+OpDecorate %uniformSampler DescriptorSet 0
+OpDecorate %uniformSampler Binding 1
+OpDecorate %inTexcoord Location 0
+OpDecorate %uniformTex DescriptorSet 0
+OpDecorate %uniformTex Binding 2
+OpMemberDecorate %Uniforms 0 Offset 0
+OpDecorate %Uniforms Block
+OpDecorate %uniforms DescriptorSet 0
+OpDecorate %uniforms Binding 0
+OpDecorate %outColor Location 0
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%_ptr_Function_float = OpTypePointer Function %float
+%13 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%uint = OpTypeInt 32 0
+%uint_8 = OpConstant %uint 8
+%_arr_13_uint_8 = OpTypeArray %13 %uint_8
+%_ptr_UniformConstant__arr_13_uint_8 = OpTypePointer UniformConstant %_arr_13_uint_8
+%uniformTexArr = OpVariable %_ptr_UniformConstant__arr_13_uint_8 UniformConstant
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%23 = OpTypeSampler
+%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23
+%uniformSampler = OpVariable %_ptr_UniformConstant_23 UniformConstant
+%27 = OpTypeSampledImage %13
+%v2float = OpTypeVector %float 2
+%_ptr_Input_v2float = OpTypePointer Input %v2float
+%inTexcoord = OpVariable %_ptr_Input_v2float Input
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uniformTex = OpVariable %_ptr_UniformConstant_13 UniformConstant
+%Uniforms = OpTypeStruct %v2float
+%_ptr_Uniform_Uniforms = OpTypePointer Uniform %Uniforms
+%uniforms = OpVariable %_ptr_Uniform_Uniforms Uniform
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%outColor = OpVariable %_ptr_Output_v4float Output
+%float_0 = OpConstant %float 0
+)";
+
+ const std::string defs_after =
+ R"(OpCapability Shader
+OpCapability ShaderNonUniform
+OpCapability SampledImageArrayNonUniformIndexing
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %inTexcoord %outColor %gl_FragCoord
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpName %main "main"
+OpName %index "index"
+OpName %x "x"
+OpName %uniformTexArr "uniformTexArr"
+OpName %uniformSampler "uniformSampler"
+OpName %inTexcoord "inTexcoord"
+OpName %y "y"
+OpName %uniformTex "uniformTex"
+OpName %Uniforms "Uniforms"
+OpMemberName %Uniforms 0 "var0"
+OpName %uniforms "uniforms"
+OpName %outColor "outColor"
+OpDecorate %uniformTexArr DescriptorSet 0
+OpDecorate %uniformTexArr Binding 3
+OpDecorate %19 NonUniform
+OpDecorate %22 NonUniform
+OpDecorate %uniformSampler DescriptorSet 0
+OpDecorate %uniformSampler Binding 1
+OpDecorate %inTexcoord Location 0
+OpDecorate %uniformTex DescriptorSet 0
+OpDecorate %uniformTex Binding 2
+OpMemberDecorate %Uniforms 0 Offset 0
+OpDecorate %Uniforms Block
+OpDecorate %uniforms DescriptorSet 0
+OpDecorate %uniforms Binding 0
+OpDecorate %outColor Location 0
+OpDecorate %63 NonUniform
+OpDecorate %_runtimearr_uint ArrayStride 4
+OpDecorate %_struct_75 Block
+OpMemberDecorate %_struct_75 0 Offset 0
+OpMemberDecorate %_struct_75 1 Offset 4
+OpDecorate %77 DescriptorSet 7
+OpDecorate %77 Binding 0
+OpDecorate %gl_FragCoord BuiltIn FragCoord
+OpDecorate %_struct_132 Block
+OpMemberDecorate %_struct_132 0 Offset 0
+OpDecorate %134 DescriptorSet 7
+OpDecorate %134 Binding 1
+OpDecorate %151 NonUniform
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%_ptr_Function_float = OpTypePointer Function %float
+%13 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%uint = OpTypeInt 32 0
+%uint_8 = OpConstant %uint 8
+%_arr_13_uint_8 = OpTypeArray %13 %uint_8
+%_ptr_UniformConstant__arr_13_uint_8 = OpTypePointer UniformConstant %_arr_13_uint_8
+%uniformTexArr = OpVariable %_ptr_UniformConstant__arr_13_uint_8 UniformConstant
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%23 = OpTypeSampler
+%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23
+%uniformSampler = OpVariable %_ptr_UniformConstant_23 UniformConstant
+%27 = OpTypeSampledImage %13
+%v2float = OpTypeVector %float 2
+%_ptr_Input_v2float = OpTypePointer Input %v2float
+%inTexcoord = OpVariable %_ptr_Input_v2float Input
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uniformTex = OpVariable %_ptr_UniformConstant_13 UniformConstant
+%Uniforms = OpTypeStruct %v2float
+%_ptr_Uniform_Uniforms = OpTypePointer Uniform %Uniforms
+%uniforms = OpVariable %_ptr_Uniform_Uniforms Uniform
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%outColor = OpVariable %_ptr_Output_v4float Output
+%float_0 = OpConstant %float 0
+%bool = OpTypeBool
+%68 = OpTypeFunction %void %uint %uint %uint %uint
+%_runtimearr_uint = OpTypeRuntimeArray %uint
+%_struct_75 = OpTypeStruct %uint %_runtimearr_uint
+%_ptr_StorageBuffer__struct_75 = OpTypePointer StorageBuffer %_struct_75
+%77 = OpVariable %_ptr_StorageBuffer__struct_75 StorageBuffer
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+%uint_10 = OpConstant %uint 10
+%uint_4 = OpConstant %uint 4
+%uint_1 = OpConstant %uint 1
+%uint_23 = OpConstant %uint 23
+%uint_2 = OpConstant %uint 2
+%uint_3 = OpConstant %uint 3
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+%v4uint = OpTypeVector %uint 4
+%uint_5 = OpConstant %uint 5
+%uint_7 = OpConstant %uint 7
+%uint_9 = OpConstant %uint 9
+%uint_79 = OpConstant %uint 79
+%122 = OpConstantNull %v4float
+%126 = OpTypeFunction %uint %uint %uint %uint %uint
+%_struct_132 = OpTypeStruct %_runtimearr_uint
+%_ptr_StorageBuffer__struct_132 = OpTypePointer StorageBuffer %_struct_132
+%134 = OpVariable %_ptr_StorageBuffer__struct_132 StorageBuffer
+%uint_87 = OpConstant %uint 87
+%165 = OpConstantNull %v2float
+%uint_89 = OpConstant %uint 89
+)";
+
+ const std::string func_before =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%index = OpVariable %_ptr_Function_int Function
+%x = OpVariable %_ptr_Function_float Function
+%y = OpVariable %_ptr_Function_float Function
+OpStore %index %int_0
+%19 = OpLoad %int %index
+%21 = OpAccessChain %_ptr_UniformConstant_13 %uniformTexArr %19
+%22 = OpLoad %13 %21
+%26 = OpLoad %23 %uniformSampler
+%28 = OpSampledImage %27 %22 %26
+%32 = OpLoad %v2float %inTexcoord
+%34 = OpImageSampleImplicitLod %v4float %28 %32
+%36 = OpCompositeExtract %float %34 0
+OpStore %x %36
+%39 = OpLoad %13 %uniformTex
+%40 = OpLoad %23 %uniformSampler
+%41 = OpSampledImage %27 %39 %40
+%42 = OpLoad %v2float %inTexcoord
+%47 = OpAccessChain %_ptr_Uniform_v2float %uniforms %int_0
+%48 = OpLoad %v2float %47
+%49 = OpFMul %v2float %42 %48
+%50 = OpImageSampleImplicitLod %v4float %41 %49
+%51 = OpCompositeExtract %float %50 0
+OpStore %y %51
+%54 = OpLoad %float %x
+%55 = OpLoad %float %y
+%57 = OpCompositeConstruct %v4float %54 %55 %float_0 %float_0
+OpStore %outColor %57
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string func_after =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%index = OpVariable %_ptr_Function_int Function
+%x = OpVariable %_ptr_Function_float Function
+%y = OpVariable %_ptr_Function_float Function
+OpStore %index %int_0
+%19 = OpLoad %int %index
+%21 = OpAccessChain %_ptr_UniformConstant_13 %uniformTexArr %19
+%22 = OpLoad %13 %21
+%26 = OpLoad %23 %uniformSampler
+%28 = OpSampledImage %27 %22 %26
+%32 = OpLoad %v2float %inTexcoord
+%59 = OpULessThan %bool %19 %uint_8
+OpSelectionMerge %60 None
+OpBranchConditional %59 %61 %62
+%61 = OpLabel
+%63 = OpLoad %13 %21
+%64 = OpSampledImage %27 %63 %26
+%124 = OpBitcast %uint %19
+%146 = OpFunctionCall %uint %125 %uint_0 %uint_0 %uint_3 %124
+%147 = OpINotEqual %bool %146 %uint_0
+OpSelectionMerge %148 None
+OpBranchConditional %147 %149 %150
+%149 = OpLabel
+%151 = OpLoad %13 %21
+%152 = OpSampledImage %27 %151 %26
+%153 = OpImageSampleImplicitLod %v4float %152 %32
+OpBranch %148
+%150 = OpLabel
+%154 = OpBitcast %uint %19
+%155 = OpFunctionCall %void %67 %uint_79 %uint_1 %154 %uint_0
+OpBranch %148
+%148 = OpLabel
+%156 = OpPhi %v4float %153 %149 %122 %150
+OpBranch %60
+%62 = OpLabel
+%66 = OpBitcast %uint %19
+%121 = OpFunctionCall %void %67 %uint_79 %uint_0 %66 %uint_8
+OpBranch %60
+%60 = OpLabel
+%123 = OpPhi %v4float %156 %148 %122 %62
+%36 = OpCompositeExtract %float %123 0
+OpStore %x %36
+%39 = OpLoad %13 %uniformTex
+%40 = OpLoad %23 %uniformSampler
+%41 = OpSampledImage %27 %39 %40
+%42 = OpLoad %v2float %inTexcoord
+%47 = OpAccessChain %_ptr_Uniform_v2float %uniforms %int_0
+%157 = OpFunctionCall %uint %125 %uint_0 %uint_0 %uint_0 %uint_0
+%158 = OpINotEqual %bool %157 %uint_0
+OpSelectionMerge %159 None
+OpBranchConditional %158 %160 %161
+%160 = OpLabel
+%162 = OpLoad %v2float %47
+OpBranch %159
+%161 = OpLabel
+%164 = OpFunctionCall %void %67 %uint_87 %uint_1 %uint_0 %uint_0
+OpBranch %159
+%159 = OpLabel
+%166 = OpPhi %v2float %162 %160 %165 %161
+%49 = OpFMul %v2float %42 %166
+%167 = OpSampledImage %27 %39 %40
+%168 = OpFunctionCall %uint %125 %uint_0 %uint_0 %uint_2 %uint_0
+%169 = OpINotEqual %bool %168 %uint_0
+OpSelectionMerge %170 None
+OpBranchConditional %169 %171 %172
+%171 = OpLabel
+%173 = OpLoad %13 %uniformTex
+%174 = OpSampledImage %27 %173 %40
+%175 = OpImageSampleImplicitLod %v4float %174 %49
+OpBranch %170
+%172 = OpLabel
+%177 = OpFunctionCall %void %67 %uint_89 %uint_1 %uint_0 %uint_0
+OpBranch %170
+%170 = OpLabel
+%178 = OpPhi %v4float %175 %171 %122 %172
+%51 = OpCompositeExtract %float %178 0
+OpStore %y %51
+%54 = OpLoad %float %x
+%55 = OpLoad %float %y
+%57 = OpCompositeConstruct %v4float %54 %55 %float_0 %float_0
+OpStore %outColor %57
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string new_funcs =
+ R"(%67 = OpFunction %void None %68
+%69 = OpFunctionParameter %uint
+%70 = OpFunctionParameter %uint
+%71 = OpFunctionParameter %uint
+%72 = OpFunctionParameter %uint
+%73 = OpLabel
+%79 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_0
+%82 = OpAtomicIAdd %uint %79 %uint_4 %uint_0 %uint_10
+%83 = OpIAdd %uint %82 %uint_10
+%84 = OpArrayLength %uint %77 1
+%85 = OpULessThanEqual %bool %83 %84
+OpSelectionMerge %86 None
+OpBranchConditional %85 %87 %86
+%87 = OpLabel
+%88 = OpIAdd %uint %82 %uint_0
+%90 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %88
+OpStore %90 %uint_10
+%92 = OpIAdd %uint %82 %uint_1
+%93 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %92
+OpStore %93 %uint_23
+%95 = OpIAdd %uint %82 %uint_2
+%96 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %95
+OpStore %96 %69
+%98 = OpIAdd %uint %82 %uint_3
+%99 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %98
+OpStore %99 %uint_4
+%102 = OpLoad %v4float %gl_FragCoord
+%104 = OpBitcast %v4uint %102
+%105 = OpCompositeExtract %uint %104 0
+%106 = OpIAdd %uint %82 %uint_4
+%107 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %106
+OpStore %107 %105
+%108 = OpCompositeExtract %uint %104 1
+%110 = OpIAdd %uint %82 %uint_5
+%111 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %110
+OpStore %111 %108
+%113 = OpIAdd %uint %82 %uint_7
+%114 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %113
+OpStore %114 %70
+%115 = OpIAdd %uint %82 %uint_8
+%116 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %115
+OpStore %116 %71
+%118 = OpIAdd %uint %82 %uint_9
+%119 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %118
+OpStore %119 %72
+OpBranch %86
+%86 = OpLabel
+OpReturn
+OpFunctionEnd
+%125 = OpFunction %uint None %126
+%127 = OpFunctionParameter %uint
+%128 = OpFunctionParameter %uint
+%129 = OpFunctionParameter %uint
+%130 = OpFunctionParameter %uint
+%131 = OpLabel
+%135 = OpAccessChain %_ptr_StorageBuffer_uint %134 %uint_0 %127
+%136 = OpLoad %uint %135
+%137 = OpIAdd %uint %136 %128
+%138 = OpAccessChain %_ptr_StorageBuffer_uint %134 %uint_0 %137
+%139 = OpLoad %uint %138
+%140 = OpIAdd %uint %139 %129
+%141 = OpAccessChain %_ptr_StorageBuffer_uint %134 %uint_0 %140
+%142 = OpLoad %uint %141
+%143 = OpIAdd %uint %142 %130
+%144 = OpAccessChain %_ptr_StorageBuffer_uint %134 %uint_0 %143
+%145 = OpLoad %uint %144
+OpReturnValue %145
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndCheck<InstBindlessCheckPass>(
+ defs_before + func_before, defs_after + func_after + new_funcs, true,
+ true, 7u, 23u, true, true, 2u);
+}
+
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// Compute shader
diff --git a/test/opt/inst_buff_addr_check_test.cpp b/test/opt/inst_buff_addr_check_test.cpp
index c31266e..f8448a9 100644
--- a/test/opt/inst_buff_addr_check_test.cpp
+++ b/test/opt/inst_buff_addr_check_test.cpp
@@ -51,10 +51,10 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpExtension "SPV_EXT_physical_storage_buffer"
%1 = OpExtInstImport "GLSL.std.450"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 450
@@ -78,31 +78,31 @@
OpDecorate %u_info Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
-OpTypeForwardPointer %_ptr_PhysicalStorageBufferEXT_bufStruct PhysicalStorageBufferEXT
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
%uint = OpTypeInt 32 0
-%ufoo = OpTypeStruct %_ptr_PhysicalStorageBufferEXT_bufStruct %uint
+%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint
%int = OpTypeInt 32 1
%uint_2 = OpConstant %uint 2
%_arr_int_uint_2 = OpTypeArray %int %uint_2
%bufStruct = OpTypeStruct %_arr_int_uint_2 %int
-%_ptr_PhysicalStorageBufferEXT_bufStruct = OpTypePointer PhysicalStorageBufferEXT %bufStruct
+%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
%u_info = OpVariable %_ptr_Uniform_ufoo Uniform
%int_0 = OpConstant %int 0
-%_ptr_Uniform__ptr_PhysicalStorageBufferEXT_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBufferEXT_bufStruct
+%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
%int_1 = OpConstant %int 1
%int_3239 = OpConstant %int 3239
-%_ptr_PhysicalStorageBufferEXT_int = OpTypePointer PhysicalStorageBufferEXT %int
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
)";
const std::string defs_after =
R"(OpCapability Shader
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpExtension "SPV_EXT_physical_storage_buffer"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 450
@@ -138,21 +138,21 @@
OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
%void = OpTypeVoid
%8 = OpTypeFunction %void
-OpTypeForwardPointer %_ptr_PhysicalStorageBufferEXT_bufStruct PhysicalStorageBufferEXT
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
%uint = OpTypeInt 32 0
-%ufoo = OpTypeStruct %_ptr_PhysicalStorageBufferEXT_bufStruct %uint
+%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint
%int = OpTypeInt 32 1
%uint_2 = OpConstant %uint 2
%_arr_int_uint_2 = OpTypeArray %int %uint_2
%bufStruct = OpTypeStruct %_arr_int_uint_2 %int
-%_ptr_PhysicalStorageBufferEXT_bufStruct = OpTypePointer PhysicalStorageBufferEXT %bufStruct
+%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
%u_info = OpVariable %_ptr_Uniform_ufoo Uniform
%int_0 = OpConstant %int 0
-%_ptr_Uniform__ptr_PhysicalStorageBufferEXT_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBufferEXT_bufStruct
+%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
%int_1 = OpConstant %int 1
%int_3239 = OpConstant %int 3239
-%_ptr_PhysicalStorageBufferEXT_int = OpTypePointer PhysicalStorageBufferEXT %int
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
%ulong = OpTypeInt 64 0
%uint_4 = OpConstant %uint 4
%bool = OpTypeBool
@@ -188,9 +188,9 @@
const std::string func_before =
R"(%main = OpFunction %void None %3
%5 = OpLabel
-%17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBufferEXT_bufStruct %u_info %int_0
-%18 = OpLoad %_ptr_PhysicalStorageBufferEXT_bufStruct %17
-%22 = OpAccessChain %_ptr_PhysicalStorageBufferEXT_int %18 %int_1
+%17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
+%18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
+%22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
OpStore %22 %int_3239 Aligned 16
OpReturn
OpFunctionEnd
@@ -199,9 +199,9 @@
const std::string func_after =
R"(%main = OpFunction %void None %8
%19 = OpLabel
-%20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBufferEXT_bufStruct %u_info %int_0
-%21 = OpLoad %_ptr_PhysicalStorageBufferEXT_bufStruct %20
-%22 = OpAccessChain %_ptr_PhysicalStorageBufferEXT_int %21 %int_1
+%20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
+%21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20
+%22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1
%24 = OpConvertPtrToU %ulong %22
%61 = OpFunctionCall %bool %26 %24 %uint_4
OpSelectionMerge %62 None
@@ -339,11 +339,11 @@
const std::string defs_before =
R"(OpCapability Shader
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpExtension "SPV_EXT_physical_storage_buffer"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 450
@@ -364,29 +364,29 @@
OpDecorate %r Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
-OpTypeForwardPointer %_ptr_PhysicalStorageBufferEXT_blockType PhysicalStorageBufferEXT
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer
%int = OpTypeInt 32 1
-%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBufferEXT_blockType
-%_ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer PhysicalStorageBufferEXT %blockType
-%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBufferEXT_blockType
+%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType
+%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType
+%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType
%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock
%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer
%int_0 = OpConstant %int 0
-%_ptr_StorageBuffer__ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBufferEXT_blockType
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType
%int_1 = OpConstant %int 1
-%_ptr_PhysicalStorageBufferEXT__ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer PhysicalStorageBufferEXT %_ptr_PhysicalStorageBufferEXT_blockType
+%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
%int_531 = OpConstant %int 531
-%_ptr_PhysicalStorageBufferEXT_int = OpTypePointer PhysicalStorageBufferEXT %int
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
)";
const std::string defs_after =
R"(OpCapability Shader
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpExtension "SPV_EXT_physical_storage_buffer"
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 450
@@ -419,19 +419,19 @@
OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
%void = OpTypeVoid
%3 = OpTypeFunction %void
-OpTypeForwardPointer %_ptr_PhysicalStorageBufferEXT_blockType PhysicalStorageBufferEXT
+OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer
%int = OpTypeInt 32 1
-%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBufferEXT_blockType
-%_ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer PhysicalStorageBufferEXT %blockType
-%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBufferEXT_blockType
+%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType
+%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType
+%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType
%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock
%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer
%int_0 = OpConstant %int 0
-%_ptr_StorageBuffer__ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBufferEXT_blockType
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType
%int_1 = OpConstant %int 1
-%_ptr_PhysicalStorageBufferEXT__ptr_PhysicalStorageBufferEXT_blockType = OpTypePointer PhysicalStorageBufferEXT %_ptr_PhysicalStorageBufferEXT_blockType
+%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
%int_531 = OpConstant %int 531
-%_ptr_PhysicalStorageBufferEXT_int = OpTypePointer PhysicalStorageBufferEXT %int
+%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
%uint = OpTypeInt 32 0
%uint_2 = OpConstant %uint 2
%ulong = OpTypeInt 64 0
@@ -464,18 +464,18 @@
%uint_7 = OpConstant %uint 7
%uint_9 = OpConstant %uint 9
%uint_44 = OpConstant %uint 44
-%132 = OpConstantNull %_ptr_PhysicalStorageBufferEXT_blockType
+%132 = OpConstantNull %ulong
%uint_46 = OpConstant %uint 46
)";
const std::string func_before =
R"(%main = OpFunction %void None %3
%5 = OpLabel
-%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBufferEXT_blockType %r %int_0
-%17 = OpLoad %_ptr_PhysicalStorageBufferEXT_blockType %16
-%21 = OpAccessChain %_ptr_PhysicalStorageBufferEXT__ptr_PhysicalStorageBufferEXT_blockType %17 %int_1
-%22 = OpLoad %_ptr_PhysicalStorageBufferEXT_blockType %21 Aligned 8
-%26 = OpAccessChain %_ptr_PhysicalStorageBufferEXT_int %22 %int_0
+%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0
+%17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16
+%21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1
+%22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
+%26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
OpStore %26 %int_531 Aligned 16
OpReturn
OpFunctionEnd
@@ -484,39 +484,40 @@
const std::string func_after =
R"(%main = OpFunction %void None %3
%5 = OpLabel
-%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBufferEXT_blockType %r %int_0
-%17 = OpLoad %_ptr_PhysicalStorageBufferEXT_blockType %16
-%21 = OpAccessChain %_ptr_PhysicalStorageBufferEXT__ptr_PhysicalStorageBufferEXT_blockType %17 %int_1
+%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0
+%17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16
+%21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1
%30 = OpConvertPtrToU %ulong %21
%67 = OpFunctionCall %bool %32 %30 %uint_8
OpSelectionMerge %68 None
OpBranchConditional %67 %69 %70
%69 = OpLabel
-%71 = OpLoad %_ptr_PhysicalStorageBufferEXT_blockType %21 Aligned 8
+%71 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
OpBranch %68
%70 = OpLabel
%72 = OpUConvert %uint %30
%74 = OpShiftRightLogical %ulong %30 %uint_32
%75 = OpUConvert %uint %74
%131 = OpFunctionCall %void %76 %uint_44 %uint_2 %72 %75
+%133 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %132
OpBranch %68
%68 = OpLabel
-%133 = OpPhi %_ptr_PhysicalStorageBufferEXT_blockType %71 %69 %132 %70
-%26 = OpAccessChain %_ptr_PhysicalStorageBufferEXT_int %133 %int_0
-%134 = OpConvertPtrToU %ulong %26
-%135 = OpFunctionCall %bool %32 %134 %uint_4
-OpSelectionMerge %136 None
-OpBranchConditional %135 %137 %138
-%137 = OpLabel
-OpStore %26 %int_531 Aligned 16
-OpBranch %136
+%134 = OpPhi %_ptr_PhysicalStorageBuffer_blockType %71 %69 %133 %70
+%26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %134 %int_0
+%135 = OpConvertPtrToU %ulong %26
+%136 = OpFunctionCall %bool %32 %135 %uint_4
+OpSelectionMerge %137 None
+OpBranchConditional %136 %138 %139
%138 = OpLabel
-%139 = OpUConvert %uint %134
-%140 = OpShiftRightLogical %ulong %134 %uint_32
-%141 = OpUConvert %uint %140
-%143 = OpFunctionCall %void %76 %uint_46 %uint_2 %139 %141
-OpBranch %136
-%136 = OpLabel
+OpStore %26 %int_531 Aligned 16
+OpBranch %137
+%139 = OpLabel
+%140 = OpUConvert %uint %135
+%141 = OpShiftRightLogical %ulong %135 %uint_32
+%142 = OpUConvert %uint %141
+%144 = OpFunctionCall %void %76 %uint_46 %uint_2 %140 %142
+OpBranch %137
+%137 = OpLabel
OpReturn
OpFunctionEnd
)";
diff --git a/test/opt/ir_context_test.cpp b/test/opt/ir_context_test.cpp
index 4e2f5b2..d5710fc 100644
--- a/test/opt/ir_context_test.cpp
+++ b/test/opt/ir_context_test.cpp
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "source/opt/ir_context.h"
+
#include <algorithm>
#include <memory>
#include <string>
@@ -19,7 +21,6 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include "source/opt/ir_context.h"
#include "source/opt/pass.h"
#include "test/opt/pass_fixture.h"
#include "test/opt/pass_utils.h"
@@ -664,6 +665,90 @@
EXPECT_EQ(next_id_bound, 0);
EXPECT_EQ(current_bound, context->module()->id_bound());
}
+
+TEST_F(IRContextTest, CfgAndDomAnalysis) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%3 = OpFunction %1 None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd)";
+
+ std::unique_ptr<IRContext> ctx =
+ BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ // Building the dominator analysis should build the CFG.
+ ASSERT_TRUE(ctx->module()->begin() != ctx->module()->end());
+ ctx->GetDominatorAnalysis(&*ctx->module()->begin());
+
+ EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisCFG));
+ EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisDominatorAnalysis));
+
+ // Invalidating the CFG analysis should invalidate the dominator analysis.
+ ctx->InvalidateAnalyses(IRContext::kAnalysisCFG);
+ EXPECT_FALSE(ctx->AreAnalysesValid(IRContext::kAnalysisCFG));
+ EXPECT_FALSE(ctx->AreAnalysesValid(IRContext::kAnalysisDominatorAnalysis));
+}
+
+TEST_F(IRContextTest, AsanErrorTest) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "x"
+ OpName %10 "y"
+ OpDecorate %8 RelaxedPrecision
+ OpDecorate %10 RelaxedPrecision
+ OpDecorate %11 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %10 = OpVariable %7 Function
+ OpStore %8 %9
+ %11 = OpLoad %6 %8
+ OpBranch %20
+ %20 = OpLabel
+ %21 = OpPhi %6 %11 %5
+ OpStore %10 %21
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(
+ env, consumer, shader, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ opt::Function* fun =
+ context->cfg()->block(5)->GetParent(); // Computes the CFG analysis
+ opt::DominatorAnalysis* dom = nullptr;
+ dom = context->GetDominatorAnalysis(fun); // Computes the dominator analysis,
+ // which depends on the CFG
+ // analysis
+ context->InvalidateAnalysesExceptFor(
+ opt::IRContext::Analysis::kAnalysisDominatorAnalysis); // Invalidates the
+ // CFG analysis
+ dom = context->GetDominatorAnalysis(
+ fun); // Recompute the CFG analysis because the Dominator tree uses it.
+ auto bb = dom->ImmediateDominator(5);
+ std::cout
+ << bb->id(); // Make sure asan does not complain about use after free.
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/legalize_vector_shuffle_test.cpp b/test/opt/legalize_vector_shuffle_test.cpp
index 8b9695b..07d96eb 100644
--- a/test/opt/legalize_vector_shuffle_test.cpp
+++ b/test/opt/legalize_vector_shuffle_test.cpp
@@ -34,9 +34,9 @@
std::vector<const char*> header = {
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
"%v3uint = OpTypeVector %uint 3"};
diff --git a/test/opt/local_access_chain_convert_test.cpp b/test/opt/local_access_chain_convert_test.cpp
index 1b75b36..39899e3 100644
--- a/test/opt/local_access_chain_convert_test.cpp
+++ b/test/opt/local_access_chain_convert_test.cpp
@@ -820,6 +820,113 @@
SinglePassRunAndCheck<LocalAccessChainConvertPass>(test, test, false, true);
}
+TEST_F(LocalAccessChainConvertTest, IdOverflowReplacingLoad) {
+ const std::string text =
+ R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "PSMain"
+ OpExecutionMode %4 OriginUpperLeft
+ OpDecorate %10 Location 47360
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %_struct_8 = OpTypeStruct %v4float
+%_ptr_Function__struct_8 = OpTypePointer Function %_struct_8
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %4 = OpFunction %void None %3
+ %5 = OpLabel
+ %10 = OpVariable %_ptr_Function__struct_8 Function
+ %4194301 = OpAccessChain %_ptr_Function_v4float %10 %int_0
+ %4194302 = OpLoad %v4float %4194301
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ std::vector<Message> messages = {
+ {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
+ SetMessageConsumer(GetTestMessageConsumer(messages));
+ auto result = SinglePassRunToBinary<LocalAccessChainConvertPass>(text, true);
+ EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
+}
+
+TEST_F(LocalAccessChainConvertTest, IdOverflowReplacingStore1) {
+ const std::string text =
+ R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "PSMain"
+ OpExecutionMode %4 OriginUpperLeft
+ OpDecorate %10 Location 47360
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %_struct_7 = OpTypeStruct %v4float
+%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %13 = OpConstantNull %v4float
+ %4 = OpFunction %void None %3
+ %5 = OpLabel
+ %10 = OpVariable %_ptr_Function__struct_7 Function
+ %4194302 = OpAccessChain %_ptr_Function_v4float %10 %int_0
+ OpStore %4194302 %13
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ std::vector<Message> messages = {
+ {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
+ SetMessageConsumer(GetTestMessageConsumer(messages));
+ auto result = SinglePassRunToBinary<LocalAccessChainConvertPass>(text, true);
+ EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
+}
+
+TEST_F(LocalAccessChainConvertTest, IdOverflowReplacingStore2) {
+ const std::string text =
+ R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "PSMain"
+ OpExecutionMode %4 OriginUpperLeft
+ OpDecorate %10 Location 47360
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %_struct_7 = OpTypeStruct %v4float
+%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %13 = OpConstantNull %v4float
+ %4 = OpFunction %void None %3
+ %5 = OpLabel
+ %10 = OpVariable %_ptr_Function__struct_7 Function
+ %4194301 = OpAccessChain %_ptr_Function_v4float %10 %int_0
+ OpStore %4194301 %13
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ std::vector<Message> messages = {
+ {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
+ SetMessageConsumer(GetTestMessageConsumer(messages));
+ auto result = SinglePassRunToBinary<LocalAccessChainConvertPass>(text, true);
+ EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
+}
+
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// Assorted vector and matrix types
diff --git a/test/opt/local_ssa_elim_test.cpp b/test/opt/local_ssa_elim_test.cpp
index a490d52..f10d118 100644
--- a/test/opt/local_ssa_elim_test.cpp
+++ b/test/opt/local_ssa_elim_test.cpp
@@ -138,8 +138,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
- predefs + after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
+ true);
}
TEST_F(LocalSSAElimTest, NestedForLoop) {
@@ -280,8 +280,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
- predefs + after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
+ true);
}
TEST_F(LocalSSAElimTest, ForLoopWithContinue) {
@@ -426,9 +426,9 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(
- predefs + names + predefs2 + before, predefs + names + predefs2 + after,
- true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + names + predefs2 + before,
+ predefs + names + predefs2 + after,
+ true, true);
}
TEST_F(LocalSSAElimTest, ForLoopWithBreak) {
@@ -567,8 +567,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
- predefs + after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
+ true);
}
TEST_F(LocalSSAElimTest, SwapProblem) {
@@ -704,8 +704,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
- predefs + after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
+ true);
}
TEST_F(LocalSSAElimTest, LostCopyProblem) {
@@ -848,8 +848,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
- predefs + after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
+ true);
}
TEST_F(LocalSSAElimTest, IfThenElse) {
@@ -948,8 +948,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
- predefs + after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
+ true);
}
TEST_F(LocalSSAElimTest, IfThen) {
@@ -1037,8 +1037,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
- predefs + after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
+ true);
}
TEST_F(LocalSSAElimTest, Switch) {
@@ -1168,8 +1168,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
- predefs + after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
+ true);
}
TEST_F(LocalSSAElimTest, SwitchWithFallThrough) {
@@ -1300,8 +1300,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
- predefs + after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
+ true);
}
TEST_F(LocalSSAElimTest, DontPatchPhiInLoopHeaderThatIsNotAVar) {
@@ -1331,7 +1331,7 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(before, before, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(before, before, true, true);
}
TEST_F(LocalSSAElimTest, OptInitializedVariableLikeStore) {
@@ -1428,8 +1428,8 @@
OpFunctionEnd
)";
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(
- predefs + func_before, predefs + func_after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(predefs + func_before,
+ predefs + func_after, true, true);
}
TEST_F(LocalSSAElimTest, PointerVariable) {
@@ -1531,7 +1531,7 @@
// Relax logical pointers to allow pointer allocations.
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ValidatorOptions()->relax_logical_pointer = true;
- SinglePassRunAndCheck<LocalMultiStoreElimPass>(before, after, true, true);
+ SinglePassRunAndCheck<SSARewritePass>(before, after, true, true);
}
TEST_F(LocalSSAElimTest, VerifyInstToBlockMap) {
@@ -1620,7 +1620,7 @@
// Force the instruction to block mapping to get built.
context->get_instr_block(27u);
- auto pass = MakeUnique<LocalMultiStoreElimPass>();
+ auto pass = MakeUnique<SSARewritePass>();
pass->SetMessageConsumer(nullptr);
const auto status = pass->Run(context.get());
EXPECT_TRUE(status == Pass::Status::SuccessWithChange);
@@ -1927,7 +1927,7 @@
OpReturn
OpFunctionEnd
)";
- SinglePassRunAndMatch<LocalMultiStoreElimPass>(text, false);
+ SinglePassRunAndMatch<SSARewritePass>(text, false);
}
TEST_F(LocalSSAElimTest, ChainedTrivialPhis) {
@@ -1987,6 +1987,41 @@
SinglePassRunAndMatch<SSARewritePass>(text, false);
}
+TEST_F(LocalSSAElimTest, Overflowtest1) {
+ // Check that the copy object get the undef value implicitly assigned in the
+ // entry block.
+ const std::string text = R"(
+OpCapability Geometry
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %4 "P2Mai" %12 %17
+OpExecutionMode %4 OriginUpperLeft
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%7 = OpTypeVector %6 4
+%11 = OpTypePointer Input %7
+%16 = OpTypePointer Output %7
+%23 = OpTypePointer Function %7
+%12 = OpVariable %11 Input
+%17 = OpVariable %16 Output
+%4 = OpFunction %2 None %3
+%2177 = OpLabel
+%4194302 = OpVariable %23 Function
+%4194301 = OpLoad %7 %4194302
+OpStore %17 %4194301
+OpReturn
+OpFunctionEnd
+ )";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ std::vector<Message> messages = {
+ {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
+ SetMessageConsumer(GetTestMessageConsumer(messages));
+ auto result = SinglePassRunToBinary<SSARewritePass>(text, true);
+ EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
+}
+
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// No optimization in the presence of
diff --git a/test/opt/module_test.cpp b/test/opt/module_test.cpp
index 569cf9b..406da09 100644
--- a/test/opt/module_test.cpp
+++ b/test/opt/module_test.cpp
@@ -21,6 +21,7 @@
#include "gtest/gtest.h"
#include "source/opt/build_module.h"
#include "source/opt/module.h"
+#include "source/opt/pass.h"
#include "spirv-tools/libspirv.hpp"
#include "test/opt/module_utils.h"
@@ -228,6 +229,72 @@
EXPECT_EQ(next_id_bound, 0);
EXPECT_EQ(current_bound, context->module()->id_bound());
}
+
+// Tests that "text" does not change when it is assembled, converted into a
+// module, converted back to a binary, and then disassembled.
+void AssembleAndDisassemble(const std::string& text) {
+ std::unique_ptr<IRContext> context = BuildModule(text);
+ std::vector<uint32_t> binary;
+
+ context->module()->ToBinary(&binary, false);
+
+ SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
+ std::string s;
+ tools.Disassemble(binary, &s);
+ EXPECT_EQ(s, text);
+}
+
+TEST(ModuleTest, TrailingOpLine) {
+ const std::string text = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%5 = OpString "file.ext"
+%void = OpTypeVoid
+%2 = OpTypeFunction %void
+%3 = OpFunction %void None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd
+OpLine %5 1 0
+)";
+
+ AssembleAndDisassemble(text);
+}
+
+TEST(ModuleTest, TrailingOpNoLine) {
+ const std::string text = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%2 = OpTypeFunction %void
+%3 = OpFunction %void None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd
+OpNoLine
+)";
+
+ AssembleAndDisassemble(text);
+}
+
+TEST(ModuleTest, MulitpleTrailingOpLine) {
+ const std::string text = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%5 = OpString "file.ext"
+%void = OpTypeVoid
+%2 = OpTypeFunction %void
+%3 = OpFunction %void None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd
+OpLine %5 1 0
+OpNoLine
+OpLine %5 1 1
+)";
+
+ AssembleAndDisassemble(text);
+}
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/optimizer_test.cpp b/test/opt/optimizer_test.cpp
index ee6e949..5c0707d 100644
--- a/test/opt/optimizer_test.cpp
+++ b/test/opt/optimizer_test.cpp
@@ -222,7 +222,7 @@
}
TEST(Optimizer, VulkanToWebGPUSetsCorrectPasses) {
- Optimizer opt(SPV_ENV_WEBGPU_0);
+ Optimizer opt(SPV_ENV_VULKAN_1_1);
opt.RegisterVulkanToWebGPUPasses();
std::vector<const char*> pass_names = opt.GetPassNames();
@@ -267,13 +267,14 @@
tools.Assemble(GetParam().input, &binary);
}
- Optimizer opt(SPV_ENV_WEBGPU_0);
+ 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));
+ validator_options, true))
+ << GetParam().input << "\n";
std::string disassembly;
{
SpirvTools tools(SPV_ENV_WEBGPU_0);
@@ -290,9 +291,9 @@
// FlattenDecorations
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Fragment %main \"main\" %hue %saturation %value\n"
"OpExecutionMode %main OriginUpperLeft\n"
"OpDecorate %group Flat\n"
@@ -311,9 +312,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Fragment %1 \"main\" %2 %3 %4\n"
"OpExecutionMode %1 OriginUpperLeft\n"
"%void = OpTypeVoid\n"
@@ -332,9 +333,9 @@
// Strip Debug
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %func \"shader\"\n"
"OpName %main \"main\"\n"
"OpName %void_fn \"void_fn\"\n"
@@ -346,9 +347,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%void = OpTypeVoid\n"
"%3 = OpTypeFunction %void\n"
@@ -361,9 +362,9 @@
// Eliminate Dead Constants
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %func \"shader\"\n"
"%u32 = OpTypeInt 32 0\n"
"%u32_ptr = OpTypePointer Workgroup %u32\n"
@@ -380,9 +381,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n"
@@ -397,9 +398,9 @@
// Strip Atomic Counter Memory
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %func \"shader\"\n"
"%u32 = OpTypeInt 32 0\n"
"%u32_ptr = OpTypePointer Workgroup %u32\n"
@@ -412,7 +413,7 @@
"%void_f = OpTypeFunction %void\n"
"%func = OpFunction %void None %void_f\n"
"%label = OpLabel\n"
- "%val0 = OpAtomicStore %u32_var %cross_device "
+ " 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"
@@ -423,9 +424,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n"
@@ -449,9 +450,9 @@
// Generate WebGPU Initializers
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %func \"shader\"\n"
"%u32 = OpTypeInt 32 0\n"
"%u32_ptr = OpTypePointer Private %u32\n"
@@ -466,9 +467,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%_ptr_Private_uint = OpTypePointer Private %uint\n"
@@ -487,9 +488,9 @@
// Legalize Vector Shuffle
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%v3uint = OpTypeVector %uint 3\n"
@@ -506,9 +507,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%v3uint = OpTypeVector %uint 3\n"
@@ -529,9 +530,9 @@
// Split Invalid Unreachable
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%uint_1 = OpConstant %uint 1\n"
@@ -560,9 +561,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%uint_1 = OpConstant %uint 1\n"
@@ -596,9 +597,9 @@
// Compact IDs
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1000 \"shader\"\n"
"%10 = OpTypeVoid\n"
"%100 = OpTypeFunction %10\n"
@@ -608,9 +609,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%void = OpTypeVoid\n"
"%3 = OpTypeFunction %void\n"
@@ -622,7 +623,7 @@
"compact-ids"}}));
TEST(Optimizer, WebGPUToVulkanSetsCorrectPasses) {
- Optimizer opt(SPV_ENV_VULKAN_1_1);
+ Optimizer opt(SPV_ENV_WEBGPU_0);
opt.RegisterWebGPUToVulkanPasses();
std::vector<const char*> pass_names = opt.GetPassNames();
@@ -659,7 +660,7 @@
tools.Assemble(GetParam().input, &binary);
}
- Optimizer opt(SPV_ENV_VULKAN_1_1);
+ Optimizer opt(SPV_ENV_WEBGPU_0);
opt.RegisterWebGPUToVulkanPasses();
std::vector<uint32_t> optimized;
@@ -682,9 +683,9 @@
// Decompose Initialized Variables
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%_ptr_Function_uint = OpTypePointer Function %uint\n"
@@ -698,9 +699,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%_ptr_Function_uint = OpTypePointer Function %uint\n"
@@ -718,9 +719,9 @@
// Compact IDs
{// input
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1000 \"shader\"\n"
"%10 = OpTypeVoid\n"
"%100 = OpTypeFunction %10\n"
@@ -730,9 +731,9 @@
"OpFunctionEnd\n",
// expected
"OpCapability Shader\n"
- "OpCapability VulkanMemoryModelKHR\n"
+ "OpCapability VulkanMemoryModel\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
- "OpMemoryModel Logical VulkanKHR\n"
+ "OpMemoryModel Logical Vulkan\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%void = OpTypeVoid\n"
"%3 = OpTypeFunction %void\n"
@@ -743,6 +744,54 @@
// pass
"compact-ids"}}));
+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
+)";
+
+ 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
+)";
+
+ std::vector<uint32_t> binary;
+ {
+ SpirvTools tools(SPV_ENV_VULKAN_1_1);
+ tools.Assemble(before, &binary);
+ }
+
+ Optimizer opt(SPV_ENV_VULKAN_1_1);
+
+ std::vector<uint32_t> optimized;
+ class ValidatorOptions validator_options;
+ ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized,
+ validator_options, true))
+ << before << "\n";
+ std::string disassembly;
+ {
+ SpirvTools tools(SPV_ENV_WEBGPU_0);
+ tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
+ }
+
+ EXPECT_EQ(after, disassembly)
+ << "Was expecting the OpNop to have been removed.";
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/reduce_load_size_test.cpp b/test/opt/reduce_load_size_test.cpp
index 7b850e3..50dc501 100644
--- a/test/opt/reduce_load_size_test.cpp
+++ b/test/opt/reduce_load_size_test.cpp
@@ -321,34 +321,6 @@
SinglePassRunAndCheck<ReduceLoadSize>(test, test, true, false);
}
-TEST_F(ReduceLoadSizeTest, extract_with_no_index) {
- const std::string test =
- R"(
- OpCapability ImageGatherExtended
- OpExtension ""
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "P�Ma'" %12 %17
- OpExecutionMode %4 OriginUpperLeft
- %void = OpTypeVoid
- %3 = OpTypeFunction %void
- %float = OpTypeFloat 32
- %_struct_7 = OpTypeStruct %float %float
-%_ptr_Input__struct_7 = OpTypePointer Input %_struct_7
-%_ptr_Output__struct_7 = OpTypePointer Output %_struct_7
- %12 = OpVariable %_ptr_Input__struct_7 Input
- %17 = OpVariable %_ptr_Output__struct_7 Output
- %4 = OpFunction %void DontInline|Pure|Const %3
- %245 = OpLabel
- %13 = OpLoad %_struct_7 %12
- %33 = OpCompositeExtract %_struct_7 %13
- OpReturn
- OpFunctionEnd
- )";
-
- auto result = SinglePassRunAndDisassemble<ReduceLoadSize>(test, true, true);
- EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
-}
-
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/relax_float_ops_test.cpp b/test/opt/relax_float_ops_test.cpp
new file mode 100644
index 0000000..14cde0b
--- /dev/null
+++ b/test/opt/relax_float_ops_test.cpp
@@ -0,0 +1,142 @@
+// Copyright (c) 2019 Valve Corporation
+// Copyright (c) 2019 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Relax float ops tests
+
+#include <string>
+#include <vector>
+
+#include "test/opt/assembly_builder.h"
+#include "test/opt/pass_fixture.h"
+#include "test/opt/pass_utils.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+using RelaxFloatOpsTest = PassTest<::testing::Test>;
+
+TEST_F(RelaxFloatOpsTest, RelaxFloatOpsBasic) {
+ // All float result instructions in functions should be relaxed
+ // clang-format off
+ //
+ // SamplerState g_sSamp : register(s0);
+ // uniform Texture1D <float4> g_tTex1df4 : register(t0);
+ //
+ // struct PS_INPUT
+ // {
+ // float Tex0 : TEXCOORD0;
+ // float Tex1 : TEXCOORD1;
+ // };
+ //
+ // struct PS_OUTPUT
+ // {
+ // float4 Color : SV_Target0;
+ // };
+ //
+ // PS_OUTPUT main(PS_INPUT i)
+ // {
+ // PS_OUTPUT psout;
+ // float4 txval10 = g_tTex1df4.Sample(g_sSamp, i.Tex0);
+ // float4 txval11 = g_tTex1df4.Sample(g_sSamp, i.Tex1);
+ // float4 t = txval10 + txval11;
+ // float4 t2 = t / 2.0;
+ // psout.Color = t2;
+ // return psout;
+ // }
+ // clang-format on
+
+ const std::string defs0 =
+ R"(OpCapability Shader
+OpCapability Sampled1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %i_Tex0 %i_Tex1 %_entryPointOutput_Color
+OpExecutionMode %main OriginUpperLeft
+OpSource HLSL 500
+OpName %main "main"
+OpName %g_tTex1df4 "g_tTex1df4"
+OpName %g_sSamp "g_sSamp"
+OpName %i_Tex0 "i.Tex0"
+OpName %i_Tex1 "i.Tex1"
+OpName %_entryPointOutput_Color "@entryPointOutput.Color"
+OpDecorate %g_tTex1df4 DescriptorSet 0
+OpDecorate %g_tTex1df4 Binding 0
+OpDecorate %g_sSamp DescriptorSet 0
+OpDecorate %g_sSamp Binding 0
+OpDecorate %i_Tex0 Location 0
+OpDecorate %i_Tex1 Location 1
+OpDecorate %_entryPointOutput_Color Location 0
+)";
+
+ const std::string defs1 =
+ R"(%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%17 = OpTypeImage %float 1D 0 0 0 1 Unknown
+%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17
+%g_tTex1df4 = OpVariable %_ptr_UniformConstant_17 UniformConstant
+%21 = OpTypeSampler
+%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
+%g_sSamp = OpVariable %_ptr_UniformConstant_21 UniformConstant
+%25 = OpTypeSampledImage %17
+%_ptr_Input_float = OpTypePointer Input %float
+%i_Tex0 = OpVariable %_ptr_Input_float Input
+%i_Tex1 = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output
+%float_0_5 = OpConstant %float 0.5
+%116 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
+)";
+
+ const std::string relax_decos =
+ R"(OpDecorate %60 RelaxedPrecision
+OpDecorate %63 RelaxedPrecision
+OpDecorate %82 RelaxedPrecision
+OpDecorate %88 RelaxedPrecision
+OpDecorate %91 RelaxedPrecision
+OpDecorate %94 RelaxedPrecision
+)";
+
+ const std::string func_orig =
+ R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%60 = OpLoad %float %i_Tex0
+%63 = OpLoad %float %i_Tex1
+%77 = OpLoad %17 %g_tTex1df4
+%78 = OpLoad %21 %g_sSamp
+%79 = OpSampledImage %25 %77 %78
+%82 = OpImageSampleImplicitLod %v4float %79 %60
+%83 = OpLoad %17 %g_tTex1df4
+%84 = OpLoad %21 %g_sSamp
+%85 = OpSampledImage %25 %83 %84
+%88 = OpImageSampleImplicitLod %v4float %85 %63
+%91 = OpFAdd %v4float %82 %88
+%94 = OpFMul %v4float %91 %116
+OpStore %_entryPointOutput_Color %94
+OpReturn
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndCheck<RelaxFloatOpsPass>(
+ defs0 + defs1 + func_orig, defs0 + relax_decos + defs1 + func_orig, true,
+ true);
+}
+
+} // namespace
+} // namespace opt
+} // namespace spvtools
diff --git a/test/opt/simplification_test.cpp b/test/opt/simplification_test.cpp
index 1420498..7a9696e 100644
--- a/test/opt/simplification_test.cpp
+++ b/test/opt/simplification_test.cpp
@@ -71,6 +71,41 @@
SinglePassRunAndMatch<SimplificationPass>(text, false);
}
+TEST_F(SimplificationTest, NewInstructionTest) {
+ // Testing that new instructions are simplified. Specifically,
+ // that the new add instruction generated by FactorAddMul is
+ // further simplified by MergeGenericAddSub.
+ const std::string text = R"(OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 430
+ OpName %main "main"
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %_ptr_int = OpTypePointer Function %int
+; CHECK: [[mul:%[a-zA-Z_\d]+]] = OpIMul %int %13 %11
+ %main = OpFunction %void None %4
+ %7 = OpLabel
+ %8 = OpVariable %_ptr_int Function
+ %9 = OpVariable %_ptr_int Function
+ %10 = OpVariable %_ptr_int Function
+ %11 = OpLoad %int %8
+ %12 = OpLoad %int %9
+ %13 = OpLoad %int %10
+ %14 = OpISub %int %11 %12
+ %15 = OpIMul %int %13 %11
+ %16 = OpIMul %int %13 %12
+ %17 = OpIAdd %int %14 %15
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<SimplificationPass>(text, false);
+}
+
TEST_F(SimplificationTest, AcrossBasicBlocks) {
// Testing that folding rules are combined across basic blocks.
const std::string text = R"(OpCapability Shader
@@ -206,7 +241,7 @@
// Don't simplify OpCopyObject if the result id has a decoration that the
// operand does not.
const std::string text = R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
+OpCapability ShaderNonUniform
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %2 "main"
@@ -214,7 +249,7 @@
OpSource GLSL 430
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
-OpDecorate %3 NonUniformEXT
+OpDecorate %3 NonUniform
%void = OpTypeVoid
%5 = OpTypeFunction %void
%int = OpTypeInt 32 1
@@ -234,7 +269,7 @@
// Simplify OpCopyObject if the result id is a subset of the decorations of
// the operand.
const std::string before = R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
+OpCapability ShaderNonUniform
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %2 "main"
@@ -242,7 +277,7 @@
OpSource GLSL 430
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
-OpDecorate %3 NonUniformEXT
+OpDecorate %3 NonUniform
%void = OpTypeVoid
%5 = OpTypeFunction %void
%int = OpTypeInt 32 1
@@ -256,7 +291,7 @@
)";
const std::string after = R"(OpCapability Shader
-OpCapability ShaderNonUniformEXT
+OpCapability ShaderNonUniform
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %2 "main"
@@ -264,7 +299,7 @@
OpSource GLSL 430
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
-OpDecorate %3 NonUniformEXT
+OpDecorate %3 NonUniform
%void = OpTypeVoid
%5 = OpTypeFunction %void
%int = OpTypeInt 32 1
diff --git a/test/opt/split_invalid_unreachable_test.cpp b/test/opt/split_invalid_unreachable_test.cpp
index 868c7b5..520af01 100644
--- a/test/opt/split_invalid_unreachable_test.cpp
+++ b/test/opt/split_invalid_unreachable_test.cpp
@@ -24,9 +24,9 @@
using SplitInvalidUnreachableTest = PassTest<::testing::Test>;
std::string spirv_header = R"(OpCapability Shader
-OpCapability VulkanMemoryModelKHR
+OpCapability VulkanMemoryModel
OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
+OpMemoryModel Logical Vulkan
OpEntryPoint Vertex %1 "shader"
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
diff --git a/test/opt/strip_atomic_counter_memory_test.cpp b/test/opt/strip_atomic_counter_memory_test.cpp
index 6287a13..90daa59 100644
--- a/test/opt/strip_atomic_counter_memory_test.cpp
+++ b/test/opt/strip_atomic_counter_memory_test.cpp
@@ -45,9 +45,9 @@
std::vector<const char*> result = {
// clang-format off
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint",
@@ -76,9 +76,9 @@
std::vector<const char*> result = {
// clang-format off
"OpCapability Shader",
- "OpCapability VulkanMemoryModelKHR",
+ "OpCapability VulkanMemoryModel",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
- "OpMemoryModel Logical VulkanKHR",
+ "OpMemoryModel Logical Vulkan",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint",
diff --git a/test/opt/strip_debug_info_test.cpp b/test/opt/strip_debug_info_test.cpp
index 25cf7d8..2f2ff46 100644
--- a/test/opt/strip_debug_info_test.cpp
+++ b/test/opt/strip_debug_info_test.cpp
@@ -51,6 +51,8 @@
"OpLine %3 4 4",
"OpNoLine",
"OpFunctionEnd",
+ "OpNoLine",
+ "OpLine %3 4 5"
// clang-format on
};
SinglePassRunAndCheck<StripDebugInfoPass>(JoinAllInsts(text),
@@ -74,6 +76,82 @@
/* skip_nop = */ false);
}
+using StripDebugStringTest = PassTest<::testing::Test>;
+
+TEST_F(StripDebugStringTest, OpDecorateRemoved) {
+ std::vector<const char*> input{
+ // clang-format off
+ "OpCapability Shader",
+ "%1 = OpExtInstImport \"GLSL.std.450\"",
+ "OpMemoryModel Logical GLSL450",
+ "OpEntryPoint Vertex %2 \"main\"",
+ "%3 = OpString \"minimal.vert\"",
+ "OpDecorate %3 Location 1337",
+ "%void = OpTypeVoid",
+ "%5 = OpTypeFunction %void",
+ "%2 = OpFunction %void None %5",
+ "%6 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd",
+ // clang-format on
+ };
+ std::vector<const char*> output{
+ // clang-format off
+ "OpCapability Shader",
+ "%1 = OpExtInstImport \"GLSL.std.450\"",
+ "OpMemoryModel Logical GLSL450",
+ "OpEntryPoint Vertex %2 \"main\"",
+ "%void = OpTypeVoid",
+ "%5 = OpTypeFunction %void",
+ "%2 = OpFunction %void None %5",
+ "%6 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd",
+ // clang-format on
+ };
+ SinglePassRunAndCheck<StripDebugInfoPass>(JoinAllInsts(input),
+ JoinAllInsts(output),
+ /* skip_nop = */ false,
+ /* do_validation */ true);
+}
+
+TEST_F(StripDebugStringTest, OpNameRemoved) {
+ std::vector<const char*> input{
+ // clang-format off
+ "OpCapability Shader",
+ "%1 = OpExtInstImport \"GLSL.std.450\"",
+ "OpMemoryModel Logical GLSL450",
+ "OpEntryPoint Vertex %2 \"main\"",
+ "%3 = OpString \"minimal.vert\"",
+ "OpName %3 \"bob\"",
+ "%void = OpTypeVoid",
+ "%5 = OpTypeFunction %void",
+ "%2 = OpFunction %void None %5",
+ "%6 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd",
+ // clang-format on
+ };
+ std::vector<const char*> output{
+ // clang-format off
+ "OpCapability Shader",
+ "%1 = OpExtInstImport \"GLSL.std.450\"",
+ "OpMemoryModel Logical GLSL450",
+ "OpEntryPoint Vertex %2 \"main\"",
+ "%void = OpTypeVoid",
+ "%5 = OpTypeFunction %void",
+ "%2 = OpFunction %void None %5",
+ "%6 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd",
+ // clang-format on
+ };
+ SinglePassRunAndCheck<StripDebugInfoPass>(JoinAllInsts(input),
+ JoinAllInsts(output),
+ /* skip_nop = */ false,
+ /* do_validation */ true);
+}
+
using StripDebugInfoTest = PassTest<::testing::TestWithParam<const char*>>;
TEST_P(StripDebugInfoTest, Kind) {
diff --git a/test/opt/struct_cfg_analysis_test.cpp b/test/opt/struct_cfg_analysis_test.cpp
index 7fb3784..0451a8b 100644
--- a/test/opt/struct_cfg_analysis_test.cpp
+++ b/test/opt/struct_cfg_analysis_test.cpp
@@ -26,6 +26,7 @@
namespace {
using StructCFGAnalysisTest = PassTest<::testing::Test>;
+using ::testing::UnorderedElementsAre;
TEST_F(StructCFGAnalysisTest, BBInSelection) {
const std::string text = R"(
@@ -62,6 +63,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// BB2 is in the construct.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -70,6 +75,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
EXPECT_EQ(analysis.ContainingSwitch(2), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The merge node is not in the construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -78,6 +87,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
}
TEST_F(StructCFGAnalysisTest, BBInLoop) {
@@ -119,6 +132,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// BB2 is in the construct.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -127,6 +144,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
EXPECT_EQ(analysis.ContainingSwitch(2), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The merge node is not in the construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -135,6 +156,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
// The continue block is in the construct.
EXPECT_EQ(analysis.ContainingConstruct(4), 1);
@@ -143,6 +168,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
EXPECT_EQ(analysis.ContainingSwitch(4), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
+ EXPECT_TRUE(analysis.IsContinueBlock(4));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(4));
+ EXPECT_FALSE(analysis.IsMergeBlock(4));
}
TEST_F(StructCFGAnalysisTest, SelectionInLoop) {
@@ -189,6 +218,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// Selection header is in the loop only.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -197,6 +230,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
EXPECT_EQ(analysis.ContainingSwitch(2), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The loop merge node is not in either construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -205,6 +242,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
// The continue block is in the loop only.
EXPECT_EQ(analysis.ContainingConstruct(4), 1);
@@ -213,14 +254,22 @@
EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
EXPECT_EQ(analysis.ContainingSwitch(4), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
+ EXPECT_TRUE(analysis.IsContinueBlock(4));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(4));
+ EXPECT_FALSE(analysis.IsMergeBlock(4));
- // BB5 is in the selection fist and the loop.
+ // BB5 is in the selection and the loop.
EXPECT_EQ(analysis.ContainingConstruct(5), 2);
EXPECT_EQ(analysis.ContainingLoop(5), 1);
EXPECT_EQ(analysis.MergeBlock(5), 6);
EXPECT_EQ(analysis.LoopMergeBlock(5), 3);
EXPECT_EQ(analysis.ContainingSwitch(5), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(5));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsMergeBlock(5));
// The selection merge is in the loop only.
EXPECT_EQ(analysis.ContainingConstruct(6), 1);
@@ -229,6 +278,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(6), 3);
EXPECT_EQ(analysis.ContainingSwitch(6), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(6));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(6));
+ EXPECT_TRUE(analysis.IsMergeBlock(6));
}
TEST_F(StructCFGAnalysisTest, LoopInSelection) {
@@ -275,6 +328,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// Loop header is in the selection only.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -283,6 +340,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
EXPECT_EQ(analysis.ContainingSwitch(2), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The selection merge node is not in either construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -291,6 +352,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
// The loop merge is in the selection only.
EXPECT_EQ(analysis.ContainingConstruct(4), 1);
@@ -299,6 +364,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
EXPECT_EQ(analysis.ContainingSwitch(4), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(4));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsMergeBlock(4));
// The loop continue target is in the loop.
EXPECT_EQ(analysis.ContainingConstruct(5), 2);
@@ -307,6 +376,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(5), 4);
EXPECT_EQ(analysis.ContainingSwitch(5), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
+ EXPECT_TRUE(analysis.IsContinueBlock(5));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsMergeBlock(5));
// BB6 is in the loop.
EXPECT_EQ(analysis.ContainingConstruct(6), 2);
@@ -315,6 +388,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(6), 4);
EXPECT_EQ(analysis.ContainingSwitch(6), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(6));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(6));
+ EXPECT_FALSE(analysis.IsMergeBlock(6));
}
TEST_F(StructCFGAnalysisTest, SelectionInSelection) {
@@ -359,6 +436,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// The inner header is in the outer selection.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -367,6 +448,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
EXPECT_EQ(analysis.ContainingSwitch(2), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The outer merge node is not in either construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -375,6 +460,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
// The inner merge is in the outer selection.
EXPECT_EQ(analysis.ContainingConstruct(4), 1);
@@ -383,6 +472,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
EXPECT_EQ(analysis.ContainingSwitch(4), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(4));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsMergeBlock(4));
// BB5 is in the inner selection.
EXPECT_EQ(analysis.ContainingConstruct(5), 2);
@@ -391,6 +484,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(5), 0);
EXPECT_EQ(analysis.ContainingSwitch(5), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(5));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsMergeBlock(5));
}
TEST_F(StructCFGAnalysisTest, LoopInLoop) {
@@ -439,6 +536,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// The inner loop header is in the outer loop.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -447,6 +548,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
EXPECT_EQ(analysis.ContainingSwitch(2), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The outer merge node is not in either construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -455,6 +560,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
// The inner merge is in the outer loop.
EXPECT_EQ(analysis.ContainingConstruct(4), 1);
@@ -463,6 +572,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
EXPECT_EQ(analysis.ContainingSwitch(4), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(4));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsMergeBlock(4));
// The inner continue target is in the inner loop.
EXPECT_EQ(analysis.ContainingConstruct(5), 2);
@@ -471,6 +584,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(5), 4);
EXPECT_EQ(analysis.ContainingSwitch(5), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
+ EXPECT_TRUE(analysis.IsContinueBlock(5));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsMergeBlock(5));
// BB6 is in the loop.
EXPECT_EQ(analysis.ContainingConstruct(6), 2);
@@ -479,6 +596,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(6), 4);
EXPECT_EQ(analysis.ContainingSwitch(6), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(6));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(6));
+ EXPECT_FALSE(analysis.IsMergeBlock(6));
// The outer continue target is in the outer loop.
EXPECT_EQ(analysis.ContainingConstruct(7), 1);
@@ -487,6 +608,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(7), 3);
EXPECT_EQ(analysis.ContainingSwitch(7), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(7), 0);
+ EXPECT_TRUE(analysis.IsContinueBlock(7));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(7));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(7));
+ EXPECT_FALSE(analysis.IsMergeBlock(7));
}
TEST_F(StructCFGAnalysisTest, KernelTest) {
@@ -523,6 +648,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(i), 0);
EXPECT_EQ(analysis.ContainingSwitch(i), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(i), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(i));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(i));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(i));
+ EXPECT_FALSE(analysis.IsMergeBlock(i));
}
}
@@ -581,6 +710,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// BB2 is in the construct.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -589,6 +722,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
EXPECT_EQ(analysis.ContainingSwitch(2), 1);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 3);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The merge node is not in the construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -597,6 +734,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
}
TEST_F(StructCFGAnalysisTest, LoopInSwitch) {
@@ -643,6 +784,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// Loop header is in the selection only.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -651,6 +796,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
EXPECT_EQ(analysis.ContainingSwitch(2), 1);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 3);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The selection merge node is not in either construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -659,6 +808,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
// The loop merge is in the selection only.
EXPECT_EQ(analysis.ContainingConstruct(4), 1);
@@ -667,6 +820,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
EXPECT_EQ(analysis.ContainingSwitch(4), 1);
EXPECT_EQ(analysis.SwitchMergeBlock(4), 3);
+ EXPECT_FALSE(analysis.IsContinueBlock(4));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsMergeBlock(4));
// The loop continue target is in the loop.
EXPECT_EQ(analysis.ContainingConstruct(5), 2);
@@ -675,6 +832,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(5), 4);
EXPECT_EQ(analysis.ContainingSwitch(5), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
+ EXPECT_TRUE(analysis.IsContinueBlock(5));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsMergeBlock(5));
// BB6 is in the loop.
EXPECT_EQ(analysis.ContainingConstruct(6), 2);
@@ -683,6 +844,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(6), 4);
EXPECT_EQ(analysis.ContainingSwitch(6), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(6));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(6));
+ EXPECT_FALSE(analysis.IsMergeBlock(6));
}
TEST_F(StructCFGAnalysisTest, SelectionInSwitch) {
@@ -727,6 +892,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// The inner header is in the outer selection.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -735,6 +904,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
EXPECT_EQ(analysis.ContainingSwitch(2), 1);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 3);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The outer merge node is not in either construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -743,6 +916,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
// The inner merge is in the outer selection.
EXPECT_EQ(analysis.ContainingConstruct(4), 1);
@@ -751,6 +928,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
EXPECT_EQ(analysis.ContainingSwitch(4), 1);
EXPECT_EQ(analysis.SwitchMergeBlock(4), 3);
+ EXPECT_FALSE(analysis.IsContinueBlock(4));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsMergeBlock(4));
// BB5 is in the inner selection.
EXPECT_EQ(analysis.ContainingConstruct(5), 2);
@@ -759,6 +940,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(5), 0);
EXPECT_EQ(analysis.ContainingSwitch(5), 1);
EXPECT_EQ(analysis.SwitchMergeBlock(5), 3);
+ EXPECT_FALSE(analysis.IsContinueBlock(5));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsMergeBlock(5));
}
TEST_F(StructCFGAnalysisTest, SwitchInSelection) {
@@ -803,6 +988,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
EXPECT_EQ(analysis.ContainingSwitch(1), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
// The inner header is in the outer selection.
EXPECT_EQ(analysis.ContainingConstruct(2), 1);
@@ -811,6 +1000,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
EXPECT_EQ(analysis.ContainingSwitch(2), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
// The outer merge node is not in either construct.
EXPECT_EQ(analysis.ContainingConstruct(3), 0);
@@ -819,6 +1012,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
EXPECT_EQ(analysis.ContainingSwitch(3), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
// The inner merge is in the outer selection.
EXPECT_EQ(analysis.ContainingConstruct(4), 1);
@@ -827,6 +1024,10 @@
EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
EXPECT_EQ(analysis.ContainingSwitch(4), 0);
EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(4));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsMergeBlock(4));
// BB5 is in the inner selection.
EXPECT_EQ(analysis.ContainingConstruct(5), 2);
@@ -835,8 +1036,339 @@
EXPECT_EQ(analysis.LoopMergeBlock(5), 0);
EXPECT_EQ(analysis.ContainingSwitch(5), 2);
EXPECT_EQ(analysis.SwitchMergeBlock(5), 4);
+ EXPECT_FALSE(analysis.IsContinueBlock(5));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsMergeBlock(5));
}
+TEST_F(StructCFGAnalysisTest, SelectionInContinue) {
+ const std::string text = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+%void = OpTypeVoid
+%bool = OpTypeBool
+%bool_undef = OpUndef %bool
+%uint = OpTypeInt 32 0
+%uint_undef = OpUndef %uint
+%void_func = OpTypeFunction %void
+%main = OpFunction %void None %void_func
+%entry_lab = OpLabel
+OpBranch %1
+%1 = OpLabel
+OpLoopMerge %3 %4 None
+OpBranchConditional %undef_bool %2 %3
+%2 = OpLabel
+OpBranch %3
+%4 = OpLabel
+OpSelectionMerge %6 None
+OpBranchConditional %undef_bool %5 %6
+%5 = OpLabel
+OpBranch %6
+%6 = OpLabel
+OpBranch %1
+%3 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ std::unique_ptr<IRContext> context =
+ BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ StructuredCFGAnalysis analysis(context.get());
+
+ // The loop header is not in either construct.
+ EXPECT_EQ(analysis.ContainingConstruct(1), 0);
+ EXPECT_EQ(analysis.ContainingLoop(1), 0);
+ EXPECT_EQ(analysis.MergeBlock(1), 0);
+ EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
+ EXPECT_EQ(analysis.ContainingSwitch(1), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
+
+ // Selection header is in the loop only.
+ EXPECT_EQ(analysis.ContainingConstruct(2), 1);
+ EXPECT_EQ(analysis.ContainingLoop(2), 1);
+ EXPECT_EQ(analysis.MergeBlock(2), 3);
+ EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
+ EXPECT_EQ(analysis.ContainingSwitch(2), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
+
+ // The loop merge node is not in either construct.
+ EXPECT_EQ(analysis.ContainingConstruct(3), 0);
+ EXPECT_EQ(analysis.ContainingLoop(3), 0);
+ EXPECT_EQ(analysis.MergeBlock(3), 0);
+ EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
+ EXPECT_EQ(analysis.ContainingSwitch(3), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
+
+ // The continue block is in the loop only.
+ EXPECT_EQ(analysis.ContainingConstruct(4), 1);
+ EXPECT_EQ(analysis.ContainingLoop(4), 1);
+ EXPECT_EQ(analysis.MergeBlock(4), 3);
+ EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
+ EXPECT_EQ(analysis.ContainingSwitch(4), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
+ EXPECT_TRUE(analysis.IsContinueBlock(4));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(4));
+ EXPECT_FALSE(analysis.IsMergeBlock(4));
+
+ // BB5 is in the selection and the continue for the loop.
+ EXPECT_EQ(analysis.ContainingConstruct(5), 4);
+ EXPECT_EQ(analysis.ContainingLoop(5), 1);
+ EXPECT_EQ(analysis.MergeBlock(5), 6);
+ EXPECT_EQ(analysis.LoopMergeBlock(5), 3);
+ EXPECT_EQ(analysis.ContainingSwitch(5), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(5));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsMergeBlock(5));
+
+ // BB5 is in the continue for the loop.
+ EXPECT_EQ(analysis.ContainingConstruct(6), 1);
+ EXPECT_EQ(analysis.ContainingLoop(6), 1);
+ EXPECT_EQ(analysis.MergeBlock(6), 3);
+ EXPECT_EQ(analysis.LoopMergeBlock(6), 3);
+ EXPECT_EQ(analysis.ContainingSwitch(6), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(6));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(6));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(6));
+ EXPECT_TRUE(analysis.IsMergeBlock(6));
+}
+
+TEST_F(StructCFGAnalysisTest, LoopInContinue) {
+ const std::string text = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+%void = OpTypeVoid
+%bool = OpTypeBool
+%bool_undef = OpUndef %bool
+%uint = OpTypeInt 32 0
+%uint_undef = OpUndef %uint
+%void_func = OpTypeFunction %void
+%main = OpFunction %void None %void_func
+%entry_lab = OpLabel
+OpBranch %1
+%1 = OpLabel
+OpLoopMerge %3 %7 None
+OpBranchConditional %undef_bool %2 %3
+%2 = OpLabel
+OpBranchConditional %undef_bool %3 %7
+%7 = OpLabel
+OpLoopMerge %4 %5 None
+OpBranchConditional %undef_bool %4 %6
+%5 = OpLabel
+OpBranch %7
+%6 = OpLabel
+OpBranch %4
+%4 = OpLabel
+OpBranch %1
+%3 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ std::unique_ptr<IRContext> context =
+ BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ StructuredCFGAnalysis analysis(context.get());
+
+ // The outer loop header is not in either construct.
+ EXPECT_EQ(analysis.ContainingConstruct(1), 0);
+ EXPECT_EQ(analysis.ContainingLoop(1), 0);
+ EXPECT_EQ(analysis.MergeBlock(1), 0);
+ EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
+ EXPECT_EQ(analysis.ContainingSwitch(1), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(1));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(1));
+ EXPECT_FALSE(analysis.IsMergeBlock(1));
+
+ // BB2 is a regular block in the inner loop.
+ EXPECT_EQ(analysis.ContainingConstruct(2), 1);
+ EXPECT_EQ(analysis.ContainingLoop(2), 1);
+ EXPECT_EQ(analysis.MergeBlock(2), 3);
+ EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
+ EXPECT_EQ(analysis.ContainingSwitch(2), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(2));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(2));
+ EXPECT_FALSE(analysis.IsMergeBlock(2));
+
+ // The outer merge node is not in either construct.
+ EXPECT_EQ(analysis.ContainingConstruct(3), 0);
+ EXPECT_EQ(analysis.ContainingLoop(3), 0);
+ EXPECT_EQ(analysis.MergeBlock(3), 0);
+ EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
+ EXPECT_EQ(analysis.ContainingSwitch(3), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(3));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
+ EXPECT_FALSE(analysis.IsInContinueConstruct(3));
+ EXPECT_TRUE(analysis.IsMergeBlock(3));
+
+ // The inner merge is in the continue of the outer loop.
+ EXPECT_EQ(analysis.ContainingConstruct(4), 1);
+ EXPECT_EQ(analysis.ContainingLoop(4), 1);
+ EXPECT_EQ(analysis.MergeBlock(4), 3);
+ EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
+ EXPECT_EQ(analysis.ContainingSwitch(4), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(4));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(4));
+ EXPECT_TRUE(analysis.IsMergeBlock(4));
+
+ // The inner continue target is in the inner loop.
+ EXPECT_EQ(analysis.ContainingConstruct(5), 7);
+ EXPECT_EQ(analysis.ContainingLoop(5), 7);
+ EXPECT_EQ(analysis.MergeBlock(5), 4);
+ EXPECT_EQ(analysis.LoopMergeBlock(5), 4);
+ EXPECT_EQ(analysis.ContainingSwitch(5), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
+ EXPECT_TRUE(analysis.IsContinueBlock(5));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(5));
+ EXPECT_FALSE(analysis.IsMergeBlock(5));
+
+ // BB6 is a regular block in the inner loop.
+ EXPECT_EQ(analysis.ContainingConstruct(6), 7);
+ EXPECT_EQ(analysis.ContainingLoop(6), 7);
+ EXPECT_EQ(analysis.MergeBlock(6), 4);
+ EXPECT_EQ(analysis.LoopMergeBlock(6), 4);
+ EXPECT_EQ(analysis.ContainingSwitch(6), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
+ EXPECT_FALSE(analysis.IsContinueBlock(6));
+ EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(6));
+ EXPECT_FALSE(analysis.IsMergeBlock(6));
+
+ // The outer continue target is in the outer loop.
+ EXPECT_EQ(analysis.ContainingConstruct(7), 1);
+ EXPECT_EQ(analysis.ContainingLoop(7), 1);
+ EXPECT_EQ(analysis.MergeBlock(7), 3);
+ EXPECT_EQ(analysis.LoopMergeBlock(7), 3);
+ EXPECT_EQ(analysis.ContainingSwitch(7), 0);
+ EXPECT_EQ(analysis.SwitchMergeBlock(7), 0);
+ EXPECT_TRUE(analysis.IsContinueBlock(7));
+ EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(7));
+ EXPECT_TRUE(analysis.IsInContinueConstruct(7));
+ EXPECT_FALSE(analysis.IsMergeBlock(7));
+}
+
+TEST_F(StructCFGAnalysisTest, FuncCallInContinueDirect) {
+ const std::string text = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "main"
+ %void = OpTypeVoid
+ %bool = OpTypeBool
+ %4 = OpUndef %bool
+ %uint = OpTypeInt 32 0
+ %6 = OpUndef %uint
+ %7 = OpTypeFunction %void
+ %1 = OpFunction %void None %7
+ %8 = OpLabel
+ OpBranch %9
+ %9 = OpLabel
+ OpLoopMerge %10 %11 None
+ OpBranchConditional %12 %10 %11
+ %11 = OpLabel
+ %13 = OpFunctionCall %void %14
+ OpBranch %9
+ %10 = OpLabel
+ %15 = OpFunctionCall %void %16
+ OpReturn
+ OpFunctionEnd
+ %14 = OpFunction %void None %7
+ %17 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %16 = OpFunction %void None %7
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ std::unique_ptr<IRContext> context =
+ BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ StructuredCFGAnalysis analysis(context.get());
+
+ auto c = analysis.FindFuncsCalledFromContinue();
+ EXPECT_THAT(c, UnorderedElementsAre(14u));
+}
+
+TEST_F(StructCFGAnalysisTest, FuncCallInContinueIndirect) {
+ const std::string text = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "main"
+ %void = OpTypeVoid
+ %bool = OpTypeBool
+ %4 = OpUndef %bool
+ %uint = OpTypeInt 32 0
+ %6 = OpUndef %uint
+ %7 = OpTypeFunction %void
+ %1 = OpFunction %void None %7
+ %8 = OpLabel
+ OpBranch %9
+ %9 = OpLabel
+ OpLoopMerge %10 %11 None
+ OpBranchConditional %12 %10 %11
+ %11 = OpLabel
+ %13 = OpFunctionCall %void %14
+ OpBranch %9
+ %10 = OpLabel
+ %15 = OpFunctionCall %void %16
+ OpReturn
+ OpFunctionEnd
+ %14 = OpFunction %void None %7
+ %17 = OpLabel
+ %19 = OpFunctionCall %void %16
+ OpReturn
+ OpFunctionEnd
+ %16 = OpFunction %void None %7
+ %18 = OpLabel
+ %20 = OpFunctionCall %void %21
+ OpReturn
+ OpFunctionEnd
+ %21 = OpFunction %void None %7
+ %22 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ std::unique_ptr<IRContext> context =
+ BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ StructuredCFGAnalysis analysis(context.get());
+
+ auto c = analysis.FindFuncsCalledFromContinue();
+ EXPECT_THAT(c, UnorderedElementsAre(14u, 16u, 21u));
+}
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/type_manager_test.cpp b/test/opt/type_manager_test.cpp
index 267d98c..743d0b6 100644
--- a/test/opt/type_manager_test.cpp
+++ b/test/opt/type_manager_test.cpp
@@ -156,7 +156,8 @@
types.emplace_back(new ReserveId());
types.emplace_back(new Queue());
- // Pipe, Forward Pointer, PipeStorage, NamedBarrier, AccelerationStructureNV
+ // Pipe, Forward Pointer, PipeStorage, NamedBarrier, AccelerationStructureNV,
+ // CooperativeMatrixNV
types.emplace_back(new Pipe(SpvAccessQualifierReadWrite));
types.emplace_back(new Pipe(SpvAccessQualifierReadOnly));
types.emplace_back(new ForwardPointer(1, SpvStorageClassInput));
@@ -165,6 +166,7 @@
types.emplace_back(new PipeStorage());
types.emplace_back(new NamedBarrier());
types.emplace_back(new AccelerationStructureNV());
+ types.emplace_back(new CooperativeMatrixNV(f32, 24, 24, 24));
return types;
}
@@ -214,6 +216,7 @@
%arr_spec_const_with_id = OpTypeArray %s32 %spec_const_with_id
%arr_long_constant = OpTypeArray %s32 %long_constant
%arr_spec_const_op = OpTypeArray %s32 %spec_const_op
+ %cm = OpTypeCooperativeMatrixNV %f64 %id4 %id4 %id4
)";
std::vector<std::pair<uint32_t, std::string>> type_id_strs = {
@@ -251,6 +254,7 @@
{36, "[sint32, id(1), words(1,99,42)]"},
{37, "[sint32, id(33), words(0,705032704,1)]"},
{38, "[sint32, id(34), words(2,34)]"},
+ {39, "<float64, 6, 6, 6>"},
};
std::unique_ptr<IRContext> context =
@@ -1060,6 +1064,7 @@
; CHECK: OpTypePipeStorage
; CHECK: OpTypeNamedBarrier
; CHECK: OpTypeAccelerationStructureNV
+; CHECK: OpTypeCooperativeMatrixNV [[f32]] [[uint24]] [[uint24]] [[uint24]]
OpCapability Shader
OpCapability Int64
OpCapability Linkage
diff --git a/test/opt/upgrade_memory_model_test.cpp b/test/opt/upgrade_memory_model_test.cpp
index b012383..7f64ffd 100644
--- a/test/opt/upgrade_memory_model_test.cpp
+++ b/test/opt/upgrade_memory_model_test.cpp
@@ -34,14 +34,14 @@
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
}
-TEST_F(UpgradeMemoryModelTest, InvalidMemoryModelVulkanKHR) {
+TEST_F(UpgradeMemoryModelTest, InvalidMemoryModelVulkan) {
const std::string text = R"(
-; CHECK: OpMemoryModel Logical VulkanKHR
+; CHECK: OpMemoryModel Logical Vulkan
OpCapability Shader
OpCapability Linkage
-OpCapability VulkanMemoryModelKHR
+OpCapability VulkanMemoryModel
OpExtension "SPV_KHR_vulkan_memory_model"
-OpMemoryModel Logical VulkanKHR
+OpMemoryModel Logical Vulkan
)";
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
@@ -49,9 +49,9 @@
TEST_F(UpgradeMemoryModelTest, JustMemoryModel) {
const std::string text = R"(
-; CHECK: OpCapability VulkanMemoryModelKHR
+; CHECK: OpCapability VulkanMemoryModel
; CHECK: OpExtension "SPV_KHR_vulkan_memory_model"
-; CHECK: OpMemoryModel Logical VulkanKHR
+; CHECK: OpMemoryModel Logical Vulkan
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
@@ -79,8 +79,8 @@
TEST_F(UpgradeMemoryModelTest, WorkgroupVariable) {
const std::string text = R"(
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
@@ -92,7 +92,7 @@
%func = OpFunction %void None %func_ty
%1 = OpLabel
%ld = OpLoad %int %var
-%st = OpStore %var %ld
+OpStore %var %ld
OpReturn
OpFunctionEnd
)";
@@ -103,8 +103,8 @@
TEST_F(UpgradeMemoryModelTest, WorkgroupFunctionParameter) {
const std::string text = R"(
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
@@ -116,7 +116,7 @@
%param = OpFunctionParameter %ptr_int_Workgroup
%1 = OpLabel
%ld = OpLoad %int %param
-%st = OpStore %param %ld
+OpStore %param %ld
OpReturn
OpFunctionEnd
)";
@@ -128,8 +128,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
@@ -155,8 +155,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
@@ -208,8 +208,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
@@ -236,8 +236,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
@@ -265,8 +265,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
@@ -297,8 +297,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
@@ -330,8 +330,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpCapability VariablePointers
@@ -363,8 +363,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpCapability VariablePointers
@@ -396,8 +396,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate {{%\w+}} Coherent
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpCapability VariablePointers
@@ -439,8 +439,8 @@
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -470,8 +470,8 @@
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -497,9 +497,9 @@
TEST_F(UpgradeMemoryModelTest, CoherentElementNotAccessed) {
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
-; CHECK-NOT: MakePointerAvailableKHR
-; CHECK-NOT: NonPrivatePointerKHR
-; CHECK-NOT: MakePointerVisibleKHR
+; CHECK-NOT: MakePointerAvailable
+; CHECK-NOT: NonPrivatePointer
+; CHECK-NOT: MakePointerVisible
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -529,8 +529,8 @@
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -563,9 +563,9 @@
TEST_F(UpgradeMemoryModelTest, MultiIndexAccessNonCoherent) {
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
-; CHECK-NOT: MakePointerAvailableKHR
-; CHECK-NOT: NonPrivatePointerKHR
-; CHECK-NOT: MakePointerVisibleKHR
+; CHECK-NOT: MakePointerAvailable
+; CHECK-NOT: NonPrivatePointer
+; CHECK-NOT: MakePointerVisible
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -599,8 +599,8 @@
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -639,9 +639,9 @@
TEST_F(UpgradeMemoryModelTest, ConsecutiveAccessChainNonCoherent) {
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
-; CHECK-NOT: MakePointerAvailableKHR
-; CHECK-NOT: NonPrivatePointerKHR
-; CHECK-NOT: MakePointerVisibleKHR
+; CHECK-NOT: MakePointerAvailable
+; CHECK-NOT: NonPrivatePointer
+; CHECK-NOT: MakePointerVisible
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -681,8 +681,8 @@
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -722,8 +722,8 @@
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK-NOT: MakePointerVisibleKHR
-; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
+; CHECK-NOT: MakePointerVisible
+; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]]
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -763,7 +763,7 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[queuefamily]]
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[queuefamily]]
; CHECK-NOT: [[queuefamily]]
OpCapability Shader
OpCapability Linkage
@@ -791,7 +791,7 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpCopyMemorySized {{%\w+}} {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[queuefamily]]
+; CHECK: OpCopyMemorySized {{%\w+}} {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[queuefamily]]
; CHECK-NOT: [[queuefamily]]
OpCapability Shader
OpCapability Linkage
@@ -822,7 +822,7 @@
; CHECK-NOT: OpDecorate
; CHECK-DAG: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5
; CHECK-DAG: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|MakePointerVisibleKHR|NonPrivatePointerKHR [[workgroup]] [[queuefamily]]
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailable|MakePointerVisible|NonPrivatePointer [[workgroup]] [[queuefamily]]
OpCapability Shader
OpCapability Linkage
OpExtension "SPV_KHR_storage_buffer_storage_class"
@@ -850,7 +850,7 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile
-; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} VolatileTexelKHR
+; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} VolatileTexel
OpCapability Shader
OpCapability Linkage
OpCapability StorageImageReadWithoutFormat
@@ -882,8 +882,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisible|NonPrivateTexel [[scope]]
OpCapability Shader
OpCapability Linkage
OpCapability StorageImageReadWithoutFormat
@@ -916,9 +916,9 @@
; CHECK-NOT: OpDecorate
; CHECK: [[image:%\w+]] = OpTypeImage
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK-NOT: NonPrivatePointerKHR
-; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK-NOT: NonPrivatePointer
+; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisible|NonPrivateTexel [[scope]]
OpCapability Shader
OpCapability Linkage
OpCapability StorageImageReadWithoutFormat
@@ -957,7 +957,7 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile
-; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} VolatileTexelKHR
+; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} VolatileTexel
OpCapability Shader
OpCapability Linkage
OpCapability StorageImageWriteWithoutFormat
@@ -989,8 +989,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR
-; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer
+; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailable|NonPrivateTexel [[scope]]
OpCapability Shader
OpCapability Linkage
OpCapability StorageImageWriteWithoutFormat
@@ -1022,9 +1022,9 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR
-; CHECK-NOT: NonPrivatePointerKHR
-; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer
+; CHECK-NOT: NonPrivatePointer
+; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailable|NonPrivateTexel [[scope]]
OpCapability Shader
OpCapability Linkage
OpCapability StorageImageWriteWithoutFormat
@@ -1063,7 +1063,7 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile
-; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} VolatileTexelKHR
+; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} VolatileTexel
OpCapability Shader
OpCapability Linkage
OpCapability StorageImageReadWithoutFormat
@@ -1097,8 +1097,8 @@
const std::string text = R"(
; CHECK-NOT: OpDecorate
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisible|NonPrivateTexel [[scope]]
OpCapability Shader
OpCapability Linkage
OpCapability StorageImageReadWithoutFormat
@@ -1134,9 +1134,9 @@
; CHECK-NOT: OpDecorate
; CHECK: [[image:%\w+]] = OpTypeImage
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
-; CHECK-NOT: NonPrivatePointerKHR
-; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
+; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]]
+; CHECK-NOT: NonPrivatePointer
+; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisible|NonPrivateTexel [[scope]]
OpCapability Shader
OpCapability Linkage
OpCapability StorageImageReadWithoutFormat
@@ -1440,7 +1440,7 @@
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
; CHECK: OpStore [[var]] [[ex1]]
-; CHECK-NOT: NonPrivatePointerKHR
+; CHECK-NOT: NonPrivatePointer
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
OpCapability Shader
OpMemoryModel Logical GLSL450
@@ -1474,7 +1474,7 @@
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
-; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[wg_scope]]
+; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailable|NonPrivatePointer [[wg_scope]]
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
OpCapability Shader
OpMemoryModel Logical GLSL450
@@ -1509,7 +1509,7 @@
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
-; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[qf_scope]]
+; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailable|NonPrivatePointer [[qf_scope]]
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
OpCapability Shader
OpMemoryModel Logical GLSL450
@@ -1579,7 +1579,7 @@
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
; CHECK: OpStore [[var]] [[ex1]]
-; CHECK-NOT: NonPrivatePointerKHR
+; CHECK-NOT: NonPrivatePointer
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
OpCapability Shader
OpMemoryModel Logical GLSL450
@@ -1615,7 +1615,7 @@
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
-; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[wg_scope]]
+; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailable|NonPrivatePointer [[wg_scope]]
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
OpCapability Shader
OpMemoryModel Logical GLSL450
@@ -1652,7 +1652,7 @@
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
-; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[qf_scope]]
+; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailable|NonPrivatePointer [[qf_scope]]
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
OpCapability Shader
OpMemoryModel Logical GLSL450
@@ -1785,7 +1785,7 @@
TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryDstCoherent) {
const std::string text = R"(
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] None
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] None
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "func" %src %dst
@@ -1810,7 +1810,7 @@
TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryDstCoherentPreviousArgs) {
const std::string text = R"(
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned|MakePointerAvailableKHR|NonPrivatePointerKHR 4 [[scope]] Aligned 4
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned|MakePointerAvailable|NonPrivatePointer 4 [[scope]] Aligned 4
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "func" %src %dst
@@ -1835,7 +1835,7 @@
TEST_F(UpgradeMemoryModelTest, SPV14CopyMemorySrcCoherent) {
const std::string text = R"(
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} None MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} None MakePointerVisible|NonPrivatePointer [[scope]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "func" %src %dst
@@ -1860,7 +1860,7 @@
TEST_F(UpgradeMemoryModelTest, SPV14CopyMemorySrcCoherentPreviousArgs) {
const std::string text = R"(
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned 4 Aligned|MakePointerVisibleKHR|NonPrivatePointerKHR 4 [[scope]]
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned 4 Aligned|MakePointerVisible|NonPrivatePointer 4 [[scope]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "func" %src %dst
@@ -1886,7 +1886,7 @@
const std::string text = R"(
; CHECK-DAG: [[queue:%\w+]] = OpConstant {{%\w+}} 5
; CHECK-DAG: [[wg:%\w+]] = OpConstant {{%\w+}} 2
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[wg]] MakePointerVisibleKHR|NonPrivatePointerKHR [[queue]]
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[wg]] MakePointerVisible|NonPrivatePointer [[queue]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "func" %src %dst
@@ -1913,7 +1913,7 @@
const std::string text = R"(
; CHECK-DAG: [[queue:%\w+]] = OpConstant {{%\w+}} 5
; CHECK-DAG: [[wg:%\w+]] = OpConstant {{%\w+}} 2
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned|MakePointerAvailableKHR|NonPrivatePointerKHR 4 [[queue]] Aligned|MakePointerVisibleKHR|NonPrivatePointerKHR 4 [[wg]]
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned|MakePointerAvailable|NonPrivatePointer 4 [[queue]] Aligned|MakePointerVisible|NonPrivatePointer 4 [[wg]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "func" %src %dst
@@ -1989,7 +1989,7 @@
TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryDstCoherentTwoOperands) {
const std::string text = R"(
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] None
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] None
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "func" %src %dst
@@ -2015,7 +2015,7 @@
SPV14CopyMemoryDstCoherentPreviousArgsTwoOperands) {
const std::string text = R"(
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
-; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned|MakePointerAvailableKHR|NonPrivatePointerKHR 4 [[scope]] Aligned 8
+; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned|MakePointerAvailable|NonPrivatePointer 4 [[scope]] Aligned 8
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "func" %src %dst
@@ -2236,4 +2236,37 @@
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
}
+TEST_F(UpgradeMemoryModelTest, CoherentStructMemberInArray) {
+ const std::string text = R"(
+; CHECK-NOT: OpMemberDecorate
+; CHECK: [[int:%[a-zA-Z0-9_]+]] = OpTypeInt 32 0
+; CHECK: [[device:%[a-zA-Z0-9_]+]] = OpConstant [[int]] 1
+; CHECK: OpLoad [[int]] {{.*}} MakePointerVisible|NonPrivatePointer
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+OpMemberDecorate %inner 1 Coherent
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_4 = OpConstant %int 4
+%inner = OpTypeStruct %int %int
+%array = OpTypeArray %inner %int_4
+%struct = OpTypeStruct %array
+%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
+%ptr_ssbo_int = OpTypePointer StorageBuffer %int
+%ssbo_var = OpVariable %ptr_ssbo_struct StorageBuffer
+%void_fn = OpTypeFunction %void
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+%gep = OpAccessChain %ptr_ssbo_int %ssbo_var %int_0 %int_0 %int_1
+%ld = OpLoad %int %gep
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
+}
+
} // namespace
diff --git a/test/opt/vector_dce_test.cpp b/test/opt/vector_dce_test.cpp
index a978a07..594995c 100644
--- a/test/opt/vector_dce_test.cpp
+++ b/test/opt/vector_dce_test.cpp
@@ -1158,74 +1158,6 @@
SinglePassRunAndCheck<VectorDCE>(text, text, true, true);
}
-TEST_F(VectorDCETest, InsertWithNoIndices) {
- const std::string text = R"(
-; CHECK: OpEntryPoint Fragment {{%\w+}} "PSMain" [[in1:%\w+]] [[in2:%\w+]] [[out:%\w+]]
-; CHECK: OpFunction
-; CHECK: [[ld:%\w+]] = OpLoad %v4float [[in2]]
-; CHECK: OpStore [[out]] [[ld]]
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %1 "PSMain" %2 %14 %3
- OpExecutionMode %1 OriginUpperLeft
- %void = OpTypeVoid
- %5 = OpTypeFunction %void
- %float = OpTypeFloat 32
- %v4float = OpTypeVector %float 4
-%_ptr_Input_v4float = OpTypePointer Input %v4float
-%_ptr_Output_v4float = OpTypePointer Output %v4float
- %2 = OpVariable %_ptr_Input_v4float Input
- %14 = OpVariable %_ptr_Input_v4float Input
- %3 = OpVariable %_ptr_Output_v4float Output
- %1 = OpFunction %void None %5
- %10 = OpLabel
- %13 = OpLoad %v4float %14
- %11 = OpLoad %v4float %2
- %12 = OpCompositeInsert %v4float %13 %11
- OpStore %3 %12
- OpReturn
- OpFunctionEnd
-)";
-
- SinglePassRunAndMatch<VectorDCE>(text, true);
-}
-
-TEST_F(VectorDCETest, ExtractWithNoIndices) {
- const std::string text = R"(
-; CHECK: OpLoad %float
-; CHECK: [[ld:%\w+]] = OpLoad %v4float
-; CHECK: [[ex1:%\w+]] = OpCompositeExtract %v4float [[ld]]
-; CHECK: [[ex2:%\w+]] = OpCompositeExtract %float [[ex1]] 1
-; CHECK: OpStore {{%\w+}} [[ex2]]
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %1 "PSMain" %2 %14 %3
- OpExecutionMode %1 OriginUpperLeft
- %void = OpTypeVoid
- %5 = OpTypeFunction %void
- %float = OpTypeFloat 32
- %v4float = OpTypeVector %float 4
-%_ptr_Input_float = OpTypePointer Input %float
-%_ptr_Input_v4float = OpTypePointer Input %v4float
-%_ptr_Output_float = OpTypePointer Output %float
- %2 = OpVariable %_ptr_Input_v4float Input
- %14 = OpVariable %_ptr_Input_float Input
- %3 = OpVariable %_ptr_Output_float Output
- %1 = OpFunction %void None %5
- %10 = OpLabel
- %13 = OpLoad %float %14
- %11 = OpLoad %v4float %2
- %12 = OpCompositeInsert %v4float %13 %11 0
- %20 = OpCompositeExtract %v4float %12
- %21 = OpCompositeExtract %float %20 1
- OpStore %3 %21
- OpReturn
- OpFunctionEnd
-)";
-
- SinglePassRunAndMatch<VectorDCE>(text, true);
-}
-
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/wrap_opkill_test.cpp b/test/opt/wrap_opkill_test.cpp
index df1b865..d50af28 100644
--- a/test/opt/wrap_opkill_test.cpp
+++ b/test/opt/wrap_opkill_test.cpp
@@ -31,7 +31,7 @@
; CHECK: [[orig_kill]] = OpFunction
; CHECK-NEXT: OpLabel
; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
-; CHECK-NEXT: OpUnreachable
+; CHECK-NEXT: OpReturn
; CHECK: [[new_kill]] = OpFunction
; CHECK-NEXT: OpLabel
; CHECK-NEXT: OpKill
@@ -83,10 +83,10 @@
; CHECK-NEXT: OpBranchConditional
; CHECK-NEXT: OpLabel
; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
-; CHECK-NEXT: OpUnreachable
+; CHECK-NEXT: OpReturn
; CHECK-NEXT: OpLabel
; CHECK-NEXT: OpFunctionCall %void [[new_kill]]
-; CHECK-NEXT: OpUnreachable
+; CHECK-NEXT: OpReturn
; CHECK: [[new_kill]] = OpFunction
; CHECK-NEXT: OpLabel
; CHECK-NEXT: OpKill
@@ -143,11 +143,11 @@
; CHECK: [[orig_kill1]] = OpFunction
; CHECK-NEXT: OpLabel
; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
-; CHECK-NEXT: OpUnreachable
+; CHECK-NEXT: OpReturn
; CHECK: [[orig_kill2]] = OpFunction
; CHECK-NEXT: OpLabel
; CHECK-NEXT: OpFunctionCall %void [[new_kill]]
-; CHECK-NEXT: OpUnreachable
+; CHECK-NEXT: OpReturn
; CHECK: [[new_kill]] = OpFunction
; CHECK-NEXT: OpLabel
; CHECK-NEXT: OpKill
@@ -193,19 +193,89 @@
SinglePassRunAndMatch<WrapOpKill>(text, true);
}
+TEST_F(WrapOpKillTest, FuncWithReturnValue) {
+ const std::string text = R"(
+; CHECK: OpEntryPoint Fragment [[main:%\w+]]
+; CHECK: [[main]] = OpFunction
+; CHECK: OpFunctionCall %int [[orig_kill:%\w+]]
+; CHECK: [[orig_kill]] = OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
+; CHECK-NEXT: [[undef:%\w+]] = OpUndef %int
+; CHECK-NEXT: OpReturnValue [[undef]]
+; CHECK: [[new_kill]] = OpFunction
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: OpKill
+; CHECK-NEXT: OpFunctionEnd
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 330
+ OpName %main "main"
+ %void = OpTypeVoid
+ %5 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %func_type = OpTypeFunction %int
+ %bool = OpTypeBool
+ %true = OpConstantTrue %bool
+ %main = OpFunction %void None %5
+ %8 = OpLabel
+ OpBranch %9
+ %9 = OpLabel
+ OpLoopMerge %10 %11 None
+ OpBranch %12
+ %12 = OpLabel
+ OpBranchConditional %true %13 %10
+ %13 = OpLabel
+ OpBranch %11
+ %11 = OpLabel
+ %14 = OpFunctionCall %int %kill_
+ OpBranch %9
+ %10 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %kill_ = OpFunction %int None %func_type
+ %15 = OpLabel
+ OpKill
+ OpFunctionEnd
+ )";
+
+ SinglePassRunAndMatch<WrapOpKill>(text, true);
+}
+
TEST_F(WrapOpKillTest, IdBoundOverflow1) {
const std::string text = R"(
OpCapability GeometryStreams
OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %4 "main"
-OpExecutionMode %4 OriginUpperLeft
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
%2 = OpTypeVoid
%3 = OpTypeFunction %2
-%4 = OpFunction %2 Pure|Const %3
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%main = OpFunction %2 None %3
+%8 = OpLabel
+OpBranch %9
+%9 = OpLabel
+OpLoopMerge %10 %11 None
+OpBranch %12
+%12 = OpLabel
+OpBranchConditional %true %13 %10
+%13 = OpLabel
+OpBranch %11
+%11 = OpLabel
+%14 = OpFunctionCall %void %kill_
+OpBranch %9
+%10 = OpLabel
+OpReturn
+OpFunctionEnd
+%kill_ = OpFunction %2 Pure|Const %3
%4194302 = OpLabel
OpKill
OpFunctionEnd
- )";
+)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
@@ -220,15 +290,33 @@
const std::string text = R"(
OpCapability GeometryStreams
OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %4 "main"
-OpExecutionMode %4 OriginUpperLeft
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
%2 = OpTypeVoid
%3 = OpTypeFunction %2
-%4 = OpFunction %2 Pure|Const %3
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%main = OpFunction %2 None %3
+%8 = OpLabel
+OpBranch %9
+%9 = OpLabel
+OpLoopMerge %10 %11 None
+OpBranch %12
+%12 = OpLabel
+OpBranchConditional %true %13 %10
+%13 = OpLabel
+OpBranch %11
+%11 = OpLabel
+%14 = OpFunctionCall %void %kill_
+OpBranch %9
+%10 = OpLabel
+OpReturn
+OpFunctionEnd
+%kill_ = OpFunction %2 Pure|Const %3
%4194301 = OpLabel
OpKill
OpFunctionEnd
- )";
+)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
@@ -243,15 +331,33 @@
const std::string text = R"(
OpCapability GeometryStreams
OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %4 "main"
-OpExecutionMode %4 OriginUpperLeft
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
%2 = OpTypeVoid
%3 = OpTypeFunction %2
-%4 = OpFunction %2 Pure|Const %3
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%main = OpFunction %2 None %3
+%8 = OpLabel
+OpBranch %9
+%9 = OpLabel
+OpLoopMerge %10 %11 None
+OpBranch %12
+%12 = OpLabel
+OpBranchConditional %true %13 %10
+%13 = OpLabel
+OpBranch %11
+%11 = OpLabel
+%14 = OpFunctionCall %void %kill_
+OpBranch %9
+%10 = OpLabel
+OpReturn
+OpFunctionEnd
+%kill_ = OpFunction %2 Pure|Const %3
%4194300 = OpLabel
OpKill
OpFunctionEnd
- )";
+)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
@@ -262,6 +368,151 @@
EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
}
+TEST_F(WrapOpKillTest, IdBoundOverflow4) {
+ const std::string text = R"(
+OpCapability DerivativeControl
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %2 Location 539091968
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%main = OpFunction %2 None %3
+%8 = OpLabel
+OpBranch %9
+%9 = OpLabel
+OpLoopMerge %10 %11 None
+OpBranch %12
+%12 = OpLabel
+OpBranchConditional %true %13 %10
+%13 = OpLabel
+OpBranch %11
+%11 = OpLabel
+%14 = OpFunctionCall %void %kill_
+OpBranch %9
+%10 = OpLabel
+OpReturn
+OpFunctionEnd
+%kill_ = OpFunction %2 Inline|Pure|Const %3
+%4194302 = OpLabel
+OpKill
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ std::vector<Message> messages = {
+ {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
+ SetMessageConsumer(GetTestMessageConsumer(messages));
+ auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
+ EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
+}
+
+TEST_F(WrapOpKillTest, IdBoundOverflow5) {
+ const std::string text = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "main"
+ OpExecutionMode %1 OriginUpperLeft
+ OpDecorate %void Location 539091968
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %_struct_5 = OpTypeStruct %float %float
+ %_struct_6 = OpTypeStruct %_struct_5
+%_ptr_Function__struct_6 = OpTypePointer Function %_struct_6
+%_ptr_Output_float = OpTypePointer Output %float
+ %9 = OpTypeFunction %_struct_5 %_ptr_Function__struct_6
+ %bool = OpTypeBool
+ %true = OpConstantTrue %bool
+ %1 = OpFunction %void None %3
+ %12 = OpLabel
+ %13 = OpVariable %_ptr_Function__struct_6 Function
+ OpBranch %14
+ %14 = OpLabel
+ OpLoopMerge %15 %16 None
+ OpBranch %17
+ %17 = OpLabel
+ OpBranchConditional %true %18 %15
+ %18 = OpLabel
+ OpBranch %16
+ %16 = OpLabel
+ %19 = OpFunctionCall %void %20
+ %21 = OpFunctionCall %_struct_5 %22 %13
+ OpBranch %14
+ %15 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %20 = OpFunction %void Inline|Pure|Const %3
+ %23 = OpLabel
+ %24 = OpVariable %_ptr_Function__struct_6 Function
+ %25 = OpFunctionCall %_struct_5 %26 %24
+ OpKill
+ OpFunctionEnd
+ %26 = OpFunction %_struct_5 None %9
+ %27 = OpLabel
+ OpUnreachable
+ OpFunctionEnd
+ %22 = OpFunction %_struct_5 Inline %9
+ %4194295 = OpLabel
+ OpKill
+ OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+
+ std::vector<Message> messages = {
+ {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
+ SetMessageConsumer(GetTestMessageConsumer(messages));
+ auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
+ EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
+}
+
+TEST_F(WrapOpKillTest, SkipEntryPoint) {
+ const std::string text = R"(
+OpCapability GeometryStreams
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %4 "main"
+OpExecutionMode %4 OriginUpperLeft
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%4 = OpFunction %2 Pure|Const %3
+%5 = OpLabel
+OpKill
+OpFunctionEnd
+)";
+
+ auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
+ EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
+}
+
+TEST_F(WrapOpKillTest, SkipFunctionNotInContinue) {
+ const std::string text = R"(
+OpCapability GeometryStreams
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%main = OpFunction %2 None %3
+%6 = OpLabel
+%7 = OpFunctionCall %void %4
+OpReturn
+OpFunctionEnd
+%4 = OpFunction %2 Pure|Const %3
+%5 = OpLabel
+OpKill
+OpFunctionEnd
+)";
+
+ auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
+ EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/reduce/CMakeLists.txt b/test/reduce/CMakeLists.txt
index 2d3b378..b19bba4 100644
--- a/test/reduce/CMakeLists.txt
+++ b/test/reduce/CMakeLists.txt
@@ -23,8 +23,6 @@
reducer_test.cpp
remove_block_test.cpp
remove_function_test.cpp
- remove_opname_instruction_test.cpp
- remove_relaxed_precision_decoration_test.cpp
remove_selection_test.cpp
remove_unreferenced_instruction_test.cpp
structured_loop_to_selection_test.cpp
diff --git a/test/reduce/reducer_test.cpp b/test/reduce/reducer_test.cpp
index 8787733..a650d3b 100644
--- a/test/reduce/reducer_test.cpp
+++ b/test/reduce/reducer_test.cpp
@@ -14,8 +14,8 @@
#include "source/reduce/reducer.h"
+#include "source/opt/build_module.h"
#include "source/reduce/operand_to_const_reduction_opportunity_finder.h"
-#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h"
#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h"
#include "test/reduce/reduce_test_util.h"
@@ -23,6 +23,12 @@
namespace reduce {
namespace {
+using opt::BasicBlock;
+using opt::IRContext;
+
+const spv_target_env kEnv = SPV_ENV_UNIVERSAL_1_3;
+const MessageConsumer kMessageConsumer = CLIMessageConsumer;
+
// This changes its mind each time IsInteresting is invoked as to whether the
// binary is interesting, until some limit is reached after which the binary is
// always deemed interesting. This is useful to test that reduction passes
@@ -55,6 +61,8 @@
};
TEST(ReducerTest, ExprToConstantAndRemoveUnreferenced) {
+ // Check that ExprToConstant and RemoveUnreferenced work together; once some
+ // ID uses have been changed to constants, those IDs can be removed.
std::string original = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
@@ -149,15 +157,6 @@
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main" %60
OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- OpName %4 "main"
- OpName %16 "buf2"
- OpMemberName %16 0 "i"
- OpName %18 ""
- OpName %25 "buf1"
- OpMemberName %25 0 "f"
- OpName %27 ""
- OpName %60 "_GLF_color"
OpMemberDecorate %16 0 Offset 0
OpDecorate %16 Block
OpDecorate %18 DescriptorSet 0
@@ -174,14 +173,12 @@
%16 = OpTypeStruct %6
%17 = OpTypePointer Uniform %16
%18 = OpVariable %17 Uniform
- %19 = OpTypePointer Uniform %6
%22 = OpTypeBool
%100 = OpConstantTrue %22
%24 = OpTypeFloat 32
%25 = OpTypeStruct %24
%26 = OpTypePointer Uniform %25
%27 = OpVariable %26 Uniform
- %28 = OpTypePointer Uniform %24
%31 = OpConstant %24 2
%56 = OpConstant %6 1
%58 = OpTypeVector %24 4
@@ -209,8 +206,7 @@
OpFunctionEnd
)";
- spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
- Reducer reducer(env);
+ Reducer reducer(kEnv);
PingPongInteresting ping_pong_interesting(10);
reducer.SetMessageConsumer(NopDiagnostic);
reducer.SetInterestingnessFunction(
@@ -218,12 +214,13 @@
return ping_pong_interesting.IsInteresting(binary);
});
reducer.AddReductionPass(
- MakeUnique<OperandToConstReductionOpportunityFinder>());
+ MakeUnique<RemoveUnreferencedInstructionReductionOpportunityFinder>(
+ false));
reducer.AddReductionPass(
- MakeUnique<RemoveUnreferencedInstructionReductionOpportunityFinder>());
+ MakeUnique<OperandToConstReductionOpportunityFinder>());
std::vector<uint32_t> binary_in;
- SpirvTools t(env);
+ SpirvTools t(kEnv);
ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption));
std::vector<uint32_t> binary_out;
@@ -237,71 +234,169 @@
ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete);
- CheckEqual(env, expected, binary_out);
+ CheckEqual(kEnv, expected, binary_out);
}
-TEST(ReducerTest, RemoveOpnameAndRemoveUnreferenced) {
- const std::string original = R"(
+bool InterestingWhileOpcodeExists(const std::vector<uint32_t>& binary,
+ uint32_t opcode, uint32_t count, bool dump) {
+ if (dump) {
+ std::stringstream ss;
+ ss << "temp_" << count << ".spv";
+ DumpShader(binary, ss.str().c_str());
+ }
+
+ std::unique_ptr<IRContext> context =
+ BuildModule(kEnv, kMessageConsumer, binary.data(), binary.size());
+ assert(context);
+ bool interesting = false;
+ for (auto& function : *context->module()) {
+ context->cfg()->ForEachBlockInPostOrder(
+ &*function.begin(), [opcode, &interesting](BasicBlock* block) -> void {
+ for (auto& inst : *block) {
+ if (inst.opcode() == opcode) {
+ interesting = true;
+ break;
+ }
+ }
+ });
+ if (interesting) {
+ break;
+ }
+ }
+ return interesting;
+}
+
+bool InterestingWhileIMulReachable(const std::vector<uint32_t>& binary,
+ uint32_t count) {
+ return InterestingWhileOpcodeExists(binary, SpvOpIMul, count, false);
+}
+
+bool InterestingWhileSDivReachable(const std::vector<uint32_t>& binary,
+ uint32_t count) {
+ return InterestingWhileOpcodeExists(binary, SpvOpSDiv, count, false);
+}
+
+// The shader below was derived from the following GLSL, and optimized.
+// #version 310 es
+// precision highp float;
+// layout(location = 0) out vec4 _GLF_color;
+// int foo() {
+// int x = 1;
+// int y;
+// x = y / x; // SDiv
+// return x;
+// }
+// void main() {
+// int c;
+// while (bool(c)) {
+// do {
+// if (bool(c)) {
+// if (bool(c)) {
+// ++c;
+// } else {
+// _GLF_color.x = float(c*c); // IMul
+// }
+// return;
+// }
+// } while(bool(foo()));
+// return;
+// }
+// }
+const std::string kShaderWithLoopsDivAndMul = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %2 "main"
- OpExecutionMode %2 OriginUpperLeft
+ OpEntryPoint Fragment %4 "main" %49
+ OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
- OpName %2 "main"
- OpName %3 "a"
- OpName %4 "this-name-counts-as-usage-for-load-instruction"
- %5 = OpTypeVoid
- %6 = OpTypeFunction %5
- %7 = OpTypeFloat 32
- %8 = OpTypePointer Function %7
- %9 = OpConstant %7 1
- %2 = OpFunction %5 None %6
- %10 = OpLabel
- %3 = OpVariable %8 Function
- %4 = OpLoad %7 %3
- OpStore %3 %9
+ OpName %4 "main"
+ OpName %49 "_GLF_color"
+ OpDecorate %49 Location 0
+ OpDecorate %52 RelaxedPrecision
+ OpDecorate %77 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %12 = OpConstant %6 1
+ %27 = OpTypeBool
+ %28 = OpTypeInt 32 0
+ %29 = OpConstant %28 0
+ %46 = OpTypeFloat 32
+ %47 = OpTypeVector %46 4
+ %48 = OpTypePointer Output %47
+ %49 = OpVariable %48 Output
+ %54 = OpTypePointer Output %46
+ %64 = OpConstantFalse %27
+ %67 = OpConstantTrue %27
+ %81 = OpUndef %6
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpBranch %61
+ %61 = OpLabel
+ OpLoopMerge %60 %63 None
+ OpBranch %20
+ %20 = OpLabel
+ %30 = OpINotEqual %27 %81 %29
+ OpLoopMerge %22 %23 None
+ OpBranchConditional %30 %21 %22
+ %21 = OpLabel
+ OpBranch %31
+ %31 = OpLabel
+ OpLoopMerge %33 %38 None
+ OpBranch %32
+ %32 = OpLabel
+ OpSelectionMerge %38 None
+ OpBranchConditional %30 %37 %38
+ %37 = OpLabel
+ OpSelectionMerge %42 None
+ OpBranchConditional %30 %41 %45
+ %41 = OpLabel
+ OpBranch %42
+ %45 = OpLabel
+ %52 = OpIMul %6 %81 %81
+ %53 = OpConvertSToF %46 %52
+ %55 = OpAccessChain %54 %49 %29
+ OpStore %55 %53
+ OpBranch %42
+ %42 = OpLabel
+ OpBranch %33
+ %38 = OpLabel
+ %77 = OpSDiv %6 %81 %12
+ %58 = OpINotEqual %27 %77 %29
+ OpBranchConditional %58 %31 %33
+ %33 = OpLabel
+ %86 = OpPhi %27 %67 %42 %64 %38
+ OpSelectionMerge %68 None
+ OpBranchConditional %86 %22 %68
+ %68 = OpLabel
+ OpBranch %22
+ %23 = OpLabel
+ OpBranch %20
+ %22 = OpLabel
+ %90 = OpPhi %27 %64 %20 %86 %33 %67 %68
+ OpSelectionMerge %70 None
+ OpBranchConditional %90 %60 %70
+ %70 = OpLabel
+ OpBranch %60
+ %63 = OpLabel
+ OpBranch %61
+ %60 = OpLabel
OpReturn
OpFunctionEnd
)";
- const std::string expected = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %2 "main"
- OpExecutionMode %2 OriginUpperLeft
- OpSource ESSL 310
- %5 = OpTypeVoid
- %6 = OpTypeFunction %5
- %7 = OpTypeFloat 32
- %8 = OpTypePointer Function %7
- %9 = OpConstant %7 1
- %2 = OpFunction %5 None %6
- %10 = OpLabel
- OpReturn
- OpFunctionEnd
- )";
+TEST(ReducerTest, ShaderReduceWhileMulReachable) {
+ Reducer reducer(kEnv);
- spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
- Reducer reducer(env);
- // Make ping-pong interesting very quickly, as there are not many
- // opportunities.
- PingPongInteresting ping_pong_interesting(1);
- reducer.SetMessageConsumer(NopDiagnostic);
- reducer.SetInterestingnessFunction(
- [&](const std::vector<uint32_t>& binary, uint32_t) -> bool {
- return ping_pong_interesting.IsInteresting(binary);
- });
- reducer.AddReductionPass(
- MakeUnique<RemoveOpNameInstructionReductionOpportunityFinder>());
- reducer.AddReductionPass(
- MakeUnique<RemoveUnreferencedInstructionReductionOpportunityFinder>());
+ reducer.SetInterestingnessFunction(InterestingWhileIMulReachable);
+ reducer.AddDefaultReductionPasses();
+ reducer.SetMessageConsumer(kMessageConsumer);
std::vector<uint32_t> binary_in;
- SpirvTools t(env);
+ SpirvTools t(kEnv);
- ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption));
+ ASSERT_TRUE(
+ t.Assemble(kShaderWithLoopsDivAndMul, &binary_in, kReduceAssembleOption));
std::vector<uint32_t> binary_out;
spvtools::ReducerOptions reducer_options;
reducer_options.set_step_limit(500);
@@ -312,8 +407,30 @@
std::move(binary_in), &binary_out, reducer_options, validator_options);
ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete);
+}
- CheckEqual(env, expected, binary_out);
+TEST(ReducerTest, ShaderReduceWhileDivReachable) {
+ Reducer reducer(kEnv);
+
+ reducer.SetInterestingnessFunction(InterestingWhileSDivReachable);
+ reducer.AddDefaultReductionPasses();
+ reducer.SetMessageConsumer(kMessageConsumer);
+
+ std::vector<uint32_t> binary_in;
+ SpirvTools t(kEnv);
+
+ ASSERT_TRUE(
+ t.Assemble(kShaderWithLoopsDivAndMul, &binary_in, kReduceAssembleOption));
+ std::vector<uint32_t> binary_out;
+ spvtools::ReducerOptions reducer_options;
+ reducer_options.set_step_limit(500);
+ reducer_options.set_fail_on_validation_error(true);
+ spvtools::ValidatorOptions validator_options;
+
+ Reducer::ReductionResultStatus status = reducer.Run(
+ std::move(binary_in), &binary_out, reducer_options, validator_options);
+
+ ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete);
}
} // namespace
diff --git a/test/reduce/remove_opname_instruction_test.cpp b/test/reduce/remove_opname_instruction_test.cpp
deleted file mode 100644
index 9d40cfc..0000000
--- a/test/reduce/remove_opname_instruction_test.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-// 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.
-
-#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h"
-
-#include "source/opt/build_module.h"
-#include "source/reduce/reduction_opportunity.h"
-#include "source/reduce/reduction_pass.h"
-#include "test/reduce/reduce_test_util.h"
-
-namespace spvtools {
-namespace reduce {
-namespace {
-
-TEST(RemoveOpnameInstructionReductionPassTest, NothingToRemove) {
- const std::string source = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main"
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- OpReturn
- OpFunctionEnd
- )";
-
- const auto env = SPV_ENV_UNIVERSAL_1_3;
- const auto consumer = nullptr;
- const auto context =
- BuildModule(env, consumer, source, kReduceAssembleOption);
- const auto ops = RemoveOpNameInstructionReductionOpportunityFinder()
- .GetAvailableOpportunities(context.get());
- ASSERT_EQ(0, ops.size());
-}
-
-TEST(RemoveOpnameInstructionReductionPassTest, RemoveSingleOpName) {
- const std::string prologue = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main"
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- )";
-
- const std::string epilogue = R"(
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- OpReturn
- OpFunctionEnd
- )";
-
- const std::string original = prologue + R"(
- OpName %4 "main"
- )" + epilogue;
-
- const std::string expected = prologue + epilogue;
-
- const auto env = SPV_ENV_UNIVERSAL_1_3;
- const auto consumer = nullptr;
- const auto context =
- BuildModule(env, consumer, original, kReduceAssembleOption);
- const auto ops = RemoveOpNameInstructionReductionOpportunityFinder()
- .GetAvailableOpportunities(context.get());
- ASSERT_EQ(1, ops.size());
- ASSERT_TRUE(ops[0]->PreconditionHolds());
- ops[0]->TryToApply();
-
- CheckEqual(env, expected, context.get());
-}
-
-TEST(RemoveOpnameInstructionReductionPassTest, TryApplyRemovesAllOpName) {
- const std::string prologue = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main"
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- )";
-
- const std::string epilogue = R"(
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %6 = OpTypeFloat 32
- %7 = OpTypePointer Function %6
- %9 = OpConstant %6 1
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- %8 = OpVariable %7 Function
- %10 = OpVariable %7 Function
- %11 = OpVariable %7 Function
- %12 = OpVariable %7 Function
- OpStore %8 %9
- OpStore %10 %9
- OpStore %11 %9
- OpStore %12 %9
- OpReturn
- OpFunctionEnd
- )";
-
- const std::string original = prologue + R"(
- OpName %4 "main"
- OpName %8 "a"
- OpName %10 "b"
- OpName %11 "c"
- OpName %12 "d"
- )" + epilogue;
-
- const std::string expected = prologue + epilogue;
-
- const auto env = SPV_ENV_UNIVERSAL_1_3;
-
- {
- // Check the right number of opportunities is detected
- const auto consumer = nullptr;
- const auto context =
- BuildModule(env, consumer, original, kReduceAssembleOption);
- const auto ops = RemoveOpNameInstructionReductionOpportunityFinder()
- .GetAvailableOpportunities(context.get());
- ASSERT_EQ(5, ops.size());
- }
-
- {
- // The reduction should remove all OpName
- std::vector<uint32_t> binary;
- SpirvTools t(env);
- ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption));
- auto reduced_binary =
- ReductionPass(env,
- spvtools::MakeUnique<
- RemoveOpNameInstructionReductionOpportunityFinder>())
- .TryApplyReduction(binary);
- CheckEqual(env, expected, reduced_binary);
- }
-}
-
-TEST(RemoveOpnameInstructionReductionPassTest,
- TryApplyRemovesAllOpNameAndOpMemberName) {
- const std::string prologue = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main"
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- )";
-
- const std::string epilogue = R"(
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %6 = OpTypeFloat 32
- %7 = OpTypeInt 32 1
- %8 = OpTypeVector %6 3
- %9 = OpTypeStruct %6 %7 %8
- %10 = OpTypePointer Function %9
- %12 = OpConstant %7 0
- %13 = OpConstant %6 1
- %14 = OpTypePointer Function %6
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- %11 = OpVariable %10 Function
- %15 = OpAccessChain %14 %11 %12
- OpStore %15 %13
- OpReturn
- OpFunctionEnd
- )";
-
- const std::string original = prologue + R"(
- OpName %4 "main"
- OpName %9 "S"
- OpMemberName %9 0 "f"
- OpMemberName %9 1 "i"
- OpMemberName %9 2 "v"
- OpName %11 "s"
- )" + epilogue;
-
- const std::string expected = prologue + epilogue;
-
- const auto env = SPV_ENV_UNIVERSAL_1_3;
-
- {
- // Check the right number of opportunities is detected
- const auto consumer = nullptr;
- const auto context =
- BuildModule(env, consumer, original, kReduceAssembleOption);
- const auto ops = RemoveOpNameInstructionReductionOpportunityFinder()
- .GetAvailableOpportunities(context.get());
- ASSERT_EQ(6, ops.size());
- }
-
- {
- // The reduction should remove all OpName
- std::vector<uint32_t> binary;
- SpirvTools t(env);
- ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption));
- auto reduced_binary =
- ReductionPass(env,
- spvtools::MakeUnique<
- RemoveOpNameInstructionReductionOpportunityFinder>())
- .TryApplyReduction(binary);
- CheckEqual(env, expected, reduced_binary);
- }
-}
-
-} // namespace
-} // namespace reduce
-} // namespace spvtools
diff --git a/test/reduce/remove_relaxed_precision_decoration_test.cpp b/test/reduce/remove_relaxed_precision_decoration_test.cpp
deleted file mode 100644
index f9ff081..0000000
--- a/test/reduce/remove_relaxed_precision_decoration_test.cpp
+++ /dev/null
@@ -1,177 +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/reduce/remove_relaxed_precision_decoration_opportunity_finder.h"
-
-#include "source/opt/build_module.h"
-#include "source/reduce/reduction_opportunity.h"
-#include "source/reduce/reduction_pass.h"
-#include "test/reduce/reduce_test_util.h"
-
-namespace spvtools {
-namespace reduce {
-namespace {
-
-TEST(RemoveRelaxedPrecisionDecorationTest, NothingToRemove) {
- const std::string source = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main"
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- OpReturn
- OpFunctionEnd
- )";
-
- const auto env = SPV_ENV_UNIVERSAL_1_3;
- const auto consumer = nullptr;
- const auto context =
- BuildModule(env, consumer, source, kReduceAssembleOption);
- const auto ops = RemoveRelaxedPrecisionDecorationOpportunityFinder()
- .GetAvailableOpportunities(context.get());
- ASSERT_EQ(0, ops.size());
-}
-
-TEST(RemoveRelaxedPrecisionDecorationTest, RemoveDecorations) {
- const std::string source = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main"
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- OpName %4 "main"
- OpName %8 "f"
- OpName %12 "i"
- OpName %16 "v"
- OpName %19 "S"
- OpMemberName %19 0 "a"
- OpMemberName %19 1 "b"
- OpMemberName %19 2 "c"
- OpName %21 "s"
- OpDecorate %8 RelaxedPrecision
- OpDecorate %12 RelaxedPrecision
- OpDecorate %16 RelaxedPrecision
- OpDecorate %17 RelaxedPrecision
- OpDecorate %18 RelaxedPrecision
- OpMemberDecorate %19 0 RelaxedPrecision
- OpMemberDecorate %19 1 RelaxedPrecision
- OpMemberDecorate %19 2 RelaxedPrecision
- OpDecorate %22 RelaxedPrecision
- OpDecorate %23 RelaxedPrecision
- OpDecorate %24 RelaxedPrecision
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %6 = OpTypeFloat 32
- %7 = OpTypePointer Function %6
- %9 = OpConstant %6 2
- %10 = OpTypeInt 32 1
- %11 = OpTypePointer Function %10
- %13 = OpConstant %10 22
- %14 = OpTypeVector %6 2
- %15 = OpTypePointer Function %14
- %19 = OpTypeStruct %10 %6 %14
- %20 = OpTypePointer Function %19
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- %8 = OpVariable %7 Function
- %12 = OpVariable %11 Function
- %16 = OpVariable %15 Function
- %21 = OpVariable %20 Function
- OpStore %8 %9
- OpStore %12 %13
- %17 = OpLoad %6 %8
- %18 = OpCompositeConstruct %14 %17 %17
- OpStore %16 %18
- %22 = OpLoad %10 %12
- %23 = OpLoad %6 %8
- %24 = OpLoad %14 %16
- %25 = OpCompositeConstruct %19 %22 %23 %24
- OpStore %21 %25
- OpReturn
- OpFunctionEnd
- )";
-
- const auto env = SPV_ENV_UNIVERSAL_1_3;
- const auto consumer = nullptr;
- const auto context =
- BuildModule(env, consumer, source, kReduceAssembleOption);
- const auto ops = RemoveRelaxedPrecisionDecorationOpportunityFinder()
- .GetAvailableOpportunities(context.get());
- ASSERT_EQ(11, ops.size());
-
- for (auto& op : ops) {
- ASSERT_TRUE(op->PreconditionHolds());
- op->TryToApply();
- }
-
- const std::string expected = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main"
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- OpName %4 "main"
- OpName %8 "f"
- OpName %12 "i"
- OpName %16 "v"
- OpName %19 "S"
- OpMemberName %19 0 "a"
- OpMemberName %19 1 "b"
- OpMemberName %19 2 "c"
- OpName %21 "s"
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %6 = OpTypeFloat 32
- %7 = OpTypePointer Function %6
- %9 = OpConstant %6 2
- %10 = OpTypeInt 32 1
- %11 = OpTypePointer Function %10
- %13 = OpConstant %10 22
- %14 = OpTypeVector %6 2
- %15 = OpTypePointer Function %14
- %19 = OpTypeStruct %10 %6 %14
- %20 = OpTypePointer Function %19
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- %8 = OpVariable %7 Function
- %12 = OpVariable %11 Function
- %16 = OpVariable %15 Function
- %21 = OpVariable %20 Function
- OpStore %8 %9
- OpStore %12 %13
- %17 = OpLoad %6 %8
- %18 = OpCompositeConstruct %14 %17 %17
- OpStore %16 %18
- %22 = OpLoad %10 %12
- %23 = OpLoad %6 %8
- %24 = OpLoad %14 %16
- %25 = OpCompositeConstruct %19 %22 %23 %24
- OpStore %21 %25
- OpReturn
- OpFunctionEnd
- )";
-
- CheckEqual(env, expected, context.get());
-}
-
-} // namespace
-} // namespace reduce
-} // namespace spvtools
diff --git a/test/reduce/remove_unreferenced_instruction_test.cpp b/test/reduce/remove_unreferenced_instruction_test.cpp
index 0babf78..3caf88c 100644
--- a/test/reduce/remove_unreferenced_instruction_test.cpp
+++ b/test/reduce/remove_unreferenced_instruction_test.cpp
@@ -23,19 +23,26 @@
namespace reduce {
namespace {
+const spv_target_env kEnv = SPV_ENV_UNIVERSAL_1_3;
+
TEST(RemoveUnreferencedInstructionReductionPassTest, RemoveStores) {
- const std::string prologue = R"(
+ // A module with some unused instructions, including some unused OpStore
+ // instructions.
+
+ RemoveUnreferencedInstructionReductionOpportunityFinder finder(true);
+
+ const std::string original = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- OpName %4 "main"
- OpName %8 "a"
- OpName %10 "b"
- OpName %12 "c"
- OpName %14 "d"
+ OpSource ESSL 310 ; 0
+ OpName %4 "main" ; 1
+ OpName %8 "a" ; 2
+ OpName %10 "b" ; 3
+ OpName %12 "c" ; 4
+ OpName %14 "d" ; 5
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
@@ -49,51 +56,323 @@
%10 = OpVariable %7 Function
%12 = OpVariable %7 Function
%14 = OpVariable %7 Function
+ OpStore %8 %9 ; 6
+ OpStore %10 %11 ; 7
+ OpStore %12 %13 ; 8
+ %15 = OpLoad %6 %8
+ OpStore %14 %15 ; 9
+ OpReturn
+ OpFunctionEnd
+
)";
- const std::string epilogue = R"(
+ const MessageConsumer consumer = nullptr;
+ const auto context =
+ BuildModule(kEnv, consumer, original, kReduceAssembleOption);
+
+ CheckValid(kEnv, context.get());
+
+ auto ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(10, ops.size());
+
+ for (auto& op : ops) {
+ ASSERT_TRUE(op->PreconditionHolds());
+ op->TryToApply();
+ CheckValid(kEnv, context.get());
+ }
+
+ const std::string step_2 = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %9 = OpConstant %6 10 ; 0
+ %11 = OpConstant %6 20 ; 1
+ %13 = OpConstant %6 30 ; 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function
+ %10 = OpVariable %7 Function ; 3
+ %12 = OpVariable %7 Function ; 4
+ %14 = OpVariable %7 Function ; 5
+ %15 = OpLoad %6 %8 ; 6
OpReturn
OpFunctionEnd
)";
- const std::string original = prologue + R"(
- OpStore %8 %9
- OpStore %10 %11
- OpStore %12 %13
- %15 = OpLoad %6 %8
- OpStore %14 %15
- )" + epilogue;
+ CheckEqual(kEnv, step_2, context.get());
- const std::string expected_after_2 = prologue + R"(
- OpStore %12 %13
- %15 = OpLoad %6 %8
- OpStore %14 %15
- )" + epilogue;
+ ops = finder.GetAvailableOpportunities(context.get());
- const std::string expected_after_4 = prologue + R"(
- %15 = OpLoad %6 %8
- )" + epilogue;
+ ASSERT_EQ(7, ops.size());
- const auto env = SPV_ENV_UNIVERSAL_1_3;
- const auto consumer = nullptr;
- const auto context =
- BuildModule(env, consumer, original, kReduceAssembleOption);
- const auto ops = RemoveUnreferencedInstructionReductionOpportunityFinder()
- .GetAvailableOpportunities(context.get());
- ASSERT_EQ(4, ops.size());
- ASSERT_TRUE(ops[0]->PreconditionHolds());
- ops[0]->TryToApply();
- ASSERT_TRUE(ops[1]->PreconditionHolds());
- ops[1]->TryToApply();
+ for (auto& op : ops) {
+ ASSERT_TRUE(op->PreconditionHolds());
+ op->TryToApply();
+ CheckValid(kEnv, context.get());
+ }
- CheckEqual(env, expected_after_2, context.get());
+ const std::string step_3 = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpVariable %7 Function ; 0
+ OpReturn
+ OpFunctionEnd
+ )";
- ASSERT_TRUE(ops[2]->PreconditionHolds());
- ops[2]->TryToApply();
- ASSERT_TRUE(ops[3]->PreconditionHolds());
- ops[3]->TryToApply();
+ CheckEqual(kEnv, step_3, context.get());
- CheckEqual(env, expected_after_4, context.get());
+ ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(1, ops.size());
+
+ for (auto& op : ops) {
+ ASSERT_TRUE(op->PreconditionHolds());
+ op->TryToApply();
+ CheckValid(kEnv, context.get());
+ }
+
+ const std::string step_4 = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypePointer Function %6 ; 0
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CheckEqual(kEnv, step_4, context.get());
+
+ ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(1, ops.size());
+
+ for (auto& op : ops) {
+ ASSERT_TRUE(op->PreconditionHolds());
+ op->TryToApply();
+ CheckValid(kEnv, context.get());
+ }
+
+ const std::string step_5 = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1 ; 0
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CheckEqual(kEnv, step_5, context.get());
+
+ ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(1, ops.size());
+
+ for (auto& op : ops) {
+ ASSERT_TRUE(op->PreconditionHolds());
+ op->TryToApply();
+ CheckValid(kEnv, context.get());
+ }
+
+ const std::string step_6 = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CheckEqual(kEnv, step_6, context.get());
+
+ ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(0, ops.size());
+}
+
+TEST(RemoveUnreferencedInstructionReductionPassTest, Referenced) {
+ // A module with some unused global variables, constants, and types. Some will
+ // not be removed initially because of the OpDecorate instructions.
+
+ RemoveUnreferencedInstructionReductionOpportunityFinder finder(true);
+
+ const std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310 ; 1
+ OpName %4 "main" ; 2
+ OpName %12 "a" ; 3
+ OpDecorate %12 RelaxedPrecision ; 4
+ OpDecorate %13 RelaxedPrecision ; 5
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeBool
+ %7 = OpConstantTrue %6 ; 6
+ %10 = OpTypeInt 32 1
+ %11 = OpTypePointer Private %10
+ %12 = OpVariable %11 Private
+ %13 = OpConstant %10 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ auto context = BuildModule(kEnv, nullptr, shader, kReduceAssembleOption);
+
+ CheckValid(kEnv, context.get());
+
+ auto ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(6, ops.size());
+
+ for (auto& op : ops) {
+ ASSERT_TRUE(op->PreconditionHolds());
+ op->TryToApply();
+ CheckValid(kEnv, context.get());
+ }
+
+ std::string after = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeBool ; 1
+ %10 = OpTypeInt 32 1
+ %11 = OpTypePointer Private %10
+ %12 = OpVariable %11 Private ; 2
+ %13 = OpConstant %10 1 ; 3
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CheckEqual(kEnv, after, context.get());
+
+ ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(3, ops.size());
+
+ for (auto& op : ops) {
+ ASSERT_TRUE(op->PreconditionHolds());
+ op->TryToApply();
+ CheckValid(kEnv, context.get());
+ }
+
+ std::string after_2 = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeInt 32 1
+ %11 = OpTypePointer Private %10 ; 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CheckEqual(kEnv, after_2, context.get());
+
+ ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(1, ops.size());
+
+ for (auto& op : ops) {
+ ASSERT_TRUE(op->PreconditionHolds());
+ op->TryToApply();
+ CheckValid(kEnv, context.get());
+ }
+
+ std::string after_3 = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeInt 32 1 ; 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CheckEqual(kEnv, after_3, context.get());
+
+ ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(1, ops.size());
+
+ for (auto& op : ops) {
+ ASSERT_TRUE(op->PreconditionHolds());
+ op->TryToApply();
+ CheckValid(kEnv, context.get());
+ }
+
+ std::string after_4 = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CheckEqual(kEnv, after_4, context.get());
+
+ ops = finder.GetAvailableOpportunities(context.get());
+
+ ASSERT_EQ(0, ops.size());
}
} // namespace
diff --git a/test/text_to_binary.constant_test.cpp b/test/text_to_binary.constant_test.cpp
index 6624d41..679bee4 100644
--- a/test/text_to_binary.constant_test.cpp
+++ b/test/text_to_binary.constant_test.cpp
@@ -328,7 +328,6 @@
using OpConstantInvalidTypeTest =
spvtest::TextToBinaryTestBase<::testing::TestWithParam<std::string>>;
-
TEST_P(OpConstantInvalidTypeTest, InvalidTypes) {
const std::string input = "%1 = " + GetParam() +
"\n"
@@ -360,8 +359,11 @@
"OpTypeReserveId",
"OpTypeQueue",
"OpTypePipe ReadOnly",
- "OpTypeForwardPointer %a UniformConstant",
- // At least one thing that isn't a type at all
+
+ // Skip OpTypeForwardPointer doesn't even produce a result ID.
+ // The assembler errors out if we try to check it in this scenario.
+
+ // Try at least one thing that isn't a type at all
"OpNot %a %b"
},
}));
@@ -470,8 +472,10 @@
"OpTypeReserveId",
"OpTypeQueue",
"OpTypePipe ReadOnly",
- "OpTypeForwardPointer %a UniformConstant",
- // At least one thing that isn't a type at all
+
+ // Skip testing OpTypeForwardPointer because it doesn't even produce a result ID.
+
+ // Try at least one thing that isn't a type at all
"OpNot %a %b"
},
}));
diff --git a/test/text_to_binary.control_flow_test.cpp b/test/text_to_binary.control_flow_test.cpp
index 01cc8e6..ae51f55 100644
--- a/test/text_to_binary.control_flow_test.cpp
+++ b/test/text_to_binary.control_flow_test.cpp
@@ -342,7 +342,7 @@
"%1 = " + GetParam() +
"\n"
"%3 = OpCopyObject %1 %2\n" // We only care the type of the expression
- "%4 = OpSwitch %3 %default 32 %c\n";
+ " OpSwitch %3 %default 32 %c\n";
EXPECT_THAT(CompileFailure(input),
Eq("The selector operand for OpSwitch must be the result of an "
"instruction that generates an integer scalar"));
@@ -371,8 +371,11 @@
"OpTypeReserveId",
"OpTypeQueue",
"OpTypePipe ReadOnly",
- "OpTypeForwardPointer %a UniformConstant",
- // At least one thing that isn't a type at all
+
+ // Skip OpTypeForwardPointer becasuse it doesn't even produce a result
+ // ID.
+
+ // At least one thing that isn't a type at all
"OpNot %a %b"
},
}));
diff --git a/test/text_to_binary.extension_test.cpp b/test/text_to_binary.extension_test.cpp
index 9408e9a..023763b 100644
--- a/test/text_to_binary.extension_test.cpp
+++ b/test/text_to_binary.extension_test.cpp
@@ -527,54 +527,54 @@
Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1),
ValuesIn(std::vector<AssemblyCase>{
- {"OpCapability VulkanMemoryModelKHR\n",
+ {"OpCapability VulkanMemoryModel\n",
MakeInstruction(SpvOpCapability,
{SpvCapabilityVulkanMemoryModelKHR})},
- {"OpCapability VulkanMemoryModelDeviceScopeKHR\n",
+ {"OpCapability VulkanMemoryModelDeviceScope\n",
MakeInstruction(SpvOpCapability,
{SpvCapabilityVulkanMemoryModelDeviceScopeKHR})},
- {"OpMemoryModel Logical VulkanKHR\n",
+ {"OpMemoryModel Logical Vulkan\n",
MakeInstruction(SpvOpMemoryModel, {SpvAddressingModelLogical,
SpvMemoryModelVulkanKHR})},
- {"OpStore %1 %2 MakePointerAvailableKHR %3\n",
+ {"OpStore %1 %2 MakePointerAvailable %3\n",
MakeInstruction(SpvOpStore,
{1, 2, SpvMemoryAccessMakePointerAvailableKHRMask,
3})},
- {"OpStore %1 %2 Volatile|MakePointerAvailableKHR %3\n",
+ {"OpStore %1 %2 Volatile|MakePointerAvailable %3\n",
MakeInstruction(SpvOpStore,
{1, 2,
int(SpvMemoryAccessMakePointerAvailableKHRMask) |
int(SpvMemoryAccessVolatileMask),
3})},
- {"OpStore %1 %2 Aligned|MakePointerAvailableKHR 4 %3\n",
+ {"OpStore %1 %2 Aligned|MakePointerAvailable 4 %3\n",
MakeInstruction(SpvOpStore,
{1, 2,
int(SpvMemoryAccessMakePointerAvailableKHRMask) |
int(SpvMemoryAccessAlignedMask),
4, 3})},
- {"OpStore %1 %2 MakePointerAvailableKHR|NonPrivatePointerKHR %3\n",
+ {"OpStore %1 %2 MakePointerAvailable|NonPrivatePointer %3\n",
MakeInstruction(SpvOpStore,
{1, 2,
int(SpvMemoryAccessMakePointerAvailableKHRMask) |
int(SpvMemoryAccessNonPrivatePointerKHRMask),
3})},
- {"%2 = OpLoad %1 %3 MakePointerVisibleKHR %4\n",
+ {"%2 = OpLoad %1 %3 MakePointerVisible %4\n",
MakeInstruction(SpvOpLoad,
{1, 2, 3, SpvMemoryAccessMakePointerVisibleKHRMask,
4})},
- {"%2 = OpLoad %1 %3 Volatile|MakePointerVisibleKHR %4\n",
+ {"%2 = OpLoad %1 %3 Volatile|MakePointerVisible %4\n",
MakeInstruction(SpvOpLoad,
{1, 2, 3,
int(SpvMemoryAccessMakePointerVisibleKHRMask) |
int(SpvMemoryAccessVolatileMask),
4})},
- {"%2 = OpLoad %1 %3 Aligned|MakePointerVisibleKHR 8 %4\n",
+ {"%2 = OpLoad %1 %3 Aligned|MakePointerVisible 8 %4\n",
MakeInstruction(SpvOpLoad,
{1, 2, 3,
int(SpvMemoryAccessMakePointerVisibleKHRMask) |
int(SpvMemoryAccessAlignedMask),
8, 4})},
- {"%2 = OpLoad %1 %3 MakePointerVisibleKHR|NonPrivatePointerKHR "
+ {"%2 = OpLoad %1 %3 MakePointerVisible|NonPrivatePointer "
"%4\n",
MakeInstruction(SpvOpLoad,
{1, 2, 3,
@@ -582,9 +582,9 @@
int(SpvMemoryAccessNonPrivatePointerKHRMask),
4})},
{"OpCopyMemory %1 %2 "
- "MakePointerAvailableKHR|"
- "MakePointerVisibleKHR|"
- "NonPrivatePointerKHR "
+ "MakePointerAvailable|"
+ "MakePointerVisible|"
+ "NonPrivatePointer "
"%3 %4\n",
MakeInstruction(SpvOpCopyMemory,
{1, 2,
@@ -593,9 +593,9 @@
int(SpvMemoryAccessNonPrivatePointerKHRMask)),
3, 4})},
{"OpCopyMemorySized %1 %2 %3 "
- "MakePointerAvailableKHR|"
- "MakePointerVisibleKHR|"
- "NonPrivatePointerKHR "
+ "MakePointerAvailable|"
+ "MakePointerVisible|"
+ "NonPrivatePointer "
"%4 %5\n",
MakeInstruction(SpvOpCopyMemorySized,
{1, 2, 3,
@@ -604,12 +604,12 @@
int(SpvMemoryAccessNonPrivatePointerKHRMask)),
4, 5})},
// Image operands
- {"OpImageWrite %1 %2 %3 MakeTexelAvailableKHR "
+ {"OpImageWrite %1 %2 %3 MakeTexelAvailable "
"%4\n",
MakeInstruction(
SpvOpImageWrite,
{1, 2, 3, int(SpvImageOperandsMakeTexelAvailableKHRMask), 4})},
- {"OpImageWrite %1 %2 %3 MakeTexelAvailableKHR|NonPrivateTexelKHR "
+ {"OpImageWrite %1 %2 %3 MakeTexelAvailable|NonPrivateTexel "
"%4\n",
MakeInstruction(SpvOpImageWrite,
{1, 2, 3,
@@ -617,7 +617,7 @@
int(SpvImageOperandsNonPrivateTexelKHRMask),
4})},
{"OpImageWrite %1 %2 %3 "
- "MakeTexelAvailableKHR|NonPrivateTexelKHR|VolatileTexelKHR "
+ "MakeTexelAvailable|NonPrivateTexel|VolatileTexel "
"%4\n",
MakeInstruction(SpvOpImageWrite,
{1, 2, 3,
@@ -625,14 +625,14 @@
int(SpvImageOperandsNonPrivateTexelKHRMask) |
int(SpvImageOperandsVolatileTexelKHRMask),
4})},
- {"%2 = OpImageRead %1 %3 %4 MakeTexelVisibleKHR "
+ {"%2 = OpImageRead %1 %3 %4 MakeTexelVisible "
"%5\n",
MakeInstruction(SpvOpImageRead,
{1, 2, 3, 4,
int(SpvImageOperandsMakeTexelVisibleKHRMask),
5})},
{"%2 = OpImageRead %1 %3 %4 "
- "MakeTexelVisibleKHR|NonPrivateTexelKHR "
+ "MakeTexelVisible|NonPrivateTexel "
"%5\n",
MakeInstruction(SpvOpImageRead,
{1, 2, 3, 4,
@@ -640,7 +640,7 @@
int(SpvImageOperandsNonPrivateTexelKHRMask),
5})},
{"%2 = OpImageRead %1 %3 %4 "
- "MakeTexelVisibleKHR|NonPrivateTexelKHR|VolatileTexelKHR "
+ "MakeTexelVisible|NonPrivateTexel|VolatileTexel "
"%5\n",
MakeInstruction(SpvOpImageRead,
{1, 2, 3, 4,
@@ -826,82 +826,82 @@
MakeInstruction(SpvOpExtension,
MakeVector("SPV_EXT_descriptor_indexing"))},
// Check capabilities, by name
- {"OpCapability ShaderNonUniformEXT\n",
+ {"OpCapability ShaderNonUniform\n",
MakeInstruction(SpvOpCapability,
{SpvCapabilityShaderNonUniformEXT})},
- {"OpCapability RuntimeDescriptorArrayEXT\n",
+ {"OpCapability RuntimeDescriptorArray\n",
MakeInstruction(SpvOpCapability,
{SpvCapabilityRuntimeDescriptorArrayEXT})},
- {"OpCapability InputAttachmentArrayDynamicIndexingEXT\n",
+ {"OpCapability InputAttachmentArrayDynamicIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilityInputAttachmentArrayDynamicIndexingEXT})},
- {"OpCapability UniformTexelBufferArrayDynamicIndexingEXT\n",
+ {"OpCapability UniformTexelBufferArrayDynamicIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT})},
- {"OpCapability StorageTexelBufferArrayDynamicIndexingEXT\n",
+ {"OpCapability StorageTexelBufferArrayDynamicIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT})},
- {"OpCapability UniformBufferArrayNonUniformIndexingEXT\n",
+ {"OpCapability UniformBufferArrayNonUniformIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilityUniformBufferArrayNonUniformIndexingEXT})},
- {"OpCapability SampledImageArrayNonUniformIndexingEXT\n",
+ {"OpCapability SampledImageArrayNonUniformIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilitySampledImageArrayNonUniformIndexingEXT})},
- {"OpCapability StorageBufferArrayNonUniformIndexingEXT\n",
+ {"OpCapability StorageBufferArrayNonUniformIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilityStorageBufferArrayNonUniformIndexingEXT})},
- {"OpCapability StorageImageArrayNonUniformIndexingEXT\n",
+ {"OpCapability StorageImageArrayNonUniformIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilityStorageImageArrayNonUniformIndexingEXT})},
- {"OpCapability InputAttachmentArrayNonUniformIndexingEXT\n",
+ {"OpCapability InputAttachmentArrayNonUniformIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT})},
- {"OpCapability UniformTexelBufferArrayNonUniformIndexingEXT\n",
+ {"OpCapability UniformTexelBufferArrayNonUniformIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT})},
- {"OpCapability StorageTexelBufferArrayNonUniformIndexingEXT\n",
+ {"OpCapability StorageTexelBufferArrayNonUniformIndexing\n",
MakeInstruction(
SpvOpCapability,
{SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT})},
// Check capabilities, by number
- {"OpCapability ShaderNonUniformEXT\n",
+ {"OpCapability ShaderNonUniform\n",
MakeInstruction(SpvOpCapability, {5301})},
- {"OpCapability RuntimeDescriptorArrayEXT\n",
+ {"OpCapability RuntimeDescriptorArray\n",
MakeInstruction(SpvOpCapability, {5302})},
- {"OpCapability InputAttachmentArrayDynamicIndexingEXT\n",
+ {"OpCapability InputAttachmentArrayDynamicIndexing\n",
MakeInstruction(SpvOpCapability, {5303})},
- {"OpCapability UniformTexelBufferArrayDynamicIndexingEXT\n",
+ {"OpCapability UniformTexelBufferArrayDynamicIndexing\n",
MakeInstruction(SpvOpCapability, {5304})},
- {"OpCapability StorageTexelBufferArrayDynamicIndexingEXT\n",
+ {"OpCapability StorageTexelBufferArrayDynamicIndexing\n",
MakeInstruction(SpvOpCapability, {5305})},
- {"OpCapability UniformBufferArrayNonUniformIndexingEXT\n",
+ {"OpCapability UniformBufferArrayNonUniformIndexing\n",
MakeInstruction(SpvOpCapability, {5306})},
- {"OpCapability SampledImageArrayNonUniformIndexingEXT\n",
+ {"OpCapability SampledImageArrayNonUniformIndexing\n",
MakeInstruction(SpvOpCapability, {5307})},
- {"OpCapability StorageBufferArrayNonUniformIndexingEXT\n",
+ {"OpCapability StorageBufferArrayNonUniformIndexing\n",
MakeInstruction(SpvOpCapability, {5308})},
- {"OpCapability StorageImageArrayNonUniformIndexingEXT\n",
+ {"OpCapability StorageImageArrayNonUniformIndexing\n",
MakeInstruction(SpvOpCapability, {5309})},
- {"OpCapability InputAttachmentArrayNonUniformIndexingEXT\n",
+ {"OpCapability InputAttachmentArrayNonUniformIndexing\n",
MakeInstruction(SpvOpCapability, {5310})},
- {"OpCapability UniformTexelBufferArrayNonUniformIndexingEXT\n",
+ {"OpCapability UniformTexelBufferArrayNonUniformIndexing\n",
MakeInstruction(SpvOpCapability, {5311})},
- {"OpCapability StorageTexelBufferArrayNonUniformIndexingEXT\n",
+ {"OpCapability StorageTexelBufferArrayNonUniformIndexing\n",
MakeInstruction(SpvOpCapability, {5312})},
// Check the decoration token
- {"OpDecorate %1 NonUniformEXT\n",
+ {"OpDecorate %1 NonUniform\n",
MakeInstruction(SpvOpDecorate, {1, SpvDecorationNonUniformEXT})},
- {"OpDecorate %1 NonUniformEXT\n",
+ {"OpDecorate %1 NonUniform\n",
MakeInstruction(SpvOpDecorate, {1, 5300})},
})));
diff --git a/test/text_to_binary.memory_test.cpp b/test/text_to_binary.memory_test.cpp
index c83c847..7b09ed5 100644
--- a/test/text_to_binary.memory_test.cpp
+++ b/test/text_to_binary.memory_test.cpp
@@ -212,7 +212,7 @@
}
TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessAvGood) {
- std::string spirv = "OpCopyMemory %1 %2 MakePointerAvailableKHR %3\n";
+ std::string spirv = "OpCopyMemory %1 %2 MakePointerAvailable %3\n";
EXPECT_THAT(CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 8, 3})));
std::string disassembly =
@@ -221,7 +221,7 @@
}
TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessVisGood) {
- std::string spirv = "OpCopyMemory %1 %2 MakePointerVisibleKHR %3\n";
+ std::string spirv = "OpCopyMemory %1 %2 MakePointerVisible %3\n";
EXPECT_THAT(CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 16, 3})));
std::string disassembly =
@@ -230,7 +230,7 @@
}
TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessNonPrivateGood) {
- std::string spirv = "OpCopyMemory %1 %2 NonPrivatePointerKHR\n";
+ std::string spirv = "OpCopyMemory %1 %2 NonPrivatePointer\n";
EXPECT_THAT(CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 32})));
std::string disassembly =
@@ -241,8 +241,8 @@
TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessMixedGood) {
std::string spirv =
"OpCopyMemory %1 %2 "
- "Volatile|Aligned|Nontemporal|MakePointerAvailableKHR|"
- "MakePointerVisibleKHR|NonPrivatePointerKHR 16 %3 %4\n";
+ "Volatile|Aligned|Nontemporal|MakePointerAvailable|"
+ "MakePointerVisible|NonPrivatePointer 16 %3 %4\n";
EXPECT_THAT(CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 63, 16, 3, 4})));
std::string disassembly =
@@ -272,8 +272,8 @@
TEST_F(MemoryRoundTripTest, OpCopyMemoryTwoAccessMixedV14Good) {
std::string spirv =
"OpCopyMemory %1 %2 Volatile|Nontemporal|"
- "MakePointerVisibleKHR %3 "
- "Aligned|MakePointerAvailableKHR|NonPrivatePointerKHR 16 %4\n";
+ "MakePointerVisible %3 "
+ "Aligned|MakePointerAvailable|NonPrivatePointer 16 %4\n";
EXPECT_THAT(CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 21, 3, 42, 16, 4})));
std::string disassembly =
@@ -341,7 +341,7 @@
}
TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessAvGood) {
- std::string spirv = "OpCopyMemorySized %1 %2 %3 MakePointerAvailableKHR %4\n";
+ std::string spirv = "OpCopyMemorySized %1 %2 %3 MakePointerAvailable %4\n";
EXPECT_THAT(CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 8, 4})));
std::string disassembly =
@@ -350,7 +350,7 @@
}
TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessVisGood) {
- std::string spirv = "OpCopyMemorySized %1 %2 %3 MakePointerVisibleKHR %4\n";
+ std::string spirv = "OpCopyMemorySized %1 %2 %3 MakePointerVisible %4\n";
EXPECT_THAT(CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 16, 4})));
std::string disassembly =
@@ -359,7 +359,7 @@
}
TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessNonPrivateGood) {
- std::string spirv = "OpCopyMemorySized %1 %2 %3 NonPrivatePointerKHR\n";
+ std::string spirv = "OpCopyMemorySized %1 %2 %3 NonPrivatePointer\n";
EXPECT_THAT(CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 32})));
std::string disassembly =
@@ -370,8 +370,8 @@
TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessMixedGood) {
std::string spirv =
"OpCopyMemorySized %1 %2 %3 "
- "Volatile|Aligned|Nontemporal|MakePointerAvailableKHR|"
- "MakePointerVisibleKHR|NonPrivatePointerKHR 16 %4 %5\n";
+ "Volatile|Aligned|Nontemporal|MakePointerAvailable|"
+ "MakePointerVisible|NonPrivatePointer 16 %4 %5\n";
EXPECT_THAT(
CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 63, 16, 4, 5})));
@@ -402,8 +402,8 @@
TEST_F(MemoryRoundTripTest, OpCopyMemorySizedTwoAccessMixedV14Good) {
std::string spirv =
"OpCopyMemorySized %1 %2 %3 Volatile|Nontemporal|"
- "MakePointerVisibleKHR %4 "
- "Aligned|MakePointerAvailableKHR|NonPrivatePointerKHR 16 %5\n";
+ "MakePointerVisible %4 "
+ "Aligned|MakePointerAvailable|NonPrivatePointer 16 %5\n";
EXPECT_THAT(
CompiledInstructions(spirv),
Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 21, 4, 42, 16, 5})));
diff --git a/test/tools/expect.py b/test/tools/expect.py
index e21a0c4..52999ce 100755
--- a/test/tools/expect.py
+++ b/test/tools/expect.py
@@ -270,8 +270,8 @@
return True, ''
-class ValidObjectFile1_4(ReturnCodeIsZero, CorrectObjectFilePreamble):
- """Mixin class for checking that every input file generates a valid SPIR-V 1.4
+class ValidObjectFile1_5(ReturnCodeIsZero, CorrectObjectFilePreamble):
+ """Mixin class for checking that every input file generates a valid SPIR-V 1.5
object file following the object file naming rule, and there is no output on
stdout/stderr."""
@@ -279,7 +279,7 @@
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
- os.path.join(status.directory, object_filename), 0x10400)
+ os.path.join(status.directory, object_filename), 0x10500)
if not success:
return False, message
return True, ''
diff --git a/test/tools/opt/flags.py b/test/tools/opt/flags.py
index 49e2cab..b34a168 100644
--- a/test/tools/opt/flags.py
+++ b/test/tools/opt/flags.py
@@ -34,7 +34,7 @@
@inside_spirv_testsuite('SpirvOptBase')
-class TestAssemblyFileAsOnlyParameter(expect.ValidObjectFile1_4):
+class TestAssemblyFileAsOnlyParameter(expect.ValidObjectFile1_5):
"""Tests that spirv-opt accepts a SPIR-V object file."""
shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm')
@@ -52,7 +52,7 @@
@inside_spirv_testsuite('SpirvOptFlags')
-class TestValidPassFlags(expect.ValidObjectFile1_4,
+class TestValidPassFlags(expect.ValidObjectFile1_5,
expect.ExecutedListOfPasses):
"""Tests that spirv-opt accepts all valid optimization flags."""
@@ -91,7 +91,7 @@
'eliminate-dead-variables',
# --eliminate-insert-extract runs the simplify-instructions pass.
'simplify-instructions',
- 'eliminate-local-multi-store',
+ 'ssa-rewrite',
'eliminate-local-single-block',
'eliminate-local-single-store',
'flatten-decorations',
@@ -129,7 +129,7 @@
@inside_spirv_testsuite('SpirvOptFlags')
-class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_4,
+class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_5,
expect.ExecutedListOfPasses):
"""Tests that spirv-opt schedules all the passes triggered by -O."""
@@ -149,7 +149,7 @@
'eliminate-local-single-block',
'eliminate-local-single-store',
'eliminate-dead-code-aggressive',
- 'eliminate-local-multi-store',
+ 'ssa-rewrite',
'eliminate-dead-code-aggressive',
'ccp',
'eliminate-dead-code-aggressive',
@@ -177,7 +177,7 @@
@inside_spirv_testsuite('SpirvOptFlags')
-class TestSizeOptimizationPasses(expect.ValidObjectFile1_4,
+class TestSizeOptimizationPasses(expect.ValidObjectFile1_5,
expect.ExecutedListOfPasses):
"""Tests that spirv-opt schedules all the passes triggered by -Os."""
@@ -196,7 +196,7 @@
'eliminate-dead-code-aggressive',
'simplify-instructions',
'eliminate-dead-inserts',
- 'eliminate-local-multi-store',
+ 'ssa-rewrite',
'eliminate-dead-code-aggressive',
'ccp',
'eliminate-dead-code-aggressive',
@@ -217,7 +217,7 @@
@inside_spirv_testsuite('SpirvOptFlags')
-class TestLegalizationPasses(expect.ValidObjectFile1_4,
+class TestLegalizationPasses(expect.ValidObjectFile1_5,
expect.ExecutedListOfPasses):
"""Tests that spirv-opt schedules all the passes triggered by --legalize-hlsl.
"""
@@ -238,7 +238,7 @@
'eliminate-local-single-block',
'eliminate-local-single-store',
'eliminate-dead-code-aggressive',
- 'eliminate-local-multi-store',
+ 'ssa-rewrite',
'eliminate-dead-code-aggressive',
'ccp',
'loop-unroll',
diff --git a/test/util/CMakeLists.txt b/test/util/CMakeLists.txt
index 8cdb35f..6679dba 100644
--- a/test/util/CMakeLists.txt
+++ b/test/util/CMakeLists.txt
@@ -15,6 +15,7 @@
add_spvtools_unittest(TARGET utils
SRCS ilist_test.cpp
bit_vector_test.cpp
+ bitutils_test.cpp
small_vector_test.cpp
LIBS SPIRV-Tools-opt
)
diff --git a/test/util/bitutils_test.cpp b/test/util/bitutils_test.cpp
new file mode 100644
index 0000000..3be7ed2
--- /dev/null
+++ b/test/util/bitutils_test.cpp
@@ -0,0 +1,193 @@
+// 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 "source/util/bitutils.h"
+
+#include "gmock/gmock.h"
+
+namespace spvtools {
+namespace utils {
+namespace {
+
+using BitUtilsTest = ::testing::Test;
+
+TEST(BitUtilsTest, MutateBitsWholeWord) {
+ const uint32_t zero_u32 = 0;
+ const uint32_t max_u32 = ~0;
+
+ EXPECT_EQ(MutateBits(zero_u32, 0, 0, false), zero_u32);
+ EXPECT_EQ(MutateBits(max_u32, 0, 0, false), max_u32);
+ EXPECT_EQ(MutateBits(zero_u32, 0, 32, false), zero_u32);
+ EXPECT_EQ(MutateBits(zero_u32, 0, 32, true), max_u32);
+ EXPECT_EQ(MutateBits(max_u32, 0, 32, true), max_u32);
+ EXPECT_EQ(MutateBits(max_u32, 0, 32, false), zero_u32);
+}
+
+TEST(BitUtilsTest, MutateBitsLow) {
+ const uint32_t zero_u32 = 0;
+ const uint32_t one_u32 = 1;
+ const uint32_t max_u32 = ~0;
+
+ EXPECT_EQ(MutateBits(zero_u32, 0, 1, false), zero_u32);
+ EXPECT_EQ(MutateBits(zero_u32, 0, 1, true), one_u32);
+ EXPECT_EQ(MutateBits(max_u32, 0, 1, true), max_u32);
+ EXPECT_EQ(MutateBits(one_u32, 0, 32, false), zero_u32);
+ EXPECT_EQ(MutateBits(one_u32, 0, 1, true), one_u32);
+ EXPECT_EQ(MutateBits(one_u32, 0, 1, false), zero_u32);
+ EXPECT_EQ(MutateBits(zero_u32, 0, 3, true), uint32_t(7));
+ EXPECT_EQ(MutateBits(uint32_t(7), 0, 2, false), uint32_t(4));
+}
+
+TEST(BitUtilsTest, MutateBitsHigh) {
+ const uint8_t zero_u8 = 0;
+ const uint8_t one_u8 = 1;
+ const uint8_t max_u8 = 255;
+
+ EXPECT_EQ(MutateBits(zero_u8, 7, 0, true), zero_u8);
+ EXPECT_EQ(MutateBits(zero_u8, 7, 1, true), uint8_t(128));
+ EXPECT_EQ(MutateBits(one_u8, 7, 1, true), uint8_t(129));
+ EXPECT_EQ(MutateBits(max_u8, 7, 1, true), max_u8);
+ EXPECT_EQ(MutateBits(max_u8, 7, 1, false), uint8_t(127));
+ EXPECT_EQ(MutateBits(max_u8, 6, 2, true), max_u8);
+ EXPECT_EQ(MutateBits(max_u8, 6, 2, false), uint8_t(63));
+}
+
+TEST(BitUtilsTest, MutateBitsUint8Mid) {
+ const uint8_t zero_u8 = 0;
+ const uint8_t max_u8 = 255;
+
+ EXPECT_EQ(MutateBits(zero_u8, 1, 2, true), uint8_t(6));
+ EXPECT_EQ(MutateBits(max_u8, 1, 2, true), max_u8);
+ EXPECT_EQ(MutateBits(max_u8, 1, 2, false), uint8_t(0xF9));
+ EXPECT_EQ(MutateBits(zero_u8, 2, 3, true), uint8_t(0x1C));
+}
+
+TEST(BitUtilsTest, MutateBitsUint64Mid) {
+ const uint64_t zero_u64 = 0;
+ const uint64_t max_u64 = ~zero_u64;
+
+ EXPECT_EQ(MutateBits(zero_u64, 1, 2, true), uint64_t(6));
+ EXPECT_EQ(MutateBits(max_u64, 1, 2, true), max_u64);
+ EXPECT_EQ(MutateBits(max_u64, 1, 2, false), uint64_t(0xFFFFFFFFFFFFFFF9));
+ EXPECT_EQ(MutateBits(zero_u64, 2, 3, true), uint64_t(0x000000000000001C));
+ EXPECT_EQ(MutateBits(zero_u64, 2, 35, true), uint64_t(0x0000001FFFFFFFFC));
+ EXPECT_EQ(MutateBits(zero_u64, 36, 4, true), uint64_t(0x000000F000000000));
+ EXPECT_EQ(MutateBits(max_u64, 36, 4, false), uint64_t(0xFFFFFF0FFFFFFFFF));
+}
+
+TEST(BitUtilsTest, SetHighBitsUint32) {
+ const uint32_t zero_u32 = 0;
+ const uint32_t one_u32 = 1;
+ const uint32_t max_u32 = ~zero_u32;
+
+ EXPECT_EQ(SetHighBits(zero_u32, 0), zero_u32);
+ EXPECT_EQ(SetHighBits(zero_u32, 1), 0x80000000);
+ EXPECT_EQ(SetHighBits(one_u32, 1), 0x80000001);
+ EXPECT_EQ(SetHighBits(one_u32, 2), 0xC0000001);
+ EXPECT_EQ(SetHighBits(zero_u32, 31), 0xFFFFFFFE);
+ EXPECT_EQ(SetHighBits(zero_u32, 32), max_u32);
+ EXPECT_EQ(SetHighBits(max_u32, 32), max_u32);
+}
+
+TEST(BitUtilsTest, ClearHighBitsUint32) {
+ const uint32_t zero_u32 = 0;
+ const uint32_t one_u32 = 1;
+ const uint32_t max_u32 = ~zero_u32;
+
+ EXPECT_EQ(ClearHighBits(zero_u32, 0), zero_u32);
+ EXPECT_EQ(ClearHighBits(zero_u32, 1), zero_u32);
+ EXPECT_EQ(ClearHighBits(one_u32, 1), one_u32);
+ EXPECT_EQ(ClearHighBits(one_u32, 31), one_u32);
+ EXPECT_EQ(ClearHighBits(one_u32, 32), zero_u32);
+ EXPECT_EQ(ClearHighBits(max_u32, 0), max_u32);
+ EXPECT_EQ(ClearHighBits(max_u32, 1), 0x7FFFFFFF);
+ EXPECT_EQ(ClearHighBits(max_u32, 2), 0x3FFFFFFF);
+ EXPECT_EQ(ClearHighBits(max_u32, 31), one_u32);
+ EXPECT_EQ(ClearHighBits(max_u32, 32), zero_u32);
+}
+
+TEST(BitUtilsTest, IsBitSetAtPositionZero) {
+ const uint32_t zero_u32 = 0;
+ for (size_t i = 0; i != 32; ++i) {
+ EXPECT_FALSE(IsBitAtPositionSet(zero_u32, i));
+ }
+
+ const uint8_t zero_u8 = 0;
+ for (size_t i = 0; i != 8; ++i) {
+ EXPECT_FALSE(IsBitAtPositionSet(zero_u8, i));
+ }
+
+ const uint64_t zero_u64 = 0;
+ for (size_t i = 0; i != 64; ++i) {
+ EXPECT_FALSE(IsBitAtPositionSet(zero_u64, i));
+ }
+}
+
+TEST(BitUtilsTest, IsBitSetAtPositionOne) {
+ const uint32_t one_u32 = 1;
+ for (size_t i = 0; i != 32; ++i) {
+ if (i == 0) {
+ EXPECT_TRUE(IsBitAtPositionSet(one_u32, i));
+ } else {
+ EXPECT_FALSE(IsBitAtPositionSet(one_u32, i));
+ }
+ }
+
+ const uint32_t two_to_17_u32 = 1 << 17;
+ for (size_t i = 0; i != 32; ++i) {
+ if (i == 17) {
+ EXPECT_TRUE(IsBitAtPositionSet(two_to_17_u32, i));
+ } else {
+ EXPECT_FALSE(IsBitAtPositionSet(two_to_17_u32, i));
+ }
+ }
+
+ const uint8_t two_to_4_u8 = 1 << 4;
+ for (size_t i = 0; i != 8; ++i) {
+ if (i == 4) {
+ EXPECT_TRUE(IsBitAtPositionSet(two_to_4_u8, i));
+ } else {
+ EXPECT_FALSE(IsBitAtPositionSet(two_to_4_u8, i));
+ }
+ }
+
+ const uint64_t two_to_55_u64 = uint64_t(1) << 55;
+ for (size_t i = 0; i != 64; ++i) {
+ if (i == 55) {
+ EXPECT_TRUE(IsBitAtPositionSet(two_to_55_u64, i));
+ } else {
+ EXPECT_FALSE(IsBitAtPositionSet(two_to_55_u64, i));
+ }
+ }
+}
+
+TEST(BitUtilsTest, IsBitSetAtPositionAll) {
+ const uint32_t max_u32 = ~0;
+ for (size_t i = 0; i != 32; ++i) {
+ EXPECT_TRUE(IsBitAtPositionSet(max_u32, i));
+ }
+
+ const uint32_t max_u8 = ~uint8_t(0);
+ for (size_t i = 0; i != 8; ++i) {
+ EXPECT_TRUE(IsBitAtPositionSet(max_u8, i));
+ }
+
+ const uint64_t max_u64 = ~uint64_t(0);
+ for (size_t i = 0; i != 64; ++i) {
+ EXPECT_TRUE(IsBitAtPositionSet(max_u64, i));
+ }
+}
+} // namespace
+} // namespace utils
+} // namespace spvtools
diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt
index b52c764..d4bfe1d 100644
--- a/test/val/CMakeLists.txt
+++ b/test/val/CMakeLists.txt
@@ -28,7 +28,6 @@
val_barriers_test.cpp
val_bitwise_test.cpp
val_builtins_test.cpp
- val_capability_test.cpp
val_cfg_test.cpp
val_composites_test.cpp
val_constants_test.cpp
@@ -36,6 +35,7 @@
val_data_test.cpp
val_decoration_test.cpp
val_derivatives_test.cpp
+ val_entry_point.cpp
val_explicit_reserved_test.cpp
val_extensions_test.cpp
val_ext_inst_test.cpp
@@ -44,6 +44,13 @@
PCH_FILE pch_test_val
)
+add_spvtools_unittest(TARGET val_capability
+ SRCS
+ val_capability_test.cpp
+ LIBS ${SPIRV_TOOLS}
+ PCH_FILE pch_test_val
+)
+
add_spvtools_unittest(TARGET val_limits
SRCS val_limits_test.cpp
${VAL_TEST_COMMON_SRCS}
diff --git a/test/val/val_adjacency_test.cpp b/test/val/val_adjacency_test.cpp
index 5c1124a..e61c03d 100644
--- a/test/val/val_adjacency_test.cpp
+++ b/test/val/val_adjacency_test.cpp
@@ -144,7 +144,7 @@
%false_label = OpLabel
OpBranch %end_label
%end_label = OpLabel
-%line = OpLine %string 0 0
+OpLine %string 0 0
%result = OpPhi %bool %true %true_label %false %false_label
)";
@@ -178,7 +178,7 @@
%false_label = OpLabel
OpBranch %end_label
%end_label = OpLabel
-%line = OpLine %string 0 0
+OpLine %string 0 0
%result = OpPhi %bool %true %true_label %false %false_label
)";
diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp
index 57a1187..cd723b2 100644
--- a/test/val/val_atomics_test.cpp
+++ b/test/val/val_atomics_test.cpp
@@ -499,9 +499,8 @@
CompileSuccessfully(GenerateKernelCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("AtomicLoad: expected Memory Scope to be a 32-bit int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("AtomicLoad: expected scope to be a 32-bit int"));
}
TEST_F(ValidateAtomics, AtomicLoadWrongMemorySemanticsType) {
@@ -674,10 +673,9 @@
CompileSuccessfully(GenerateKernelCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("AtomicStore: expected Memory Scope to be a 32-bit int\n "
- "OpAtomicStore %28 %float_1 %uint_0_1 %float_1\n"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("AtomicStore: expected scope to be a 32-bit int\n "
+ "OpAtomicStore %28 %float_1 %uint_0_1 %float_1\n"));
}
TEST_F(ValidateAtomics, AtomicStoreWrongMemorySemanticsType) {
@@ -708,7 +706,7 @@
TEST_F(ValidateAtomics, AtomicExchangeShaderSuccess) {
const std::string body = R"(
-%val1 = OpAtomicStore %u32_var %device %relaxed %u32_1
+OpAtomicStore %u32_var %device %relaxed %u32_1
%val2 = OpAtomicExchange %u32 %u32_var %device %relaxed %u32_0
)";
@@ -720,7 +718,7 @@
const std::string body = R"(
OpAtomicStore %f32_var %device %relaxed %f32_1
%val2 = OpAtomicExchange %f32 %f32_var %device %relaxed %f32_0
-%val3 = OpAtomicStore %u32_var %device %relaxed %u32_1
+OpAtomicStore %u32_var %device %relaxed %u32_1
%val4 = OpAtomicExchange %u32 %u32_var %device %relaxed %u32_0
)";
@@ -743,7 +741,7 @@
TEST_F(ValidateAtomics, AtomicExchangeWrongResultType) {
const std::string body = R"(
-%val1 = OpStore %f32vec4_var %f32vec4_0000
+OpStore %f32vec4_var %f32vec4_0000
%val2 = OpAtomicExchange %f32vec4 %f32vec4_var %device %relaxed %f32vec4_0000
)";
@@ -768,7 +766,7 @@
TEST_F(ValidateAtomics, AtomicExchangeWrongPointerDataType) {
const std::string body = R"(
-%val1 = OpStore %f32vec4_var %f32vec4_0000
+OpStore %f32vec4_var %f32vec4_0000
%val2 = OpAtomicExchange %f32 %f32vec4_var %device %relaxed %f32vec4_0000
)";
@@ -788,9 +786,8 @@
CompileSuccessfully(GenerateKernelCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("AtomicExchange: expected Memory Scope to be a 32-bit int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("AtomicExchange: expected scope to be a 32-bit int"));
}
TEST_F(ValidateAtomics, AtomicExchangeWrongMemorySemanticsType) {
@@ -822,7 +819,7 @@
TEST_F(ValidateAtomics, AtomicCompareExchangeShaderSuccess) {
const std::string body = R"(
-%val1 = OpAtomicStore %u32_var %device %relaxed %u32_1
+OpAtomicStore %u32_var %device %relaxed %u32_1
%val2 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0
)";
@@ -834,7 +831,7 @@
const std::string body = R"(
OpAtomicStore %f32_var %device %relaxed %f32_1
%val2 = OpAtomicCompareExchange %f32 %f32_var %device %relaxed %relaxed %f32_0 %f32_1
-%val3 = OpAtomicStore %u32_var %device %relaxed %u32_1
+OpAtomicStore %u32_var %device %relaxed %u32_1
%val4 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0
)";
@@ -857,7 +854,7 @@
TEST_F(ValidateAtomics, AtomicCompareExchangeWrongResultType) {
const std::string body = R"(
-%val1 = OpStore %f32vec4_var %f32vec4_0000
+OpStore %f32vec4_var %f32vec4_0000
%val2 = OpAtomicCompareExchange %f32vec4 %f32vec4_var %device %relaxed %relaxed %f32vec4_0000 %f32vec4_0000
)";
@@ -882,7 +879,7 @@
TEST_F(ValidateAtomics, AtomicCompareExchangeWrongPointerDataType) {
const std::string body = R"(
-%val1 = OpStore %f32vec4_var %f32vec4_0000
+OpStore %f32vec4_var %f32vec4_0000
%val2 = OpAtomicCompareExchange %f32 %f32vec4_var %device %relaxed %relaxed %f32_0 %f32_1
)";
@@ -902,10 +899,9 @@
CompileSuccessfully(GenerateKernelCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("AtomicCompareExchange: expected Memory Scope to be a 32-bit "
- "int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("AtomicCompareExchange: expected scope to be a 32-bit "
+ "int"));
}
TEST_F(ValidateAtomics, AtomicCompareExchangeWrongMemorySemanticsType1) {
@@ -975,7 +971,7 @@
TEST_F(ValidateAtomics, AtomicCompareExchangeWeakSuccess) {
const std::string body = R"(
-%val3 = OpAtomicStore %u32_var %device %relaxed %u32_1
+OpAtomicStore %u32_var %device %relaxed %u32_1
%val4 = OpAtomicCompareExchangeWeak %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0
)";
@@ -1085,8 +1081,7 @@
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr(
- "AtomicFlagTestAndSet: expected Memory Scope to be a 32-bit int"));
+ HasSubstr("AtomicFlagTestAndSet: expected scope to be a 32-bit int"));
}
TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongMemorySemanticsType) {
@@ -1159,7 +1154,7 @@
CompileSuccessfully(GenerateKernelCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("AtomicFlagClear: expected Memory Scope to be a 32-bit "
+ HasSubstr("AtomicFlagClear: expected scope to be a 32-bit "
"int\n OpAtomicFlagClear %30 %ulong_1 %uint_0_1\n"));
}
diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp
index 18f57f8..ae166d9 100644
--- a/test/val/val_barriers_test.cpp
+++ b/test/val/val_barriers_test.cpp
@@ -341,9 +341,8 @@
CompileSuccessfully(GenerateShaderCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("ControlBarrier: expected Execution Scope to be a 32-bit int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("ControlBarrier: expected scope to be a 32-bit int"));
}
TEST_F(ValidateBarriers, OpControlBarrierU64ExecutionScope) {
@@ -353,9 +352,8 @@
CompileSuccessfully(GenerateShaderCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("ControlBarrier: expected Execution Scope to be a 32-bit int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("ControlBarrier: expected scope to be a 32-bit int"));
}
TEST_F(ValidateBarriers, OpControlBarrierFloatMemoryScope) {
@@ -365,9 +363,8 @@
CompileSuccessfully(GenerateShaderCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("ControlBarrier: expected Memory Scope to be a 32-bit int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("ControlBarrier: expected scope to be a 32-bit int"));
}
TEST_F(ValidateBarriers, OpControlBarrierU64MemoryScope) {
@@ -377,9 +374,8 @@
CompileSuccessfully(GenerateShaderCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("ControlBarrier: expected Memory Scope to be a 32-bit int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("ControlBarrier: expected scope to be a 32-bit int"));
}
TEST_F(ValidateBarriers, OpControlBarrierFloatMemorySemantics) {
@@ -797,9 +793,8 @@
CompileSuccessfully(GenerateShaderCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("MemoryBarrier: expected Memory Scope to be a 32-bit int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("MemoryBarrier: expected scope to be a 32-bit int"));
}
TEST_F(ValidateBarriers, OpMemoryBarrierU64MemoryScope) {
@@ -809,9 +804,8 @@
CompileSuccessfully(GenerateShaderCode(body));
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("MemoryBarrier: expected Memory Scope to be a 32-bit int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("MemoryBarrier: expected scope to be a 32-bit int"));
}
TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemorySemantics) {
@@ -993,8 +987,7 @@
ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr(
- "MemoryNamedBarrier: expected Memory Scope to be a 32-bit int"));
+ HasSubstr("MemoryNamedBarrier: expected scope to be a 32-bit int"));
}
TEST_F(ValidateBarriers, OpMemoryNamedBarrierFloatMemorySemantics) {
diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp
index e3eca09..58593dc 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -2330,9 +2330,9 @@
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Vulkan spec requires BuiltIn WorkgroupSize to be a "
- "constant. ID <2> (OpCopyObject) is not a constant"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("BuiltIns can only target variables, structs or constants"));
}
CodeGenerator GetWorkgroupSizeNotVectorGenerator(spv_target_env env) {
@@ -3302,6 +3302,78 @@
HasSubstr("BuiltIn SubgroupId cannot be used as a member decoration"));
}
+TEST_F(ValidateBuiltIns, TargetIsType) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+OpDecorate %void BuiltIn Position
+%void = OpTypeVoid
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("BuiltIns can only target variables, structs or constants"));
+}
+
+TEST_F(ValidateBuiltIns, TargetIsVariable) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+OpDecorate %wg_var BuiltIn Position
+%int = OpTypeInt 32 0
+%int_wg_ptr = OpTypePointer Workgroup %int
+%wg_var = OpVariable %int_wg_ptr Workgroup
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateBuiltIns, TargetIsStruct) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+OpDecorate %struct BuiltIn Position
+%struct = OpTypeStruct
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateBuiltIns, TargetIsConstant) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+OpDecorate %int0 BuiltIn Position
+%int = OpTypeInt 32 0
+%int0 = OpConstant %int 0
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateBuiltIns, TargetIsSpecConstant) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+OpDecorate %int0 BuiltIn Position
+%int = OpTypeInt 32 0
+%int0 = OpSpecConstant %int 0
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_capability_test.cpp b/test/val/val_capability_test.cpp
index 5a6e751..ae1d62b 100644
--- a/test/val/val_capability_test.cpp
+++ b/test/val/val_capability_test.cpp
@@ -23,6 +23,7 @@
#include "gmock/gmock.h"
#include "source/assembly_grammar.h"
#include "source/spirv_target_env.h"
+#include "spirv-tools/libspirv.h"
#include "test/test_fixture.h"
#include "test/unit_spirv.h"
#include "test/val/val_fixtures.h"
@@ -33,6 +34,7 @@
using spvtest::ScopedContext;
using testing::Combine;
+using testing::Eq;
using testing::HasSubstr;
using testing::Values;
using testing::ValuesIn;
@@ -1286,221 +1288,264 @@
Values(
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn Position\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn Position\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
// Just mentioning PointSize, ClipDistance, or CullDistance as a BuiltIn does
// not trigger the requirement for the associated capability.
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/365
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn PointSize\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn PointSize\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllCapabilities()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn ClipDistance\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn ClipDistance\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllCapabilities()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn CullDistance\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn CullDistance\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllCapabilities()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn VertexId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn VertexId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn InstanceId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn InstanceId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn PrimitiveId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn PrimitiveId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
GeometryTessellationDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn InvocationId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn InvocationId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
GeometryTessellationDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn Layer\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn Layer\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn ViewportIndex\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn ViewportIndex\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
std::vector<std::string>{"MultiViewport"}),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn TessLevelOuter\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn TessLevelOuter\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
TessellationDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn TessLevelInner\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn TessLevelInner\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
TessellationDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn TessCoord\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn TessCoord\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
TessellationDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn PatchVertices\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn PatchVertices\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
TessellationDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn FragCoord\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn FragCoord\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn PointCoord\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn PointCoord\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn FrontFacing\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn FrontFacing\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn SampleId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn SampleId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
std::vector<std::string>{"SampleRateShading"}),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn SamplePosition\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn SamplePosition\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
std::vector<std::string>{"SampleRateShading"}),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn SampleMask\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn SampleMask\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn FragDepth\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn FragDepth\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn HelperInvocation\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn HelperInvocation\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn VertexIndex\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn VertexIndex\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn InstanceIndex\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn InstanceIndex\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn NumWorkgroups\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn NumWorkgroups\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllCapabilities()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn WorkgroupSize\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn WorkgroupSize\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllCapabilities()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn WorkgroupId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn WorkgroupId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllCapabilities()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn LocalInvocationId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn LocalInvocationId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllCapabilities()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn GlobalInvocationId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn GlobalInvocationId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllCapabilities()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn LocalInvocationIndex\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn LocalInvocationIndex\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllCapabilities()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn WorkDim\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn WorkDim\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn GlobalSize\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn GlobalSize\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn EnqueuedWorkgroupSize\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn EnqueuedWorkgroupSize\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn GlobalOffset\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn GlobalOffset\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn GlobalLinearId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn GlobalLinearId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn SubgroupSize\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn SubgroupSize\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelAndGroupNonUniformDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn SubgroupMaxSize\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn SubgroupMaxSize\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn NumSubgroups\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn NumSubgroups\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelAndGroupNonUniformDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn NumEnqueuedSubgroups\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn NumEnqueuedSubgroups\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn SubgroupId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn SubgroupId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelAndGroupNonUniformDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn SubgroupLocalInvocationId\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn SubgroupLocalInvocationId\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
KernelAndGroupNonUniformDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn VertexIndex\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn VertexIndex\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n" +
- "OpDecorate %intt BuiltIn InstanceIndex\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn InstanceIndex\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
ShaderDependencies())
)));
@@ -1548,18 +1593,21 @@
Values(
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn PointSize\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn PointSize\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllSpirV10Capabilities()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn ClipDistance\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn ClipDistance\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllSpirV10Capabilities()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn CullDistance\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn CullDistance\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllSpirV10Capabilities())
)));
@@ -1580,13 +1628,15 @@
Values(
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn PointSize\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn PointSize\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllVulkan11Capabilities()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt BuiltIn CullDistance\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %int0 BuiltIn CullDistance\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid),
AllVulkan11Capabilities())
)));
@@ -2436,6 +2486,178 @@
<< getDiagnosticString();
}
+// Test that extensions incorporated into SPIR-V 1.5 no longer require
+// the associated OpExtension instruction. Test one capability per extension.
+
+struct CapabilityExtensionVersionCase {
+ std::string capability;
+ std::string capability_new_name;
+ std::string extension;
+ spv_target_env last_version_requiring_extension;
+ spv_target_env first_version_in_core;
+};
+
+using ValidateCapabilityExtensionVersionTest =
+ spvtest::ValidateBase<CapabilityExtensionVersionCase>;
+
+// Returns a minimal shader module with the given capability instruction.
+std::string MinimalShaderModuleWithCapability(std::string cap) {
+ std::string mem_model =
+ (cap.find("VulkanMemory") == 0) ? "VulkanKHR" : "GLSL450";
+ std::string extra_cap = (cap.find("VulkanMemoryModelDeviceScope") == 0)
+ ? "\nOpCapability VulkanMemoryModelKHR\n"
+ : "";
+ return std::string("OpCapability ") + cap + extra_cap + R"(
+OpCapability Shader
+OpMemoryModel Logical )" + mem_model + R"(
+OpEntryPoint Vertex %main "main"
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+}
+
+TEST_P(ValidateCapabilityExtensionVersionTest, FailsInOlderSpirvVersion) {
+ const auto spirv = MinimalShaderModuleWithCapability(GetParam().capability);
+ CompileSuccessfully(spirv, GetParam().last_version_requiring_extension);
+ EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION,
+ ValidateInstructions(GetParam().last_version_requiring_extension));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr(std::string("1st operand of Capability: operand ") +
+ GetParam().capability_new_name))
+ << spirv << "\n";
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr(std::string("requires one of these extensions: ") +
+ GetParam().extension));
+}
+
+TEST_P(ValidateCapabilityExtensionVersionTest,
+ SucceedsInNewerSpirvVersionWithOldName) {
+ const auto spirv = MinimalShaderModuleWithCapability(GetParam().capability);
+ CompileSuccessfully(spirv, GetParam().first_version_in_core);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateInstructions(GetParam().first_version_in_core));
+ EXPECT_THAT(getDiagnosticString(), Eq("")) << spirv << "\n";
+}
+
+TEST_P(ValidateCapabilityExtensionVersionTest,
+ SucceedsInNewerSpirvVersionWithNewName) {
+ const auto spirv =
+ MinimalShaderModuleWithCapability(GetParam().capability_new_name);
+ CompileSuccessfully(spirv, GetParam().first_version_in_core);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateInstructions(GetParam().first_version_in_core));
+ EXPECT_THAT(getDiagnosticString(), Eq("")) << spirv << "\n";
+}
+
+std::vector<CapabilityExtensionVersionCase> CapVersionCases1_5() {
+#define IN15NOSUFFIX(C, E) \
+ { C, C, E, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5 }
+#define IN15(C, C_WITHOUT_SUFFIX, E) \
+ { C, C_WITHOUT_SUFFIX, E, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5 }
+ return std::vector<CapabilityExtensionVersionCase>{
+ // SPV_KHR_8bit_storage
+ IN15NOSUFFIX("StorageBuffer8BitAccess", "SPV_KHR_8bit_storage"),
+ IN15NOSUFFIX("UniformAndStorageBuffer8BitAccess", "SPV_KHR_8bit_storage"),
+ IN15NOSUFFIX("StoragePushConstant8", "SPV_KHR_8bit_storage"),
+ // SPV_EXT_descriptor_indexing
+ IN15("ShaderNonUniformEXT", "ShaderNonUniform",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("RuntimeDescriptorArrayEXT", "RuntimeDescriptorArray",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("InputAttachmentArrayDynamicIndexingEXT",
+ "InputAttachmentArrayDynamicIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("UniformTexelBufferArrayDynamicIndexingEXT",
+ "UniformTexelBufferArrayDynamicIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("StorageTexelBufferArrayDynamicIndexingEXT",
+ "StorageTexelBufferArrayDynamicIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("UniformBufferArrayNonUniformIndexingEXT",
+ "UniformBufferArrayNonUniformIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("SampledImageArrayNonUniformIndexingEXT",
+ "SampledImageArrayNonUniformIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("StorageBufferArrayNonUniformIndexingEXT",
+ "StorageBufferArrayNonUniformIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("StorageImageArrayNonUniformIndexingEXT",
+ "StorageImageArrayNonUniformIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("InputAttachmentArrayNonUniformIndexingEXT",
+ "InputAttachmentArrayNonUniformIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("UniformTexelBufferArrayNonUniformIndexingEXT",
+ "UniformTexelBufferArrayNonUniformIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ IN15("StorageTexelBufferArrayNonUniformIndexingEXT",
+ "StorageTexelBufferArrayNonUniformIndexing",
+ "SPV_EXT_descriptor_indexing"),
+ // SPV_EXT_physical_storage_buffer
+ IN15("PhysicalStorageBufferAddressesEXT",
+ "PhysicalStorageBufferAddresses", "SPV_EXT_physical_storage_buffer"),
+ // SPV_KHR_vulkan_memory_model
+ IN15("VulkanMemoryModelKHR", "VulkanMemoryModel",
+ "SPV_KHR_vulkan_memory_model"),
+ IN15("VulkanMemoryModelDeviceScopeKHR", "VulkanMemoryModelDeviceScope",
+ "SPV_KHR_vulkan_memory_model"),
+ };
+#undef IN15
+}
+
+INSTANTIATE_TEST_SUITE_P(NewInSpirv1_5, ValidateCapabilityExtensionVersionTest,
+ ValuesIn(CapVersionCases1_5()));
+
+TEST_P(ValidateCapability,
+ CapShaderViewportIndexLayerFailsInOlderSpirvVersion) {
+ const auto spirv =
+ MinimalShaderModuleWithCapability("ShaderViewportIndexLayerEXT");
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
+ EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION,
+ ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "1st operand of Capability: operand ShaderViewportIndexLayerEXT"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("requires one of these extensions: "
+ "SPV_EXT_shader_viewport_index_layer"));
+}
+
+TEST_P(ValidateCapability, CapShaderViewportIndexLayerFailsInNewSpirvVersion) {
+ const auto spirv =
+ MinimalShaderModuleWithCapability("ShaderViewportIndexLayerEXT");
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
+ EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION,
+ ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "1st operand of Capability: operand ShaderViewportIndexLayerEXT"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("requires one of these extensions: "
+ "SPV_EXT_shader_viewport_index_layer"));
+}
+
+TEST_F(ValidateCapability, CapShaderViewportIndexSucceedsInNewSpirvVersion) {
+ const auto spirv = MinimalShaderModuleWithCapability("ShaderViewportIndex");
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateCapability, CapShaderLayerSucceedsInNewSpirvVersion) {
+ const auto spirv = MinimalShaderModuleWithCapability("ShaderLayer");
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp
index b22db06..f06f36c 100644
--- a/test/val/val_cfg_test.cpp
+++ b/test/val/val_cfg_test.cpp
@@ -342,11 +342,10 @@
str += "OpFunctionEnd\n";
CompileSuccessfully(str);
- ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr(
- "Variables can only be defined in the first block of a function"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("All OpVariable instructions in a function must be the "
+ "first instructions in the first block"));
}
TEST_P(ValidateCFG, BlockSelfLoopIsOk) {
@@ -3027,6 +3026,7 @@
%undef = OpUndef %bool
%func = OpFunction %void None %void_fn
%entry = OpLabel
+OpSelectionMerge %block None
OpBranchConditional %undef %block %unreachable
%block = OpLabel
OpReturn
@@ -3050,6 +3050,7 @@
%undef = OpUndef %int
%func = OpFunction %void None %void_fn
%entry = OpLabel
+OpSelectionMerge %block1 None
OpSwitch %undef %block1 0 %unreachable 1 %block2
%block1 = OpLabel
OpReturn
@@ -3749,7 +3750,355 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-/// TODO(umar): Nested CFG constructs
+TEST_F(ValidateCFG, MissingMergeConditionalBranchBad) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpBranchConditional %undef %then %else
+%then = OpLabel
+OpReturn
+%else = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
+}
+
+TEST_F(ValidateCFG, MissingMergeSwitchBad) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%int = OpTypeInt 32 0
+%undef = OpUndef %int
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpSwitch %undef %then 0 %else
+%then = OpLabel
+OpReturn
+%else = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
+}
+
+TEST_F(ValidateCFG, MissingMergeSwitchBad2) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%int = OpTypeInt 32 0
+%undef = OpUndef %int
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpSwitch %undef %then 0 %then 1 %then 2 %else
+%then = OpLabel
+OpReturn
+%else = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
+}
+
+TEST_F(ValidateCFG, MissingMergeOneBranchToMergeGood) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpSelectionMerge %b3 None
+OpBranchConditional %undef %b1 %b2
+%b1 = OpLabel
+OpBranchConditional %undef %b2 %b3
+%b2 = OpLabel
+OpBranch %b3
+%b3 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MissingMergeSameTargetConditionalBranchGood) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpBranchConditional %undef %then %then
+%then = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MissingMergeOneTargetSwitchGood) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%int = OpTypeInt 32 0
+%undef = OpUndef %int
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpSwitch %undef %then 0 %then 1 %then
+%then = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MissingMergeOneUnseenTargetSwitchGood) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%int = OpTypeInt 32 0
+%undef_int = OpUndef %int
+%bool = OpTypeBool
+%undef_bool = OpUndef %bool
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpSelectionMerge %merge None
+OpBranchConditional %undef_bool %merge %b1
+%b1 = OpLabel
+OpSwitch %undef_int %b2 0 %b2 1 %merge 2 %b2
+%b2 = OpLabel
+OpBranch %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MissingMergeLoopBreakGood) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpBranch %loop
+%loop = OpLabel
+OpLoopMerge %exit %continue None
+OpBranch %body
+%body = OpLabel
+OpBranchConditional %undef %body2 %exit
+%body2 = OpLabel
+OpBranch %continue
+%continue = OpLabel
+OpBranch %loop
+%exit = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MissingMergeLoopContinueGood) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpBranch %loop
+%loop = OpLabel
+OpLoopMerge %exit %continue None
+OpBranch %body
+%body = OpLabel
+OpBranchConditional %undef %body2 %continue
+%body2 = OpLabel
+OpBranch %continue
+%continue = OpLabel
+OpBranch %loop
+%exit = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MissingMergeSwitchBreakGood) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpSelectionMerge %merge None
+OpSwitch %int_0 %merge 1 %b1
+%b1 = OpLabel
+OpBranchConditional %undef %merge %b2
+%b2 = OpLabel
+OpBranch %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MissingMergeSwitchFallThroughGood) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpSelectionMerge %merge None
+OpSwitch %int_0 %b1 1 %b2
+%b1 = OpLabel
+OpBranchConditional %undef %b3 %b2
+%b2 = OpLabel
+OpBranch %merge
+%b3 = OpLabel
+OpBranch %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateCFG, MissingMergeInALoopBad) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpBranch %loop
+%loop = OpLabel
+OpLoopMerge %exit %continue None
+OpBranch %body
+%body = OpLabel
+OpBranchConditional %undef %b1 %b2
+%b1 = OpLabel
+OpBranch %exit
+%b2 = OpLabel
+OpBranch %continue
+%continue = OpLabel
+OpBranch %loop
+%exit = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
+}
+
+TEST_F(ValidateCFG, MissingMergeCrissCrossBad) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpSelectionMerge %merge None
+OpBranchConditional %undef %b1 %b2
+%b1 = OpLabel
+OpBranchConditional %undef %b3 %b4
+%b2 = OpLabel
+OpBranchConditional %undef %b3 %b4
+%b3 = OpLabel
+OpBranch %merge
+%b4 = OpLabel
+OpBranch %merge
+%merge = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text);
+ EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
+}
} // namespace
} // namespace val
diff --git a/test/val/val_composites_test.cpp b/test/val/val_composites_test.cpp
index 74b6f20..e970562 100644
--- a/test/val/val_composites_test.cpp
+++ b/test/val/val_composites_test.cpp
@@ -648,7 +648,6 @@
%val16 = OpCompositeExtract %f32 %struct 4 1000 1
%val17 = OpCompositeExtract %f32 %struct 5 0
%val18 = OpCompositeExtract %u32 %struct 5 1
-%val19 = OpCompositeExtract %big_struct %struct
)";
CompileSuccessfully(GenerateShaderCode(body));
@@ -767,6 +766,18 @@
"indexes still remain to be traversed."));
}
+TEST_F(ValidateComposites, CompositeExtractNoIndices) {
+ const std::string body = R"(
+%struct = OpLoad %big_struct %var_big_struct
+%val1 = OpCompositeExtract %big_struct %struct
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected at least one index to OpCompositeExtract"));
+}
+
TEST_F(ValidateComposites, CompositeExtractWrongType1) {
const std::string body = R"(
%struct = OpLoad %big_struct %var_big_struct
@@ -861,7 +872,6 @@
%val16 = OpCompositeInsert %big_struct %f32_3 %struct 4 1000 1
%val17 = OpCompositeInsert %big_struct %f32_3 %struct 5 0
%val18 = OpCompositeInsert %big_struct %u32_3 %struct 5 1
-%val19 = OpCompositeInsert %big_struct %struct %struct
)";
CompileSuccessfully(GenerateShaderCode(body));
@@ -1157,9 +1167,8 @@
HasSubstr("The Result Type must be the same as Composite type"));
}
-// Valid: No Indexes were passed to OpCompositeExtract, and the Result Type is
-// the same as the Base Composite type.
-TEST_F(ValidateComposites, CompositeExtractNoIndexesGood) {
+// Invalid: No Indexes were passed to OpCompositeExtract.
+TEST_F(ValidateComposites, CompositeExtractNoIndices2) {
std::ostringstream spirv;
spirv << GetHeaderForTestsFromValId() << std::endl;
spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
@@ -1167,29 +1176,32 @@
spirv << R"(OpReturn
OpFunctionEnd)";
CompileSuccessfully(spirv.str());
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Expected at least one index to OpCompositeExtract, zero found"));
}
-// Invalid: No Indexes were passed to OpCompositeExtract, but the Result Type is
-// different from the Base Composite type.
-TEST_F(ValidateComposites, CompositeExtractNoIndexesBad) {
+// Invalid: No Indexes were passed to OpCompositeExtract.
+TEST_F(ValidateComposites, CompositeExtractNoIndicesWrongResultType) {
std::ostringstream spirv;
spirv << GetHeaderForTestsFromValId() << std::endl;
spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
- spirv << "%float_entry = OpCompositeExtract %float %matrix" << std::endl;
+ spirv << "%float_entry = OpCompositeExtract %float %matrix" << std::endl;
spirv << R"(OpReturn
OpFunctionEnd)";
CompileSuccessfully(spirv.str());
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Result type (OpTypeFloat) does not match the type "
- "that results from indexing into the composite "
- "(OpTypeMatrix)."));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Expected at least one index to OpCompositeExtract, zero found"));
}
-// Valid: No Indexes were passed to OpCompositeInsert, and the type of the
+// Invalid: No Indices were passed to OpCompositeInsert, and the type of the
// Object<id> argument matches the Composite type.
-TEST_F(ValidateComposites, CompositeInsertMissingIndexesGood) {
+TEST_F(ValidateComposites, CompositeInsertMissingIndices) {
std::ostringstream spirv;
spirv << GetHeaderForTestsFromValId() << std::endl;
spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
@@ -1199,12 +1211,16 @@
OpReturn
OpFunctionEnd)";
CompileSuccessfully(spirv.str());
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Expected at least one index to OpCompositeInsert, zero found"));
}
-// Invalid: No Indexes were passed to OpCompositeInsert, but the type of the
+// Invalid: No Indices were passed to OpCompositeInsert, but the type of the
// Object<id> argument does not match the Composite type.
-TEST_F(ValidateComposites, CompositeInsertMissingIndexesBad) {
+TEST_F(ValidateComposites, CompositeInsertMissingIndices2) {
std::ostringstream spirv;
spirv << GetHeaderForTestsFromValId() << std::endl;
spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
@@ -1214,10 +1230,10 @@
OpFunctionEnd)";
CompileSuccessfully(spirv.str());
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("The Object type (OpTypeInt) does not match the type "
- "that results from indexing into the Composite "
- "(OpTypeMatrix)."));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Expected at least one index to OpCompositeInsert, zero found"));
}
// Valid: Tests that we can index into Struct, Array, Matrix, and Vector!
diff --git a/test/val/val_constants_test.cpp b/test/val/val_constants_test.cpp
index 2499f5c..301539d 100644
--- a/test/val/val_constants_test.cpp
+++ b/test/val/val_constants_test.cpp
@@ -458,6 +458,26 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
+TEST_F(ValidateConstant, NullPhysicalStorageBuffer) {
+ std::string spirv = R"(
+OpCapability Shader
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Linkage
+OpExtension "SPV_KHR_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpName %ptr "ptr"
+%int = OpTypeInt 32 0
+%ptr = OpTypePointer PhysicalStorageBuffer %int
+%null = OpConstantNull %ptr
+)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpConstantNull Result Type <id> '1[%ptr]' cannot have "
+ "a null value"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_conversion_test.cpp b/test/val/val_conversion_test.cpp
index 8851af3..47e6793 100644
--- a/test/val/val_conversion_test.cpp
+++ b/test/val/val_conversion_test.cpp
@@ -248,6 +248,8 @@
%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3
%f64vec4_1234 = OpConstantComposite %f64vec4 %f64_1 %f64_2 %f64_3 %f64_4
+%u64vec2_01 = OpConstantComposite %u64vec2 %u64_0 %u64_1
+
%true = OpConstantTrue %bool
%false = OpConstantFalse %bool
@@ -1206,6 +1208,49 @@
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
+TEST_F(ValidateConversion, BitcastSuccessSPV1p5) {
+ const std::string body = R"(
+%ptr = OpVariable %f32ptr_func Function
+%val1 = OpBitcast %u32 %ptr
+%val2 = OpBitcast %u64 %ptr
+%val3 = OpBitcast %f32ptr_func %u32_1
+%val4 = OpBitcast %f32ptr_wg %u64_1
+%val5 = OpBitcast %f32 %u32_1
+%val6 = OpBitcast %f32vec2 %u32vec2_12
+%val7 = OpBitcast %f32vec2 %u64_1
+%val8 = OpBitcast %f64 %u32vec2_12
+%val9 = OpBitcast %f32vec4 %f64vec2_12
+%val10 = OpBitcast %u32ptr_func %u32vec2_01
+%val11 = OpBitcast %u32vec2 %ptr
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+}
+
+TEST_F(ValidateConversion, BitcastSuccessPhysicalStorageBufferKHR) {
+ const std::string body = R"(
+%ptr = OpVariable %f32ptr_func Function
+%val1 = OpBitcast %u32 %ptr
+%val2 = OpBitcast %u64 %ptr
+%val3 = OpBitcast %f32ptr_func %u32_1
+%val4 = OpBitcast %f32ptr_wg %u64_1
+%val5 = OpBitcast %f32 %u32_1
+%val6 = OpBitcast %f32vec2 %u32vec2_12
+%val7 = OpBitcast %f32vec2 %u64_1
+%val8 = OpBitcast %f64 %u32vec2_12
+%val9 = OpBitcast %f32vec4 %f64vec2_12
+%val10 = OpBitcast %u32ptr_func %u32vec2_01
+%val11 = OpBitcast %u32vec2 %ptr
+)";
+
+ CompileSuccessfully(
+ GenerateKernelCode(body,
+ "\nOpExtension \"SPV_KHR_physical_storage_buffer\"")
+ .c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
TEST_F(ValidateConversion, BitcastInputHasNoType) {
const std::string body = R"(
%val = OpBitcast %u32 %f32
@@ -1249,10 +1294,66 @@
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Expected input to be a pointer or int scalar if Result Type "
- "is pointer: Bitcast"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected input to be a pointer or int scalar if "
+ "Result Type is pointer: Bitcast"));
+}
+
+TEST_F(ValidateConversion, BitcastPtrWrongInputTypeSPV1p5) {
+ const std::string body = R"(
+%val = OpBitcast %u32ptr_func %f32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA,
+ ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected input to be a pointer, int scalar or 32-bit "
+ "int vector if Result Type is pointer: Bitcast"));
+}
+
+TEST_F(ValidateConversion, BitcastPtrWrongInputTypePhysicalStorageBufferKHR) {
+ const std::string body = R"(
+%val = OpBitcast %u32ptr_func %f32_1
+)";
+
+ CompileSuccessfully(
+ GenerateKernelCode(body,
+ "\nOpExtension \"SPV_KHR_physical_storage_buffer\"")
+ .c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected input to be a pointer, int scalar or 32-bit "
+ "int vector if Result Type is pointer: Bitcast"));
+}
+
+TEST_F(ValidateConversion, BitcastPtrWrongInputTypeIntVectorSPV1p5) {
+ const std::string body = R"(
+%val = OpBitcast %u32ptr_func %u64vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA,
+ ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected input to be a pointer, int scalar or 32-bit "
+ "int vector if Result Type is pointer: Bitcast"));
+}
+
+TEST_F(ValidateConversion,
+ BitcastPtrWrongInputTypeIntVectorPhysicalStorageBufferKHR) {
+ const std::string body = R"(
+%val = OpBitcast %u32ptr_func %u64vec2_01
+)";
+
+ CompileSuccessfully(
+ GenerateKernelCode(body,
+ "\nOpExtension \"SPV_KHR_physical_storage_buffer\"")
+ .c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected input to be a pointer, int scalar or 32-bit "
+ "int vector if Result Type is pointer: Bitcast"));
}
TEST_F(ValidateConversion, BitcastPtrWrongResultType) {
@@ -1262,11 +1363,66 @@
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr(
- "Pointer can only be converted to another pointer or int scalar: "
- "Bitcast"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Pointer can only be converted to another pointer or "
+ "int scalar: Bitcast"));
+}
+
+TEST_F(ValidateConversion, BitcastPtrWrongResultTypeSPV1p5) {
+ const std::string body = R"(
+%val = OpBitcast %f32 %f32inp
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA,
+ ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Pointer can only be converted to another pointer, int "
+ "scalar or 32-bit int vector: Bitcast"));
+}
+
+TEST_F(ValidateConversion, BitcastPtrWrongResultTypePhysicalStorageBufferKHR) {
+ const std::string body = R"(
+%val = OpBitcast %f32 %f32inp
+)";
+
+ CompileSuccessfully(
+ GenerateKernelCode(body,
+ "\nOpExtension \"SPV_KHR_physical_storage_buffer\"")
+ .c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Pointer can only be converted to another pointer, int "
+ "scalar or 32-bit int vector: Bitcast"));
+}
+
+TEST_F(ValidateConversion, BitcastPtrWrongResultTypeIntVectorSPV1p5) {
+ const std::string body = R"(
+%val = OpBitcast %u64vec2 %f32inp
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA,
+ ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Pointer can only be converted to another pointer, int "
+ "scalar or 32-bit int vector: Bitcast"));
+}
+
+TEST_F(ValidateConversion,
+ BitcastPtrWrongResultTypeIntVectorPhysicalStorageBufferKHR) {
+ const std::string body = R"(
+%val = OpBitcast %u64vec2 %f32inp
+)";
+
+ CompileSuccessfully(
+ GenerateKernelCode(body,
+ "\nOpExtension \"SPV_KHR_physical_storage_buffer\"")
+ .c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Pointer can only be converted to another pointer, int "
+ "scalar or 32-bit int vector: Bitcast"));
}
TEST_F(ValidateConversion, BitcastDifferentTotalBitWidth) {
diff --git a/test/val/val_data_test.cpp b/test/val/val_data_test.cpp
index 4690f97..30afd03 100644
--- a/test/val/val_data_test.cpp
+++ b/test/val/val_data_test.cpp
@@ -629,15 +629,26 @@
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateData, specialize_boolean_to_int) {
+TEST_F(ValidateData, specialize_boolean_true_to_int) {
std::string str = header + R"(
%2 = OpTypeInt 32 1
-%3 = OpSpecConstantTrue %2
+%3 = OpSpecConstantTrue %2)";
+ CompileSuccessfully(str.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpSpecConstantTrue Result Type <id> '1[%int]' is not "
+ "a boolean type"));
+}
+
+TEST_F(ValidateData, specialize_boolean_false_to_int) {
+ std::string str = header + R"(
+%2 = OpTypeInt 32 1
%4 = OpSpecConstantFalse %2)";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Specialization constant must be a boolean"));
+ HasSubstr("OpSpecConstantFalse Result Type <id> '1[%int]' is not "
+ "a boolean type"));
}
TEST_F(ValidateData, missing_forward_pointer_decl) {
@@ -648,7 +659,7 @@
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("must first be declared using OpTypeForwardPointer"));
+ HasSubstr("Operand 3[%3] requires a previous definition"));
}
TEST_F(ValidateData, missing_forward_pointer_decl_self_reference) {
@@ -658,8 +669,9 @@
)";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("must first be declared using OpTypeForwardPointer"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Operand 2[%_struct_2] requires a previous definition"));
}
TEST_F(ValidateData, forward_pointer_missing_definition) {
@@ -698,9 +710,7 @@
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("A forward reference operand in an OpTypeStruct must "
- "be an OpTypePointer that points to an OpTypeStruct. "
- "Found OpTypePointer that points to OpTypeInt."));
+ HasSubstr("Forward pointers must point to a structure"));
}
TEST_F(ValidateData, struct_forward_pointer_good) {
@@ -934,23 +944,6 @@
"OpTypeStruct %_runtimearr_uint %uint\n"));
}
-TEST_F(ValidateData, invalid_forward_reference_in_array) {
- std::string str = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- %uint = OpTypeInt 32 0
-%uint_1 = OpConstant %uint 1
-%_arr_3_uint_1 = OpTypeArray %_arr_3_uint_1 %uint_1
-)";
-
- CompileSuccessfully(str.c_str(), SPV_ENV_UNIVERSAL_1_3);
- ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Forward reference operands in an OpTypeArray must "
- "first be declared using OpTypeForwardPointer."));
-}
-
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index c267dbf..256e115 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -4785,7 +4785,8 @@
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("requires SPIR-V version 1.4 or later\n"
- " OpDecorateId %int0 UniformId %subgroupscope"));
+ " OpDecorateId %int0 UniformId %subgroupscope"))
+ << spirv;
}
TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV13BadTargetV14) {
@@ -4860,9 +4861,8 @@
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("ConstantNull: expected Execution Scope to be a 32-bit int"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("ConstantNull: expected scope to be a 32-bit int"));
}
TEST_F(ValidateDecorations,
@@ -6690,6 +6690,311 @@
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
+TEST_F(ValidateDecorations, VulkanStorageBufferBlock) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %struct Block
+OpMemberDecorate %struct 0 Offset 0
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%struct = OpTypeStruct %uint
+%ptr_ssbo = OpTypePointer StorageBuffer %struct
+%var = OpVariable %ptr_ssbo StorageBuffer
+%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(ValidateDecorations, VulkanStorageBufferMissingBlock) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%struct = OpTypeStruct %uint
+%ptr_ssbo = OpTypePointer StorageBuffer %struct
+%var = OpVariable %ptr_ssbo StorageBuffer
+%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(),
+ HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables "
+ "must be identified with a Block decoration"));
+}
+
+TEST_F(ValidateDecorations, VulkanStorageBufferArrayMissingBlock) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%uint_4 = OpConstant %uint 4
+%struct = OpTypeStruct %uint
+%array = OpTypeArray %struct %uint_4
+%ptr_ssbo = OpTypePointer StorageBuffer %array
+%var = OpVariable %ptr_ssbo StorageBuffer
+%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(),
+ HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables "
+ "must be identified with a Block decoration"));
+}
+
+TEST_F(ValidateDecorations, VulkanStorageBufferRuntimeArrayMissingBlock) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpCapability RuntimeDescriptorArrayEXT
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%struct = OpTypeStruct %uint
+%array = OpTypeRuntimeArray %struct
+%ptr_ssbo = OpTypePointer StorageBuffer %array
+%var = OpVariable %ptr_ssbo StorageBuffer
+%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(),
+ HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables "
+ "must be identified with a Block decoration"));
+}
+
+TEST_F(ValidateDecorations, VulkanUniformBlock) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %struct Block
+OpMemberDecorate %struct 0 Offset 0
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%struct = OpTypeStruct %uint
+%ptr_ubo = OpTypePointer Uniform %struct
+%var = OpVariable %ptr_ubo Uniform
+%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(ValidateDecorations, VulkanUniformBufferBlock) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %struct BufferBlock
+OpMemberDecorate %struct 0 Offset 0
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%struct = OpTypeStruct %uint
+%ptr_ubo = OpTypePointer Uniform %struct
+%var = OpVariable %ptr_ubo Uniform
+%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(ValidateDecorations, VulkanUniformMissingBlock) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%struct = OpTypeStruct %uint
+%ptr_ubo = OpTypePointer Uniform %struct
+%var = OpVariable %ptr_ubo Uniform
+%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(),
+ HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables must be "
+ "identified with a Block or BufferBlock decoration"));
+}
+
+TEST_F(ValidateDecorations, VulkanUniformArrayMissingBlock) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%uint_4 = OpConstant %uint 4
+%struct = OpTypeStruct %uint
+%array = OpTypeArray %struct %uint_4
+%ptr_ubo = OpTypePointer Uniform %array
+%var = OpVariable %ptr_ubo Uniform
+%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(),
+ HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables must be "
+ "identified with a Block or BufferBlock decoration"));
+}
+
+TEST_F(ValidateDecorations, VulkanUniformRuntimeArrayMissingBlock) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpCapability RuntimeDescriptorArrayEXT
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%struct = OpTypeStruct %uint
+%array = OpTypeRuntimeArray %struct
+%ptr_ubo = OpTypePointer Uniform %array
+%var = OpVariable %ptr_ubo Uniform
+%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(),
+ HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables must be "
+ "identified with a Block or BufferBlock decoration"));
+}
+
+TEST_F(ValidateDecorations, VulkanArrayStrideZero) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %var DescriptorSet 0
+OpDecorate %var Binding 0
+OpDecorate %struct Block
+OpMemberDecorate %struct 0 Offset 0
+OpDecorate %array ArrayStride 0
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_4 = OpConstant %int 4
+%array = OpTypeArray %int %int_4
+%struct = OpTypeStruct %array
+%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
+%var = OpVariable %ptr_ssbo_struct StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("contains an array with stride 0"));
+}
+
+TEST_F(ValidateDecorations, VulkanArrayStrideTooSmall) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpDecorate %var DescriptorSet 0
+OpDecorate %var Binding 0
+OpDecorate %struct Block
+OpMemberDecorate %struct 0 Offset 0
+OpDecorate %inner ArrayStride 4
+OpDecorate %outer ArrayStride 4
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_4 = OpConstant %int 4
+%inner = OpTypeArray %int %int_4
+%outer = OpTypeArray %inner %int_4
+%struct = OpTypeStruct %outer
+%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
+%var = OpVariable %ptr_ssbo_struct StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "contains an array with stride 4, but with an element size of 16"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_derivatives_test.cpp b/test/val/val_derivatives_test.cpp
index dac95f6..606abb9 100644
--- a/test/val/val_derivatives_test.cpp
+++ b/test/val/val_derivatives_test.cpp
@@ -62,7 +62,17 @@
%f32vec4_ptr_input = OpTypePointer Input %f32vec4
%f32vec4_var_input = OpVariable %f32vec4_ptr_input Input
+)";
+ if (capabilities_and_extensions.find("OpCapability Float16") !=
+ std::string::npos) {
+ ss << "%f16 = OpTypeFloat 16\n"
+ << "%f16vec4 = OpTypeVector %f16 4\n"
+ << "%f16_0 = OpConstantNull %f16\n"
+ << "%f16vec4_0 = OpConstantNull %f16vec4\n";
+ }
+
+ ss << R"(
%main = OpFunction %void None %func
%main_entry = OpLabel
)";
@@ -150,6 +160,36 @@
"execution model: DPdx"));
}
+using ValidateHalfDerivatives = spvtest::ValidateBase<std::string>;
+
+TEST_P(ValidateHalfDerivatives, ScalarFailure) {
+ const std::string op = GetParam();
+ const std::string body = "%val = " + op + " %f16 %f16_0\n";
+
+ CompileSuccessfully(
+ GenerateShaderCode(body, "OpCapability Float16\n").c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Result type component width must be 32 bits"));
+}
+
+TEST_P(ValidateHalfDerivatives, VectorFailure) {
+ const std::string op = GetParam();
+ const std::string body = "%val = " + op + " %f16vec4 %f16vec4_0\n";
+
+ CompileSuccessfully(
+ GenerateShaderCode(body, "OpCapability Float16\n").c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Result type component width must be 32 bits"));
+}
+
+INSTANTIATE_TEST_SUITE_P(HalfDerivatives, ValidateHalfDerivatives,
+ ::testing::Values("OpDPdx", "OpDPdy", "OpFwidth",
+ "OpDPdxFine", "OpDPdyFine",
+ "OpFwidthFine", "OpDPdxCoarse",
+ "OpDPdyCoarse", "OpFwidthCoarse"));
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_entry_point.cpp b/test/val/val_entry_point.cpp
new file mode 100644
index 0000000..f28cf5d
--- /dev/null
+++ b/test/val/val_entry_point.cpp
@@ -0,0 +1,76 @@
+// Copyright (c) 2019 Samsung Inc
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "test/unit_spirv.h"
+#include "test/val/val_fixtures.h"
+
+namespace spvtools {
+namespace {
+
+using ::testing::Eq;
+using ::testing::HasSubstr;
+
+using ValidateEntryPoints = spvtest::ValidateBase<bool>;
+
+TEST_F(ValidateEntryPoints, DuplicateEntryPoints) {
+ const std::string body = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %3 "foo"
+OpEntryPoint GLCompute %4 "foo"
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%3 = OpFunction %1 None %2
+%20 = OpLabel
+OpReturn
+OpFunctionEnd
+%4 = OpFunction %1 None %2
+%21 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Entry points cannot share the same name"));
+}
+
+TEST_F(ValidateEntryPoints, UniqueEntryPoints) {
+ const std::string body = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %3 "foo"
+OpEntryPoint GLCompute %4 "foo2"
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%3 = OpFunction %1 None %2
+%20 = OpLabel
+OpReturn
+OpFunctionEnd
+%4 = OpFunction %1 None %2
+%21 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+} // namespace
+} // namespace spvtools
diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp
index ec5715c..327aef1 100644
--- a/test/val/val_id_test.cpp
+++ b/test/val/val_id_test.cpp
@@ -1476,7 +1476,8 @@
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Specialization constant must be a boolean type."));
+ HasSubstr("OpSpecConstantTrue Result Type <id> '1[%void]' is not "
+ "a boolean type"));
}
TEST_F(ValidateIdWithMessage, OpSpecConstantFalseGood) {
@@ -1492,8 +1493,10 @@
%2 = OpSpecConstantFalse %1)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Specialization constant must be a boolean type."));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpSpecConstantFalse Result Type <id> '1[%void]' is not "
+ "a boolean type"));
}
TEST_F(ValidateIdWithMessage, OpSpecConstantGood) {
@@ -2317,8 +2320,8 @@
%6 = OpFunction %1 None %4
%7 = OpLabel
%8 = OpLoad %2 %5
- %9 = OpReturn
-%10 = OpFunctionEnd
+ OpReturn
+ OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
@@ -5176,8 +5179,7 @@
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Forward reference operands in an OpTypeStruct must "
- "first be declared using OpTypeForwardPointer."));
+ HasSubstr("Operand 2[%2] requires a previous definition"));
}
TEST_F(ValidateIdWithMessage, UndefinedIdScope) {
@@ -6462,6 +6464,26 @@
"pointer definition.\n OpTypeForwardPointer "
"%_ptr_Function_int CrossWorkgroup"));
}
+
+TEST_F(ValidateIdWithMessage, MissingForwardPointer) {
+ const std::string spirv = R"(
+ OpCapability Linkage
+ OpCapability Shader
+ OpMemoryModel Logical Simple
+ %float = OpTypeFloat 32
+ %_struct_9 = OpTypeStruct %float %_ptr_Uniform__struct_9
+%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
+ %1278 = OpVariable %_ptr_Uniform__struct_9 Uniform
+)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Operand 3[%_ptr_Uniform__struct_2] requires a previous definition"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp
index fd3d886..433c9fa 100644
--- a/test/val/val_image_test.cpp
+++ b/test/val/val_image_test.cpp
@@ -2938,7 +2938,7 @@
TEST_F(ValidateImage, WriteSuccess1) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %u32vec4_0123
+OpImageWrite %img %u32vec2_01 %u32vec4_0123
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -2949,7 +2949,7 @@
TEST_F(ValidateImage, WriteSuccess2) {
const std::string body = R"(
%img = OpLoad %type_image_f32_1d_0002_rgba32f %uniform_image_f32_1d_0002_rgba32f
-%res1 = OpImageWrite %img %u32_1 %f32vec4_0000
+OpImageWrite %img %u32_1 %f32vec4_0000
)";
const std::string extra = "\nOpCapability Image1D\n";
@@ -2960,7 +2960,7 @@
TEST_F(ValidateImage, WriteSuccess3) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0102_rgba32f %uniform_image_f32_cube_0102_rgba32f
-%res1 = OpImageWrite %img %u32vec3_012 %f32vec4_0000
+OpImageWrite %img %u32vec3_012 %f32vec4_0000
)";
const std::string extra = "\nOpCapability ImageCubeArray\n";
@@ -2972,8 +2972,8 @@
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?
-%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000
-%res2 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1
+OpImageWrite %img %u32vec2_01 %f32vec4_0000
+OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -2984,7 +2984,7 @@
TEST_F(ValidateImage, WriteSubpassData) {
const std::string body = R"(
%img = OpLoad %type_image_f32_spd_0002 %uniform_image_f32_spd_0002
-%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000
+OpImageWrite %img %u32vec2_01 %f32vec4_0000
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -2996,7 +2996,7 @@
TEST_F(ValidateImage, WriteNeedCapabilityStorageImageWriteWithoutFormat) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %u32vec4_0123
+OpImageWrite %img %u32vec2_01 %u32vec4_0123
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -3006,7 +3006,7 @@
TEST_F(ValidateImage, WriteNeedCapabilityStorageImageWriteWithoutFormatVulkan) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %u32vec4_0123
+OpImageWrite %img %u32vec2_01 %u32vec4_0123
)";
spv_target_env env = SPV_ENV_VULKAN_1_0;
@@ -3023,7 +3023,7 @@
TEST_F(ValidateImage, WriteNeedCapabilityImage1D) {
const std::string body = R"(
%img = OpLoad %type_image_f32_1d_0002_rgba32f %uniform_image_f32_1d_0002_rgba32f
-%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000
+OpImageWrite %img %u32vec2_01 %f32vec4_0000
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -3036,7 +3036,7 @@
TEST_F(ValidateImage, WriteNeedCapabilityImageCubeArray) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0102_rgba32f %uniform_image_f32_cube_0102_rgba32f
-%res1 = OpImageWrite %img %u32vec3_012 %f32vec4_0000
+OpImageWrite %img %u32vec3_012 %f32vec4_0000
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -3050,7 +3050,7 @@
TEST_F(ValidateImage, WriteNotImage) {
const std::string body = R"(
%sampler = OpLoad %type_sampler %uniform_sampler
-%res1 = OpImageWrite %sampler %u32vec2_01 %f32vec4_0000
+OpImageWrite %sampler %u32vec2_01 %f32vec4_0000
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
@@ -3062,7 +3062,7 @@
TEST_F(ValidateImage, WriteImageSampled) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
-%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000
+OpImageWrite %img %u32vec2_01 %f32vec4_0000
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -3075,7 +3075,7 @@
TEST_F(ValidateImage, WriteWrongCoordinateType) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %f32vec2_00 %u32vec4_0123
+OpImageWrite %img %f32vec2_00 %u32vec4_0123
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -3088,7 +3088,7 @@
TEST_F(ValidateImage, WriteCoordinateSizeTooSmall) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32_1 %u32vec4_0123
+OpImageWrite %img %u32_1 %u32vec4_0123
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -3102,7 +3102,7 @@
TEST_F(ValidateImage, WriteTexelWrongType) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %img
+OpImageWrite %img %u32vec2_01 %img
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -3115,7 +3115,7 @@
TEST_F(ValidateImage, DISABLED_WriteTexelNotVector4) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %u32vec3_012
+OpImageWrite %img %u32vec2_01 %u32vec3_012
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -3128,7 +3128,7 @@
TEST_F(ValidateImage, WriteTexelWrongComponentType) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000
+OpImageWrite %img %u32vec2_01 %f32vec4_0000
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -3143,7 +3143,7 @@
TEST_F(ValidateImage, WriteSampleNotInteger) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010
-%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %f32_1
+OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %f32_1
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -3156,7 +3156,7 @@
TEST_F(ValidateImage, SampleNotMultisampled) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
-%res2 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1
+OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1
)";
const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n";
@@ -4527,7 +4527,7 @@
TEST_F(ValidateImage, MakeTexelAvailableKHRSuccessImageWrite) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_2
+OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_2
)";
const std::string extra = R"(
@@ -4567,7 +4567,7 @@
TEST_F(ValidateImage, MakeTexelAvailableKHRFailureMissingNonPrivate) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR %u32_1
+OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR %u32_1
)";
const std::string extra = R"(
@@ -4588,7 +4588,7 @@
TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageWriteBad) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1
+OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1
)";
const std::string extra = R"(
@@ -4610,7 +4610,7 @@
TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageWriteGood) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
-%res1 = OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1
+OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1
)";
const std::string extra = R"(
diff --git a/test/val/val_limits_test.cpp b/test/val/val_limits_test.cpp
index becf7be..0ef61e2 100644
--- a/test/val/val_limits_test.cpp
+++ b/test/val/val_limits_test.cpp
@@ -212,7 +212,7 @@
%5 = OpFunction %1 None %2
%7 = OpLabel
%8 = OpIAdd %3 %4 %4
-%9 = OpSwitch %4 %10)";
+ OpSwitch %4 %10)";
// Now add the (literal, label) pairs
for (int i = 0; i < 16383; ++i) {
@@ -240,7 +240,7 @@
%5 = OpFunction %1 None %2
%7 = OpLabel
%8 = OpIAdd %3 %4 %4
-%9 = OpSwitch %4 %10)";
+ OpSwitch %4 %10)";
// Now add the (literal, label) pairs
for (int i = 0; i < 16384; ++i) {
@@ -271,7 +271,7 @@
%5 = OpFunction %1 None %2
%7 = OpLabel
%8 = OpIAdd %3 %4 %4
-%9 = OpSwitch %4 %10)";
+ OpSwitch %4 %10)";
// Now add the (literal, label) pairs
for (int i = 0; i < 10; ++i) {
@@ -301,7 +301,7 @@
%5 = OpFunction %1 None %2
%7 = OpLabel
%8 = OpIAdd %3 %4 %4
-%9 = OpSwitch %4 %10)";
+ OpSwitch %4 %10)";
// Now add the (literal, label) pairs
for (int i = 0; i < 11; ++i) {
diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp
index 54009df..22761cc 100644
--- a/test/val/val_memory_test.cpp
+++ b/test/val/val_memory_test.cpp
@@ -1492,8 +1492,8 @@
getDiagnosticString(),
HasSubstr(
"Source memory access must not include MakePointerAvailableKHR\n"
- " OpCopyMemory %5 %6 MakePointerAvailableKHR|NonPrivatePointerKHR"
- " %uint_1 MakePointerAvailableKHR|NonPrivatePointerKHR %uint_1"));
+ " OpCopyMemory %5 %6 MakePointerAvailable|NonPrivatePointer"
+ " %uint_1 MakePointerAvailable|NonPrivatePointer %uint_1"));
}
TEST_F(ValidateMemory, VulkanMemoryModelCopyMemoryTwoAccessSecondWithVisBad) {
@@ -1525,10 +1525,9 @@
ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr(
- "Target memory access must not include MakePointerVisibleKHR\n"
- " OpCopyMemory %5 %6 MakePointerVisibleKHR|NonPrivatePointerKHR"
- " %uint_1 MakePointerVisibleKHR|NonPrivatePointerKHR %uint_1"));
+ HasSubstr("Target memory access must not include MakePointerVisibleKHR\n"
+ " OpCopyMemory %5 %6 MakePointerVisible|NonPrivatePointer"
+ " %uint_1 MakePointerVisible|NonPrivatePointer %uint_1"));
}
TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedBad1) {
@@ -2319,9 +2318,14 @@
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
+OpDecorate %struct Block
+OpMemberDecorate %struct 0 Offset 0
%sampler_t = OpTypeSampler
+%uint = OpTypeInt 32 0
%array_t = OpTypeRuntimeArray %sampler_t
-%array_sb_ptr = OpTypePointer StorageBuffer %array_t
+%struct = OpTypeStruct %uint
+%sb_array_t = OpTypeRuntimeArray %struct
+%array_sb_ptr = OpTypePointer StorageBuffer %sb_array_t
%2 = OpVariable %array_sb_ptr StorageBuffer
%array_uc_ptr = OpTypePointer UniformConstant %array_t
%3 = OpVariable %array_uc_ptr UniformConstant
@@ -2992,6 +2996,7 @@
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
+OpDecorate %inner_array_t ArrayStride 4
OpDecorate %array_t ArrayStride 4
OpMemberDecorate %struct_t 0 Offset 0
OpDecorate %struct_t Block
@@ -3021,6 +3026,7 @@
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
+OpDecorate %inner_array_t ArrayStride 4
OpDecorate %array_t ArrayStride 4
OpMemberDecorate %struct_t 0 Offset 0
OpDecorate %struct_t Block
@@ -4293,6 +4299,185 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
+TEST_F(ValidateMemory, VulkanStorageBufferNotAStruct) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%ptr_ssbo = OpTypePointer StorageBuffer %uint
+%var = OpVariable %ptr_ssbo StorageBuffer
+%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(),
+ HasSubstr("From Vulkan spec, section 14.5.2:\nVariables identified with "
+ "the StorageBuffer storage class are used to access "
+ "transparent buffer backed resources. Such variables must be "
+ "typed as OpTypeStruct, or an array of this type"));
+}
+
+TEST_F(ValidateMemory, VulkanStorageBufferRuntimeArrayNotAStruct) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpCapability RuntimeDescriptorArrayEXT
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpExtension "SPV_EXT_descriptor_indexing"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%array = OpTypeRuntimeArray %uint
+%ptr_ssbo = OpTypePointer StorageBuffer %array
+%var = OpVariable %ptr_ssbo StorageBuffer
+%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(),
+ HasSubstr("From Vulkan spec, section 14.5.2:\nVariables identified with "
+ "the StorageBuffer storage class are used to access "
+ "transparent buffer backed resources. Such variables must be "
+ "typed as OpTypeStruct, or an array of this type"));
+}
+
+TEST_F(ValidateMemory, VulkanStorageBufferArrayNotAStruct) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%uint = OpTypeInt 32 0
+%uint_4 = OpConstant %uint 4
+%array = OpTypeArray %uint %uint_4
+%ptr_ssbo = OpTypePointer StorageBuffer %array
+%var = OpVariable %ptr_ssbo StorageBuffer
+%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(),
+ HasSubstr("From Vulkan spec, section 14.5.2:\nVariables identified with "
+ "the StorageBuffer storage class are used to access "
+ "transparent buffer backed resources. Such variables must be "
+ "typed as OpTypeStruct, or an array of this type"));
+}
+
+TEST_F(ValidateMemory, PhysicalStorageBufferPtrEqual) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpCapability Int64
+OpCapability PhysicalStorageBufferAddresses
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%bool = OpTypeBool
+%long = OpTypeInt 64 0
+%long_0 = OpConstant %long 0
+%ptr_pssbo_long = OpTypePointer PhysicalStorageBuffer %long
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%conv = OpConvertUToPtr %ptr_pssbo_long %long_0
+%eq = OpPtrEqual %bool %conv %conv
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Cannot use a pointer in the PhysicalStorageBuffer storage class"));
+}
+
+TEST_F(ValidateMemory, PhysicalStorageBufferPtrNotEqual) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpCapability Int64
+OpCapability PhysicalStorageBufferAddresses
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%bool = OpTypeBool
+%long = OpTypeInt 64 0
+%long_0 = OpConstant %long 0
+%ptr_pssbo_long = OpTypePointer PhysicalStorageBuffer %long
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%conv = OpConvertUToPtr %ptr_pssbo_long %long_0
+%neq = OpPtrNotEqual %bool %conv %conv
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Cannot use a pointer in the PhysicalStorageBuffer storage class"));
+}
+
+TEST_F(ValidateMemory, PhysicalStorageBufferPtrDiff) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpCapability Int64
+OpCapability PhysicalStorageBufferAddresses
+OpCapability VariablePointers
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+%void = OpTypeVoid
+%long = OpTypeInt 64 0
+%long_0 = OpConstant %long 0
+%ptr_pssbo_long = OpTypePointer PhysicalStorageBuffer %long
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%conv = OpConvertUToPtr %ptr_pssbo_long %long_0
+%diff = OpPtrDiff %long %conv %conv
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Cannot use a pointer in the PhysicalStorageBuffer storage class"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_misc_test.cpp b/test/val/val_misc_test.cpp
index 350f561..9395484 100644
--- a/test/val/val_misc_test.cpp
+++ b/test/val/val_misc_test.cpp
@@ -83,6 +83,149 @@
getDiagnosticString(),
HasSubstr("Cannot create undefined values with 8- or 16-bit types"));
}
+
+const std::string ShaderClockSpriv = R"(
+OpCapability Shader
+OpCapability Int64
+OpCapability ShaderClockKHR
+OpExtension "SPV_KHR_shader_clock"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 450
+OpSourceExtension "GL_ARB_gpu_shader_int64"
+OpSourceExtension "GL_ARB_shader_clock"
+OpSourceExtension "GL_EXT_shader_realtime_clock"
+OpName %main "main"
+OpName %time1 "time1"
+%void = OpTypeVoid
+)";
+
+TEST_F(ValidateMisc, ShaderClockInt64) {
+ const std::string spirv = ShaderClockSpriv + R"(
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_3 = OpConstant %uint 3
+%uint_1 = OpConstant %uint 1
+%main = OpFunction %void None %3
+%5 = OpLabel
+%time1 = OpVariable %_ptr_Function_uint Function
+%11 = OpReadClockKHR %uint %uint_3
+OpStore %time1 %11
+OpReturn
+OpFunctionEnd)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("or 64bit unsigned integer"));
+}
+
+TEST_F(ValidateMisc, ShaderClockVec2) {
+ const std::string spirv = ShaderClockSpriv + R"(
+%3 = OpTypeFunction %void
+%ulong = OpTypeInt 64 0
+%_ptr_Function_ulong = OpTypePointer Function %ulong
+%uint = OpTypeInt 32 0
+%uint_3 = OpConstant %uint 3
+%v2uint = OpTypeVector %ulong 2
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+%main = OpFunction %void None %3
+%5 = OpLabel
+%time1 = OpVariable %_ptr_Function_v2uint Function
+%15 = OpReadClockKHR %v2uint %uint_3
+OpStore %time1 %15
+OpReturn
+OpFunctionEnd)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("vector of two components"));
+}
+
+TEST_F(ValidateMisc, ShaderClockInvalidScopeValue) {
+ const std::string spirv = ShaderClockSpriv + R"(
+%3 = OpTypeFunction %void
+%ulong = OpTypeInt 64 0
+%uint = OpTypeInt 32 0
+%_ptr_Function_ulong = OpTypePointer Function %ulong
+%uint_10 = OpConstant %uint 10
+%uint_1 = OpConstant %uint 1
+%main = OpFunction %void None %3
+%5 = OpLabel
+%time1 = OpVariable %_ptr_Function_ulong Function
+%11 = OpReadClockKHR %ulong %uint_10
+OpStore %time1 %11
+OpReturn
+OpFunctionEnd)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Invalid scope value"));
+}
+
+TEST_F(ValidateMisc, ShaderClockSubgroupScope) {
+ const std::string spirv = ShaderClockSpriv + R"(
+%3 = OpTypeFunction %void
+%ulong = OpTypeInt 64 0
+%uint = OpTypeInt 32 0
+%_ptr_Function_ulong = OpTypePointer Function %ulong
+%subgroup = OpConstant %uint 3
+%uint_1 = OpConstant %uint 1
+%main = OpFunction %void None %3
+%5 = OpLabel
+%time1 = OpVariable %_ptr_Function_ulong Function
+%11 = OpReadClockKHR %ulong %subgroup
+OpStore %time1 %11
+OpReturn
+OpFunctionEnd)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateMisc, ShaderClockDeviceScope) {
+ const std::string spirv = ShaderClockSpriv + R"(
+%3 = OpTypeFunction %void
+%ulong = OpTypeInt 64 0
+%uint = OpTypeInt 32 0
+%_ptr_Function_ulong = OpTypePointer Function %ulong
+%device = OpConstant %uint 1
+%uint_1 = OpConstant %uint 1
+%main = OpFunction %void None %3
+%5 = OpLabel
+%time1 = OpVariable %_ptr_Function_ulong Function
+%11 = OpReadClockKHR %ulong %device
+OpStore %time1 %11
+OpReturn
+OpFunctionEnd)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateMisc, ShaderClockWorkgroupScope) {
+ 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);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Scope must be Subgroup or Device"));
+}
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_opencl_test.cpp b/test/val/val_opencl_test.cpp
index 18b2f71..1064158 100644
--- a/test/val/val_opencl_test.cpp
+++ b/test/val/val_opencl_test.cpp
@@ -45,15 +45,18 @@
TEST_F(ValidateOpenCL, NonOpenCLMemoryModelBad) {
std::string spirv = R"(
OpCapability Kernel
- OpMemoryModel Physical32 GLSL450
+ OpCapability Addresses
+ OpCapability VulkanMemoryModelKHR
+ OpExtension "SPV_KHR_vulkan_memory_model"
+ OpMemoryModel Physical32 VulkanKHR
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Memory model must be OpenCL in the OpenCL environment."
- "\n OpMemoryModel Physical32 GLSL450\n"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Memory model must be OpenCL in the OpenCL environment."));
}
TEST_F(ValidateOpenCL, NonVoidSampledTypeImageBad) {
diff --git a/test/val/val_ssa_test.cpp b/test/val/val_ssa_test.cpp
index e10abd7..035c710 100644
--- a/test/val/val_ssa_test.cpp
+++ b/test/val/val_ssa_test.cpp
@@ -1415,7 +1415,8 @@
OpName %intptrt "intptrt"
OpTypeForwardPointer %intptrt UniformConstant
%uint = OpTypeInt 32 0
- %intptrt = OpTypePointer UniformConstant %uint
+ %struct = OpTypeStruct %uint
+ %intptrt = OpTypePointer UniformConstant %struct
)";
CompileSuccessfully(str);
diff --git a/test/val/val_storage_test.cpp b/test/val/val_storage_test.cpp
index f54b425..fe37a93 100644
--- a/test/val/val_storage_test.cpp
+++ b/test/val/val_storage_test.cpp
@@ -157,6 +157,7 @@
const auto str = R"(
OpCapability Kernel
OpCapability Linkage
+ OpCapability GenericPointer
OpMemoryModel Logical OpenCL
%intt = OpTypeInt 32 0
%ptrt = OpTypePointer Function %intt
@@ -172,6 +173,7 @@
const auto str = R"(
OpCapability Shader
OpCapability Linkage
+ OpCapability GenericPointer
OpMemoryModel Logical GLSL450
%intt = OpTypeInt 32 1
%voidt = OpTypeVoid
@@ -184,7 +186,7 @@
OpFunctionEnd
)";
CompileSuccessfully(str);
- ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
+ EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpVariable storage class cannot be Generic"));
}
@@ -307,12 +309,10 @@
std::make_tuple("Workgroup", false, true, ""),
std::make_tuple("Private", false, true, ""),
std::make_tuple("Function", true, true, ""),
- std::make_tuple(
- "CrossWorkgroup", false, false,
- "For WebGPU, OpTypePointer storage class must be one of"),
- std::make_tuple(
- "PushConstant", false, false,
- "For WebGPU, OpTypePointer storage class must be one of")));
+ 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
diff --git a/test/val/val_type_unique_test.cpp b/test/val/val_type_unique_test.cpp
index 67ceadd..45a4d50 100644
--- a/test/val/val_type_unique_test.cpp
+++ b/test/val/val_type_unique_test.cpp
@@ -210,9 +210,11 @@
OpTypeForwardPointer %ptr Generic
OpTypeForwardPointer %ptr2 Generic
%intt = OpTypeInt 32 0
+%int_struct = OpTypeStruct %intt
%floatt = OpTypeFloat 32
-%ptr = OpTypePointer Generic %intt
-%ptr2 = OpTypePointer Generic %floatt
+%ptr = OpTypePointer Generic %int_struct
+%float_struct = OpTypeStruct %floatt
+%ptr2 = OpTypePointer Generic %float_struct
)";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
diff --git a/test/val/val_webgpu_test.cpp b/test/val/val_webgpu_test.cpp
index c55f927..8f62555 100644
--- a/test/val/val_webgpu_test.cpp
+++ b/test/val/val_webgpu_test.cpp
@@ -187,23 +187,6 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
}
-TEST_F(ValidateWebGPU, NonLogicalAddressingModelBad) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability VulkanMemoryModelKHR
- OpExtension "SPV_KHR_vulkan_memory_model"
- OpMemoryModel Physical32 VulkanKHR
-)";
-
- CompileSuccessfully(spirv);
-
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Addressing model must be Logical for WebGPU "
- "environment.\n OpMemoryModel Physical32 "
- "VulkanKHR\n"));
-}
-
TEST_F(ValidateWebGPU, NonVulkanKHRMemoryModelBad) {
std::string spirv = R"(
OpCapability Shader
diff --git a/tools/as/as.cpp b/tools/as/as.cpp
index acef5b4..f6e9629 100644
--- a/tools/as/as.cpp
+++ b/tools/as/as.cpp
@@ -48,7 +48,7 @@
argv0, argv0, target_env_list.c_str());
}
-static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_4;
+static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
int main(int argc, char** argv) {
const char* inFile = nullptr;
diff --git a/tools/cfg/cfg.cpp b/tools/cfg/cfg.cpp
index 411ef88..ce7f1c2 100644
--- a/tools/cfg/cfg.cpp
+++ b/tools/cfg/cfg.cpp
@@ -44,7 +44,7 @@
argv0, argv0);
}
-static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_4;
+static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
int main(int argc, char** argv) {
const char* inFile = nullptr;
diff --git a/tools/dis/dis.cpp b/tools/dis/dis.cpp
index 2a6f411..c0ce267 100644
--- a/tools/dis/dis.cpp
+++ b/tools/dis/dis.cpp
@@ -60,7 +60,7 @@
argv0, argv0);
}
-static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_4;
+static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
int main(int argc, char** argv) {
const char* inFile = nullptr;
diff --git a/tools/fuzz/fuzz.cpp b/tools/fuzz/fuzz.cpp
index 24e4ac6..5d582f5 100644
--- a/tools/fuzz/fuzz.cpp
+++ b/tools/fuzz/fuzz.cpp
@@ -20,6 +20,7 @@
#include <sstream>
#include <string>
+#include "source/fuzz/force_render_red.h"
#include "source/fuzz/fuzzer.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/replayer.h"
@@ -54,6 +55,8 @@
// Status and actions to perform after parsing command-line arguments.
enum class FuzzActions {
+ FORCE_RENDER_RED, // Turn the shader into a form such that it is guaranteed
+ // to render a red image.
FUZZ, // Run the fuzzer to apply transformations in a randomized fashion.
REPLAY, // Replay an existing sequence of transformations.
SHRINK, // Shrink an existing sequence of transformations with respect to an
@@ -72,43 +75,66 @@
R"(%s - Fuzzes an equivalent SPIR-V binary based on a given binary.
USAGE: %s [options] <input.spv> -o <output.spv>
+USAGE: %s [options] <input.spv> -o <output.spv> \
+ --shrink=<input.transformations> -- <interestingness_test> [args...]
-The SPIR-V binary is read from <input.spv>, which must have extension .spv. If
-<input.facts> is also present, facts about the SPIR-V binary are read from this
-file.
+The SPIR-V binary is read from <input.spv>. If <input.facts> is also present,
+facts about the SPIR-V binary are read from this file.
The transformed SPIR-V binary is written to <output.spv>. Human-readable and
binary representations of the transformations that were applied are written to
<output.transformations_json> and <output.transformations>, respectively.
+When passing --shrink=<input.transformations> an <interestingness_test>
+must also be provided; this is the path to a script that returns 0 if and only
+if a given SPIR-V binary is interesting. The SPIR-V binary will be passed to
+the script as an argument after any other provided arguments [args...]. The
+"--" characters are optional but denote that all arguments that follow are
+positional arguments and thus will be forwarded to the interestingness script,
+and not parsed by %s.
+
NOTE: The fuzzer is a work in progress.
Options (in lexicographical order):
-h, --help
Print this help.
+ --force-render-red
+ Transforms the input shader into a shader that writes red to the
+ output buffer, and then captures the original shader as the body
+ of a conditional with a dynamically false guard. Exploits input
+ facts to make the guard non-obviously false. This option is a
+ helper for massaging crash-inducing tests into a runnable
+ format; it does not perform any fuzzing.
--replay
File from which to read a sequence of transformations to replay
(instead of fuzzing)
- --seed
+ --seed=
Unsigned 32-bit integer seed to control random number
generation.
- --shrink
+ --shrink=
File from which to read a sequence of transformations to shrink
(instead of fuzzing)
- --shrinker-step-limit
+ --shrinker-step-limit=
Unsigned 32-bit integer specifying maximum number of steps the
shrinker will take before giving up. Ignored unless --shrink
is used.
- --interestingness
- Path to an interestingness function to guide shrinking: a script
- that returns 0 if and only if a given binary is interesting.
- Required if --shrink is provided; disallowed otherwise.
+ --shrinker-temp-file-prefix=
+ Specifies a temporary file prefix that will be used to output
+ temporary shader files during shrinking. A number and .spv
+ extension will be added. The default is "temp_", which will
+ cause files like "temp_0001.spv" to be output to the current
+ directory. Ignored unless --shrink is used.
+ --replay-validation
+ Run the validator after applying each transformation during
+ replay (including the replay that occurs during shrinking).
+ Aborts if an invalid binary is created. Useful for debugging
+ spirv-fuzz.
--version
Display fuzzer version information.
)",
- program, program);
+ program, program, program, program);
}
// Message consumer for this tool. Used to emit diagnostics during
@@ -122,24 +148,20 @@
fprintf(stderr, "%s\n", message);
}
-bool EndsWithSpv(const std::string& filename) {
- std::string dot_spv = ".spv";
- return filename.length() >= dot_spv.length() &&
- 0 == filename.compare(filename.length() - dot_spv.length(),
- filename.length(), dot_spv);
-}
-
FuzzStatus ParseFlags(int argc, const char** argv, std::string* in_binary_file,
std::string* out_binary_file,
std::string* replay_transformations_file,
- std::string* interestingness_function_file,
+ std::vector<std::string>* interestingness_test,
std::string* shrink_transformations_file,
+ std::string* shrink_temp_file_prefix,
spvtools::FuzzerOptions* fuzzer_options) {
uint32_t positional_arg_index = 0;
+ bool only_positional_arguments_remain = false;
+ bool force_render_red = false;
for (int argi = 1; argi < argc; ++argi) {
const char* cur_arg = argv[argi];
- if ('-' == cur_arg[0]) {
+ if ('-' == cur_arg[0] && !only_positional_arguments_remain) {
if (0 == strcmp(cur_arg, "--version")) {
spvtools::Logf(FuzzDiagnostic, SPV_MSG_INFO, nullptr, {}, "%s\n",
spvSoftwareVersionDetailsString());
@@ -154,13 +176,15 @@
PrintUsage(argv[0]);
return {FuzzActions::STOP, 1};
}
+ } else if (0 == strncmp(cur_arg, "--force-render-red",
+ sizeof("--force-render-red") - 1)) {
+ force_render_red = true;
} else if (0 == strncmp(cur_arg, "--replay=", sizeof("--replay=") - 1)) {
const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
*replay_transformations_file = std::string(split_flag.second);
- } else if (0 == strncmp(cur_arg, "--interestingness=",
- sizeof("--interestingness=") - 1)) {
- const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
- *interestingness_function_file = std::string(split_flag.second);
+ } else if (0 == strncmp(cur_arg, "--replay-validation",
+ sizeof("--replay-validation") - 1)) {
+ fuzzer_options->enable_replay_validation();
} else if (0 == strncmp(cur_arg, "--shrink=", sizeof("--shrink=") - 1)) {
const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
*shrink_transformations_file = std::string(split_flag.second);
@@ -181,11 +205,18 @@
static_cast<uint32_t>(strtol(split_flag.second.c_str(), &end, 10));
assert(end != split_flag.second.c_str() && errno == 0);
fuzzer_options->set_shrinker_step_limit(step_limit);
- } else if ('\0' == cur_arg[1]) {
- // We do not support fuzzing from standard input. We could support
- // this if there was a compelling use case.
+ } else if (0 == strncmp(cur_arg, "--shrinker-temp-file-prefix=",
+ sizeof("--shrinker-temp-file-prefix=") - 1)) {
+ const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
+ *shrink_temp_file_prefix = std::string(split_flag.second);
+ } else if (0 == strcmp(cur_arg, "--")) {
+ only_positional_arguments_remain = true;
+ } else {
+ std::stringstream ss;
+ ss << "Unrecognized argument: " << cur_arg << std::endl;
+ spvtools::Error(FuzzDiagnostic, nullptr, {}, ss.str().c_str());
PrintUsage(argv[0]);
- return {FuzzActions::STOP, 0};
+ return {FuzzActions::STOP, 1};
}
} else if (positional_arg_index == 0) {
// Binary input file name
@@ -193,9 +224,7 @@
*in_binary_file = std::string(cur_arg);
positional_arg_index++;
} else {
- spvtools::Error(FuzzDiagnostic, nullptr, {},
- "Too many positional arguments specified");
- return {FuzzActions::STOP, 1};
+ interestingness_test->push_back(std::string(cur_arg));
}
}
@@ -204,20 +233,47 @@
return {FuzzActions::STOP, 1};
}
- if (!EndsWithSpv(*in_binary_file)) {
- spvtools::Error(FuzzDiagnostic, nullptr, {},
- "Input filename must have extension .spv");
- return {FuzzActions::STOP, 1};
- }
-
if (out_binary_file->empty()) {
spvtools::Error(FuzzDiagnostic, nullptr, {}, "-o required");
return {FuzzActions::STOP, 1};
}
- if (!EndsWithSpv(*out_binary_file)) {
+ auto const_fuzzer_options =
+ static_cast<spv_const_fuzzer_options>(*fuzzer_options);
+ if (force_render_red) {
+ if (!replay_transformations_file->empty() ||
+ !shrink_transformations_file->empty() ||
+ const_fuzzer_options->replay_validation_enabled) {
+ spvtools::Error(FuzzDiagnostic, nullptr, {},
+ "The --force-render-red argument cannot be used with any "
+ "other arguments except -o.");
+ return {FuzzActions::STOP, 1};
+ }
+ return {FuzzActions::FORCE_RENDER_RED, 0};
+ }
+
+ if (replay_transformations_file->empty() &&
+ shrink_transformations_file->empty() &&
+ static_cast<spv_const_fuzzer_options>(*fuzzer_options)
+ ->replay_validation_enabled) {
spvtools::Error(FuzzDiagnostic, nullptr, {},
- "Output filename must have extension .spv");
+ "The --replay-validation argument can only be used with "
+ "one of the --replay or --shrink arguments.");
+ return {FuzzActions::STOP, 1};
+ }
+
+ if (shrink_transformations_file->empty() && !interestingness_test->empty()) {
+ spvtools::Error(FuzzDiagnostic, nullptr, {},
+ "Too many positional arguments specified; extra positional "
+ "arguments are used as the interestingness function, which "
+ "are only valid with the --shrink option.");
+ return {FuzzActions::STOP, 1};
+ }
+
+ if (!shrink_transformations_file->empty() && interestingness_test->empty()) {
+ spvtools::Error(
+ FuzzDiagnostic, nullptr, {},
+ "The --shrink option requires an interestingness function.");
return {FuzzActions::STOP, 1};
}
@@ -230,28 +286,14 @@
"The --replay and --shrink arguments are mutually exclusive.");
return {FuzzActions::STOP, 1};
}
- if (!interestingness_function_file->empty()) {
- spvtools::Error(FuzzDiagnostic, nullptr, {},
- "The --replay and --interestingness arguments are "
- "mutually exclusive.");
- return {FuzzActions::STOP, 1};
- }
return {FuzzActions::REPLAY, 0};
}
- if (!shrink_transformations_file->empty() ^
- !interestingness_function_file->empty()) {
- spvtools::Error(FuzzDiagnostic, nullptr, {},
- "Both or neither of the --shrink and --interestingness "
- "arguments must be provided.");
- return {FuzzActions::STOP, 1};
- }
-
if (!shrink_transformations_file->empty()) {
// The tool is being invoked in shrink mode.
- assert(!interestingness_function_file->empty() &&
- "An error should have been raised if --shrink but not --interesting "
- "was provided.");
+ assert(!interestingness_test->empty() &&
+ "An error should have been raised if --shrink was provided without "
+ "an interestingness test.");
return {FuzzActions::SHRINK, 0};
}
@@ -278,6 +320,7 @@
}
bool Replay(const spv_target_env& target_env,
+ spv_const_fuzzer_options fuzzer_options,
const std::vector<uint32_t>& binary_in,
const spvtools::fuzz::protobufs::FactSequence& initial_facts,
const std::string& replay_transformations_file,
@@ -289,7 +332,8 @@
&transformation_sequence)) {
return false;
}
- spvtools::fuzz::Replayer replayer(target_env);
+ spvtools::fuzz::Replayer replayer(target_env,
+ fuzzer_options->replay_validation_enabled);
replayer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
auto replay_result_status =
replayer.Run(binary_in, initial_facts, transformation_sequence,
@@ -303,7 +347,8 @@
const std::vector<uint32_t>& binary_in,
const spvtools::fuzz::protobufs::FactSequence& initial_facts,
const std::string& shrink_transformations_file,
- const std::string& interestingness_function_file,
+ const std::string& shrink_temp_file_prefix,
+ const std::vector<std::string>& interestingness_command,
std::vector<uint32_t>* binary_out,
spvtools::fuzz::protobufs::TransformationSequence*
transformations_applied) {
@@ -313,18 +358,28 @@
return false;
}
spvtools::fuzz::Shrinker shrinker(target_env,
- fuzzer_options->shrinker_step_limit);
+ fuzzer_options->shrinker_step_limit,
+ fuzzer_options->replay_validation_enabled);
shrinker.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
+ assert(!interestingness_command.empty() &&
+ "An error should have been raised because the interestingness_command "
+ "is empty.");
+ std::stringstream joined;
+ joined << interestingness_command[0];
+ for (size_t i = 1, size = interestingness_command.size(); i < size; ++i) {
+ joined << " " << interestingness_command[i];
+ }
+ std::string interestingness_command_joined = joined.str();
+
spvtools::fuzz::Shrinker::InterestingnessFunction interestingness_function =
- [interestingness_function_file](std::vector<uint32_t> binary,
- uint32_t reductions_applied) -> bool {
+ [interestingness_command_joined, shrink_temp_file_prefix](
+ std::vector<uint32_t> binary, uint32_t reductions_applied) -> bool {
std::stringstream ss;
- ss << "temp_" << std::setw(4) << std::setfill('0') << reductions_applied
- << ".spv";
+ ss << shrink_temp_file_prefix << std::setw(4) << std::setfill('0')
+ << reductions_applied << ".spv";
const auto spv_file = ss.str();
- const std::string command =
- std::string(interestingness_function_file) + " " + spv_file;
+ const std::string command = interestingness_command_joined + " " + spv_file;
auto write_file_succeeded =
WriteFile(spv_file.c_str(), "wb", &binary[0], binary.size());
(void)(write_file_succeeded);
@@ -362,21 +417,39 @@
} // namespace
+// Dumps |binary| to file |filename|. Useful for interactive debugging.
+void DumpShader(const std::vector<uint32_t>& binary, const char* filename) {
+ auto write_file_succeeded =
+ WriteFile(filename, "wb", &binary[0], binary.size());
+ if (!write_file_succeeded) {
+ std::cerr << "Failed to dump shader" << std::endl;
+ }
+}
+
+// Dumps the SPIRV-V module in |context| to file |filename|. Useful for
+// interactive debugging.
+void DumpShader(spvtools::opt::IRContext* context, const char* filename) {
+ std::vector<uint32_t> binary;
+ context->module()->ToBinary(&binary, false);
+ DumpShader(binary, filename);
+}
+
const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_3;
int main(int argc, const char** argv) {
std::string in_binary_file;
std::string out_binary_file;
std::string replay_transformations_file;
- std::string interestingness_function_file;
+ std::vector<std::string> interestingness_test;
std::string shrink_transformations_file;
+ std::string shrink_temp_file_prefix = "temp_";
spvtools::FuzzerOptions fuzzer_options;
- FuzzStatus status =
- ParseFlags(argc, argv, &in_binary_file, &out_binary_file,
- &replay_transformations_file, &interestingness_function_file,
- &shrink_transformations_file, &fuzzer_options);
+ FuzzStatus status = ParseFlags(
+ argc, argv, &in_binary_file, &out_binary_file,
+ &replay_transformations_file, &interestingness_test,
+ &shrink_transformations_file, &shrink_temp_file_prefix, &fuzzer_options);
if (status.action == FuzzActions::STOP) {
return status.code;
@@ -388,10 +461,12 @@
}
spvtools::fuzz::protobufs::FactSequence initial_facts;
- const std::string dot_spv(".spv");
- std::string in_facts_file =
- in_binary_file.substr(0, in_binary_file.length() - dot_spv.length()) +
- ".facts";
+
+ // If not found, dot_pos will be std::string::npos, which can be used in
+ // substr to mean "the end of the string"; there is no need to check the
+ // result.
+ size_t dot_pos = in_binary_file.rfind('.');
+ std::string in_facts_file = in_binary_file.substr(0, dot_pos) + ".facts";
std::ifstream facts_input(in_facts_file);
if (facts_input) {
std::string facts_json_string((std::istreambuf_iterator<char>(facts_input)),
@@ -411,6 +486,12 @@
spv_target_env target_env = kDefaultEnvironment;
switch (status.action) {
+ case FuzzActions::FORCE_RENDER_RED:
+ if (!spvtools::fuzz::ForceRenderRed(target_env, binary_in, initial_facts,
+ &binary_out)) {
+ return 1;
+ }
+ break;
case FuzzActions::FUZZ:
if (!Fuzz(target_env, fuzzer_options, binary_in, initial_facts,
&binary_out, &transformations_applied)) {
@@ -418,7 +499,7 @@
}
break;
case FuzzActions::REPLAY:
- if (!Replay(target_env, binary_in, initial_facts,
+ if (!Replay(target_env, fuzzer_options, binary_in, initial_facts,
replay_transformations_file, &binary_out,
&transformations_applied)) {
return 1;
@@ -431,8 +512,9 @@
return 1;
}
if (!Shrink(target_env, fuzzer_options, binary_in, initial_facts,
- shrink_transformations_file, interestingness_function_file,
- &binary_out, &transformations_applied)) {
+ shrink_transformations_file, shrink_temp_file_prefix,
+ interestingness_test, &binary_out,
+ &transformations_applied)) {
return 1;
}
} break;
@@ -447,35 +529,40 @@
return 1;
}
- std::string output_file_prefix =
- out_binary_file.substr(0, out_binary_file.length() - dot_spv.length());
- std::ofstream transformations_file;
- transformations_file.open(output_file_prefix + ".transformations",
- std::ios::out | std::ios::binary);
- bool success =
- transformations_applied.SerializeToOstream(&transformations_file);
- transformations_file.close();
- if (!success) {
- spvtools::Error(FuzzDiagnostic, nullptr, {},
- "Error writing out transformations binary");
- return 1;
- }
+ if (status.action != FuzzActions::FORCE_RENDER_RED) {
+ // If not found, dot_pos will be std::string::npos, which can be used in
+ // substr to mean "the end of the string"; there is no need to check the
+ // result.
+ dot_pos = out_binary_file.rfind('.');
+ std::string output_file_prefix = out_binary_file.substr(0, dot_pos);
+ std::ofstream transformations_file;
+ transformations_file.open(output_file_prefix + ".transformations",
+ std::ios::out | std::ios::binary);
+ bool success =
+ transformations_applied.SerializeToOstream(&transformations_file);
+ transformations_file.close();
+ if (!success) {
+ spvtools::Error(FuzzDiagnostic, nullptr, {},
+ "Error writing out transformations binary");
+ return 1;
+ }
- std::string json_string;
- auto json_options = google::protobuf::util::JsonOptions();
- json_options.add_whitespace = true;
- auto json_generation_status = google::protobuf::util::MessageToJsonString(
- transformations_applied, &json_string, json_options);
- if (json_generation_status != google::protobuf::util::Status::OK) {
- spvtools::Error(FuzzDiagnostic, nullptr, {},
- "Error writing out transformations in JSON format");
- return 1;
- }
+ std::string json_string;
+ auto json_options = google::protobuf::util::JsonOptions();
+ json_options.add_whitespace = true;
+ auto json_generation_status = google::protobuf::util::MessageToJsonString(
+ transformations_applied, &json_string, json_options);
+ if (json_generation_status != google::protobuf::util::Status::OK) {
+ spvtools::Error(FuzzDiagnostic, nullptr, {},
+ "Error writing out transformations in JSON format");
+ return 1;
+ }
- std::ofstream transformations_json_file(output_file_prefix +
- ".transformations_json");
- transformations_json_file << json_string;
- transformations_json_file.close();
+ std::ofstream transformations_json_file(output_file_prefix +
+ ".transformations_json");
+ transformations_json_file << json_string;
+ transformations_json_file.close();
+ }
return 0;
}
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index b229c84..4364e3e 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -59,7 +59,7 @@
return ss.str();
}
-const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_4;
+const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
std::string GetLegalizationPasses() {
spvtools::Optimizer optimizer(kDefaultEnvironment);
@@ -80,13 +80,13 @@
}
std::string GetVulkanToWebGPUPasses() {
- spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0);
+ spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1);
optimizer.RegisterVulkanToWebGPUPasses();
return GetListOfPassesAsString(optimizer);
}
std::string GetWebGPUToVulkanPasses() {
- spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1);
+ spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0);
optimizer.RegisterWebGPUToVulkanPasses();
return GetListOfPassesAsString(optimizer);
}
@@ -141,6 +141,16 @@
and constant index access chains in entry point call tree
functions.)");
printf(R"(
+ --convert-relaxed-to-half
+ Convert all RelaxedPrecision arithmetic operations to half
+ precision, inserting conversion operations where needed.
+ Run after function scope variable load and store elimination
+ for better results. Simplify-instructions, redundancy-elimination
+ and DCE should be run after this pass to eliminate excess
+ conversions. This conversion is useful when the target platform
+ does not support RelaxedPrecision or ignores it. This pass also
+ removes all RelaxedPrecision decorations.)");
+ printf(R"(
--copy-propagate-arrays
Does propagation of memory references when an array is a copy of
another. It will only propagate an array if the source is never
@@ -393,6 +403,10 @@
Looks for instructions in the same function that compute the
same value, and deletes the redundant ones.)");
printf(R"(
+ --relax-float-ops
+ Decorate all float operations with RelaxedPrecision if not already
+ so decorated. This does not decorate types or variables.)");
+ printf(R"(
--relax-struct-store
Allow store from one struct type to a different type with
compatible layout and members. This option is forwarded to the
@@ -512,6 +526,13 @@
avoid triggering those bugs.
Current workarounds: Avoid OpUnreachable in loops.)");
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
+ whose only instruction is an OpKill. This is done to enable
+ inlining on these functions.
+ )");
+ printf(R"(
--unify-const
Remove the duplicated constants.)");
printf(R"(
@@ -778,7 +799,7 @@
return {OPT_STOP, 1};
}
- optimizer->SetTargetEnv(SPV_ENV_WEBGPU_0);
+ optimizer->SetTargetEnv(SPV_ENV_VULKAN_1_1);
optimizer->RegisterVulkanToWebGPUPasses();
} else if (0 == strcmp(cur_arg, "--webgpu-to-vulkan")) {
webgpu_to_vulkan_set = true;
@@ -796,7 +817,7 @@
return {OPT_STOP, 1};
}
- optimizer->SetTargetEnv(SPV_ENV_VULKAN_1_1);
+ optimizer->SetTargetEnv(SPV_ENV_WEBGPU_0);
optimizer->RegisterWebGPUToVulkanPasses();
} else if (0 == strcmp(cur_arg, "--validate-after-all")) {
optimizer->SetValidateAfterAll(true);
diff --git a/tools/reduce/reduce.cpp b/tools/reduce/reduce.cpp
index be07b20..0bdeb82 100644
--- a/tools/reduce/reduce.cpp
+++ b/tools/reduce/reduce.cpp
@@ -58,20 +58,24 @@
// NOTE: Please maintain flags in lexicographical order.
printf(
R"(%s - Reduce a SPIR-V binary file with respect to a user-provided
- interestingness test.
+interestingness test.
-USAGE: %s [options] <input> <interestingness-test>
+USAGE: %s [options] <input.spv> -o <output.spv> -- <interestingness_test> [args...]
-The SPIR-V binary is read from <input>.
+The SPIR-V binary is read from <input.spv>. The reduced SPIR-V binary is
+written to <output.spv>.
-Whether a binary is interesting is determined by <interestingness-test>, which
-should be the path to a script.
+Whether a binary is interesting is determined by <interestingness_test>, which
+should be the path to a script. The "--" characters are optional but denote
+that all arguments that follow are positional arguments and thus will be
+forwarded to the interestingness test, and not parsed by %s.
* The script must be executable.
- * The script should take the path to a SPIR-V binary file (.spv) as its single
+ * The script should take the path to a SPIR-V binary file (.spv) as an
argument, and exit with code 0 if and only if the binary file is
- interesting.
+ interesting. The binary will be passed to the script as an argument after
+ any other provided arguments [args...].
* Example: an interestingness test for reducing a SPIR-V binary file that
causes tool "foo" to exit with error code 1 and print "Fatal error: bar" to
@@ -95,9 +99,15 @@
SPIR-V module that fails to validate.
-h, --help
Print this help.
- --step-limit
+ --step-limit=
32-bit unsigned integer specifying maximum number of steps the
reducer will take before giving up.
+ --temp-file-prefix=
+ Specifies a temporary file prefix that will be used to output
+ temporary shader files during reduction. A number and .spv
+ extension will be added. The default is "temp_", which will
+ cause files like "temp_0001.spv" to be output to the current
+ directory.
--version
Display reducer version information.
@@ -109,7 +119,7 @@
--scalar-block-layout
--skip-block-layout
)",
- program, program);
+ program, program, program);
}
// Message consumer for this tool. Used to emit diagnostics during
@@ -123,15 +133,19 @@
fprintf(stderr, "%s\n", message);
}
-ReduceStatus ParseFlags(int argc, const char** argv, const char** in_file,
- const char** interestingness_test,
+ReduceStatus ParseFlags(int argc, const char** argv,
+ std::string* in_binary_file,
+ std::string* out_binary_file,
+ std::vector<std::string>* interestingness_test,
+ std::string* temp_file_prefix,
spvtools::ReducerOptions* reducer_options,
spvtools::ValidatorOptions* validator_options) {
uint32_t positional_arg_index = 0;
+ bool only_positional_arguments_remain = false;
for (int argi = 1; argi < argc; ++argi) {
const char* cur_arg = argv[argi];
- if ('-' == cur_arg[0]) {
+ if ('-' == cur_arg[0] && !only_positional_arguments_remain) {
if (0 == strcmp(cur_arg, "--version")) {
spvtools::Logf(ReduceDiagnostic, SPV_MSG_INFO, nullptr, {}, "%s\n",
spvSoftwareVersionDetailsString());
@@ -139,11 +153,13 @@
} else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
PrintUsage(argv[0]);
return {REDUCE_STOP, 0};
- } else if ('\0' == cur_arg[1]) {
- // We do not support reduction from standard input. We could support
- // this if there was a compelling use case.
- PrintUsage(argv[0]);
- return {REDUCE_STOP, 0};
+ } else if (0 == strcmp(cur_arg, "-o")) {
+ if (out_binary_file->empty() && argi + 1 < argc) {
+ *out_binary_file = std::string(argv[++argi]);
+ } else {
+ PrintUsage(argv[0]);
+ return {REDUCE_STOP, 1};
+ }
} else if (0 == strncmp(cur_arg,
"--step-limit=", sizeof("--step-limit=") - 1)) {
const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
@@ -153,43 +169,54 @@
static_cast<uint32_t>(strtol(split_flag.second.c_str(), &end, 10));
assert(end != split_flag.second.c_str() && errno == 0);
reducer_options->set_step_limit(step_limit);
+ } else if (0 == strcmp(cur_arg, "--fail-on-validation-error")) {
+ reducer_options->set_fail_on_validation_error(true);
+ } else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) {
+ validator_options->SetBeforeHlslLegalization(true);
+ } else if (0 == strcmp(cur_arg, "--relax-logical-pointer")) {
+ validator_options->SetRelaxLogicalPointer(true);
+ } else if (0 == strcmp(cur_arg, "--relax-block-layout")) {
+ validator_options->SetRelaxBlockLayout(true);
+ } else if (0 == strcmp(cur_arg, "--scalar-block-layout")) {
+ validator_options->SetScalarBlockLayout(true);
+ } else if (0 == strcmp(cur_arg, "--skip-block-layout")) {
+ validator_options->SetSkipBlockLayout(true);
+ } else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
+ validator_options->SetRelaxStructStore(true);
+ } else if (0 == strncmp(cur_arg, "--temp-file-prefix=",
+ sizeof("--temp-file-prefix=") - 1)) {
+ const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
+ *temp_file_prefix = std::string(split_flag.second);
+ } else if (0 == strcmp(cur_arg, "--")) {
+ only_positional_arguments_remain = true;
+ } else {
+ std::stringstream ss;
+ ss << "Unrecognized argument: " << cur_arg << std::endl;
+ spvtools::Error(ReduceDiagnostic, nullptr, {}, ss.str().c_str());
+ PrintUsage(argv[0]);
+ return {REDUCE_STOP, 1};
}
} else if (positional_arg_index == 0) {
- // Input file name
- assert(!*in_file);
- *in_file = cur_arg;
+ // Binary input file name
+ assert(in_binary_file->empty());
+ *in_binary_file = std::string(cur_arg);
positional_arg_index++;
- } else if (positional_arg_index == 1) {
- assert(!*interestingness_test);
- *interestingness_test = cur_arg;
- positional_arg_index++;
- } else if (0 == strcmp(cur_arg, "--fail-on-validation-error")) {
- reducer_options->set_fail_on_validation_error(true);
- } else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) {
- validator_options->SetBeforeHlslLegalization(true);
- } else if (0 == strcmp(cur_arg, "--relax-logical-pointer")) {
- validator_options->SetRelaxLogicalPointer(true);
- } else if (0 == strcmp(cur_arg, "--relax-block-layout")) {
- validator_options->SetRelaxBlockLayout(true);
- } else if (0 == strcmp(cur_arg, "--scalar-block-layout")) {
- validator_options->SetScalarBlockLayout(true);
- } else if (0 == strcmp(cur_arg, "--skip-block-layout")) {
- validator_options->SetSkipBlockLayout(true);
- } else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
- validator_options->SetRelaxStructStore(true);
} else {
- spvtools::Error(ReduceDiagnostic, nullptr, {},
- "Too many positional arguments specified");
- return {REDUCE_STOP, 1};
+ interestingness_test->push_back(std::string(cur_arg));
}
}
- if (!*in_file) {
+ if (in_binary_file->empty()) {
spvtools::Error(ReduceDiagnostic, nullptr, {}, "No input file specified");
return {REDUCE_STOP, 1};
}
- if (!*interestingness_test) {
+ if (out_binary_file->empty()) {
+ spvtools::Error(ReduceDiagnostic, nullptr, {}, "-o required");
+ return {REDUCE_STOP, 1};
+ }
+
+ if (interestingness_test->empty()) {
spvtools::Error(ReduceDiagnostic, nullptr, {},
"No interestingness test specified");
return {REDUCE_STOP, 1};
@@ -217,18 +244,21 @@
DumpShader(binary, filename);
}
-const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_4;
+const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
int main(int argc, const char** argv) {
- const char* in_file = nullptr;
- const char* interestingness_test = nullptr;
+ std::string in_binary_file;
+ std::string out_binary_file;
+ std::vector<std::string> interestingness_test;
+ std::string temp_file_prefix = "temp_";
spv_target_env target_env = kDefaultEnvironment;
spvtools::ReducerOptions reducer_options;
spvtools::ValidatorOptions validator_options;
- ReduceStatus status = ParseFlags(argc, argv, &in_file, &interestingness_test,
- &reducer_options, &validator_options);
+ ReduceStatus status = ParseFlags(
+ argc, argv, &in_binary_file, &out_binary_file, &interestingness_test,
+ &temp_file_prefix, &reducer_options, &validator_options);
if (status.action == REDUCE_STOP) {
return status.code;
@@ -242,15 +272,22 @@
spvtools::reduce::Reducer reducer(target_env);
+ std::stringstream joined;
+ joined << interestingness_test[0];
+ for (size_t i = 1, size = interestingness_test.size(); i < size; ++i) {
+ joined << " " << interestingness_test[i];
+ }
+ std::string interestingness_command_joined = joined.str();
+
reducer.SetInterestingnessFunction(
- [interestingness_test](std::vector<uint32_t> binary,
- uint32_t reductions_applied) -> bool {
+ [interestingness_command_joined, temp_file_prefix](
+ std::vector<uint32_t> binary, uint32_t reductions_applied) -> bool {
std::stringstream ss;
- ss << "temp_" << std::setw(4) << std::setfill('0') << reductions_applied
- << ".spv";
+ ss << temp_file_prefix << std::setw(4) << std::setfill('0')
+ << reductions_applied << ".spv";
const auto spv_file = ss.str();
const std::string command =
- std::string(interestingness_test) + " " + spv_file;
+ interestingness_command_joined + " " + spv_file;
auto write_file_succeeded =
WriteFile(spv_file.c_str(), "wb", &binary[0], binary.size());
(void)(write_file_succeeded);
@@ -263,7 +300,7 @@
reducer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
std::vector<uint32_t> binary_in;
- if (!ReadFile<uint32_t>(in_file, "rb", &binary_in)) {
+ if (!ReadFile<uint32_t>(in_binary_file.c_str(), "rb", &binary_in)) {
return 1;
}
@@ -271,12 +308,20 @@
const auto reduction_status = reducer.Run(std::move(binary_in), &binary_out,
reducer_options, validator_options);
- if (reduction_status == spvtools::reduce::Reducer::ReductionResultStatus::
- kInitialStateNotInteresting ||
- !WriteFile<uint32_t>("_reduced_final.spv", "wb", binary_out.data(),
+ // Always try to write the output file, even if the reduction failed.
+ if (!WriteFile<uint32_t>(out_binary_file.c_str(), "wb", binary_out.data(),
binary_out.size())) {
return 1;
}
- return 0;
+ // These are the only successful statuses.
+ switch (reduction_status) {
+ case spvtools::reduce::Reducer::ReductionResultStatus::kComplete:
+ case spvtools::reduce::Reducer::ReductionResultStatus::kReachedStepLimit:
+ return 0;
+ default:
+ break;
+ }
+
+ return 1;
}
diff --git a/tools/sva/.eslintrc.json b/tools/sva/.eslintrc.json
new file mode 100644
index 0000000..2f07726
--- /dev/null
+++ b/tools/sva/.eslintrc.json
@@ -0,0 +1,25 @@
+{
+ "env": {
+ "browser": true,
+ "es6": true,
+ "node": true,
+ "mocha": true
+ },
+ "extends": "eslint:recommended",
+ "parserOptions": {
+ "ecmaVersion": 2018,
+ "sourceType": "module"
+ },
+ "rules": {
+ "block-scoped-var": "error",
+ "consistent-return": "error",
+ "eqeqeq": ["error", "always"],
+ "indent": [ "error", 2 ],
+ "linebreak-style": [ "error", "unix" ],
+ "no-eval": "error",
+ "no-shadow": "error",
+ "no-shadow-restricted-names": "error",
+ "quotes": [ "error", "double" ],
+ "semi": [ "error", "always" ]
+ }
+}
diff --git a/tools/sva/.gitignore b/tools/sva/.gitignore
new file mode 100644
index 0000000..88e64c3
--- /dev/null
+++ b/tools/sva/.gitignore
@@ -0,0 +1,6 @@
+.DS_Store
+node_modules
+third_party/spirv-headers
+o.sva
+build
+yarn-error.log
diff --git a/tools/sva/README.md b/tools/sva/README.md
new file mode 100644
index 0000000..d80b4d2
--- /dev/null
+++ b/tools/sva/README.md
@@ -0,0 +1,41 @@
+# SVA
+
+SPIR-V Assember for WebGPU. The SPIR-V Assembler is a JavaScript library to
+convert SPIR-V assembly (as produced by spirv-dis in SPIR-V Tools) into a
+SPIR-V binary. The assembler assumes it is generating WebGPU SPIR-V and thus has
+the following limitations.
+
+ * Only 32 bit integers and floats supported
+ * Only GLSL accepted as an extended instruction set
+ * Doesn't support ! syntax for integers
+ * Doesn't support hex encoding for float
+
+```shell
+yarn install
+yarn test
+```
+
+You can also use `yarn watch` to watch all of the files and re-run tests as
+needed.
+
+## Webserver
+Using `yarn serve` will start a webserver on localhost:5000. If you load the
+`tests/index.html` file this will load the SVA files into browser.
+
+## Command Line
+There is a simple assembler binary with can be executed from the command line.
+
+```shell
+yarn sva tests/simple.spv_asm
+```
+
+The above will generate a `o.sva` file in the current directory.
+
+## Update spirv.data.json
+
+If there is a new spirv-headers release update the externals folder checkout
+and then:
+
+```shell
+./tools/process_grammar.rb > src/spirv.data.json
+```
diff --git a/tools/sva/bin/sva.js b/tools/sva/bin/sva.js
new file mode 100755
index 0000000..e2448d6
--- /dev/null
+++ b/tools/sva/bin/sva.js
@@ -0,0 +1,32 @@
+#!/usr/bin/env node
+//
+// Copyright 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.
+
+"use strict";
+
+const fs = require("fs");
+
+import SVA from "../src/sva.js";
+
+let input = fs.readFileSync(process.argv[2], "utf-8");
+let u = SVA.assemble(input);
+
+if (typeof u === "string") {
+ console.log(u);
+} else {
+ fs.writeFileSync("o.sva", new Buffer(u.buffer), (err) => {
+ console.log(["ERROR", err]);
+ });
+}
diff --git a/tools/sva/mocha.opts b/tools/sva/mocha.opts
new file mode 100644
index 0000000..4a52320
--- /dev/null
+++ b/tools/sva/mocha.opts
@@ -0,0 +1 @@
+--recursive
diff --git a/tools/sva/package.json b/tools/sva/package.json
new file mode 100644
index 0000000..3072d4c
--- /dev/null
+++ b/tools/sva/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "sva",
+ "version": "0.1.0",
+ "description": "SPIR-V Assembler",
+ "main": "index.js",
+ "author": "dan sinclair <dsinclair@google.com>",
+ "license": "Apache-2.0",
+ "private": true,
+ "scripts": {
+ "sva": "node -r esm bin/sva.js",
+ "lint": "eslint --fix --ext .js .",
+ "test": "mocha --require esm src/**/*_test.js",
+ "watch": "mocha --require esm --watch --watch-extension js \"src/**/*_test.js\"",
+ "serve": "serve",
+ "bundle": "rollup -c"
+ },
+ "devDependencies": {
+ "chai": "^4.2.0",
+ "eslint": "^6.3.0",
+ "esm": "^3.2.25",
+ "mocha": "^6.2.0",
+ "rollup": "^1.21.4",
+ "serve": "^11.1.0"
+ }
+}
diff --git a/tools/sva/rollup.config.js b/tools/sva/rollup.config.js
new file mode 100644
index 0000000..2056e16
--- /dev/null
+++ b/tools/sva/rollup.config.js
@@ -0,0 +1,7 @@
+export default {
+ input: 'src/sva.js',
+ output: {
+ file: 'build/sva.js',
+ format: 'esm',
+ }
+}
diff --git a/tools/sva/src/assembler.js b/tools/sva/src/assembler.js
new file mode 100644
index 0000000..7bc208e
--- /dev/null
+++ b/tools/sva/src/assembler.js
@@ -0,0 +1,98 @@
+// Copyright 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.
+
+export default class Assembler {
+ static get GENERATOR_ID() { return 0; }
+
+ /**
+ * @param {AST} the AST to build the SPIR-V from
+ */
+ constructor(ast) {
+ this.ast_ = ast;
+ }
+
+ /**
+ * Assembles the AST into binary SPIR-V.
+ * @return {Uint32Array} The SPIR-V binary data.
+ */
+ assemble() {
+ let total_size = 5;
+ for (const inst of this.ast_.instructions()) {
+ total_size += 1;
+ for (const op of inst.operands()) {
+ total_size += op.length();
+ }
+ }
+
+ let u = new Uint32Array(total_size);
+ u[0] = 0x07230203; // Magic
+ u[1] = 0x00010500; // Version 1.5
+ u[2] = Assembler.GENERATOR_ID; // Generator magic number
+ u[3] = this.ast_.getIdBounds(); // ID bounds
+ u[4] = 0; // Reserved
+
+ let idx = 5;
+ for (const inst of this.ast_.instructions()) {
+ let op_size = 1;
+ for (const op of inst.operands()) {
+ op_size += op.length();
+ }
+
+ u[idx++] = op_size << 16 | inst.opcode();
+ for (const op of inst.operands()) {
+ idx = this.processOp(u, idx, op);
+ }
+ }
+
+ return u;
+ }
+
+ processOp(u, idx, op) {
+ if (op.type() === "string") {
+ let len = 0;
+ let v = 0;
+ for (const ch of op.value()) {
+ v = v | (ch.charCodeAt(0) << (len * 8));
+ len += 1;
+
+ if (len === 4) {
+ u[idx++] = v;
+ len = 0;
+ v = 0;
+ }
+ }
+ // Make sure either the terminating 0 byte is written or the last
+ // partial word is written.
+ u[idx++] = v;
+
+ } else if (op.type() === "float") {
+ // TODO(dsinclair): Handle 64 bit floats ...
+ let b = new ArrayBuffer(4);
+ let f = new Float32Array(b);
+ f[0] = op.value();
+
+ let u2 = new Uint32Array(b);
+
+ u[idx++] = u2[0];
+ } else {
+ u[idx++] = op.value();
+ }
+
+ for (const param of op.params()) {
+ idx = this.processOp(u, idx, param);
+ }
+
+ return idx;
+ }
+}
diff --git a/tools/sva/src/assembler_test.js b/tools/sva/src/assembler_test.js
new file mode 100644
index 0000000..a23d211
--- /dev/null
+++ b/tools/sva/src/assembler_test.js
@@ -0,0 +1,165 @@
+// Copyright 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.
+
+import { assert } from "chai";
+import Lexer from "./lexer";
+import Parser from "./parser";
+import grammar from "./spirv.data.js";
+import Assembler from "./assembler";
+
+describe("assembler", () => {
+ it("generates SPIR-V magic number", () => {
+ let input = `; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 6
+; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 440
+ OpName %main "main"
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd`;
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+
+ let a = new Assembler(ast);
+ let res = a.assemble();
+ assert.equal(res[0], 0x07230203);
+ });
+
+ it("assembles enumerant params", () => {
+ let input = "OpExecutionMode %main LocalSize 2 3 4";
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+
+ let a = new Assembler(ast);
+ let res = a.assemble();
+
+ assert.lengthOf(res, 11);
+ assert.equal(res[5], (6 /* word count */ << 16) | 16 /* opcode */);
+ assert.equal(res[6], 1 /* %main */);
+ assert.equal(res[7], 17 /* LocalSize */);
+ assert.equal(res[8], 2);
+ assert.equal(res[9], 3);
+ assert.equal(res[10], 4);
+ });
+
+ it("assembles float 32 values", () => {
+ let input = `%float = OpTypeFloat 32
+ %float1 = OpConstant %float 0.400000006`;
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+
+ let a = new Assembler(ast);
+ let res = a.assemble();
+
+ assert.lengthOf(res, 12);
+ assert.equal(res[8], (4 /* word count */ << 16) | 43 /* opcode */);
+ assert.equal(res[9], 1 /* %float */);
+ assert.equal(res[10], 2 /* %float */);
+ assert.equal(res[11], 0x3ecccccd /* 0.400000006 */);
+ });
+
+ describe("strings", () => {
+ it("assembles 'abcd'", () => {
+ let input = `OpName %mains "abcd"`;
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+
+ let a = new Assembler(ast);
+ let res = a.assemble();
+
+ assert.lengthOf(res, 9);
+ assert.equal(res[5], (4 /* word count */ << 16) | 5 /* opcode */);
+ assert.equal(res[6], 1 /* %mains */);
+ assert.equal(res[7], 0x64636261 /* food */);
+ assert.equal(res[8], 0x00000000 /* null byte */);
+ });
+
+ it("assembles 'abcde'", () => {
+ let input = `OpName %mains "abcde"`;
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+
+ let a = new Assembler(ast);
+ let res = a.assemble();
+
+ assert.lengthOf(res, 9);
+ assert.equal(res[5], (4 /* word count */ << 16) | 5 /* opcode */);
+ assert.equal(res[6], 1 /* %mains */);
+ assert.equal(res[7], 0x64636261 /* abcd */);
+ assert.equal(res[8], 0x00000065 /* e */);
+ });
+
+ it("assembles 'abcdef'", () => {
+ let input = `OpName %mains "abcdef"`;
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+
+ let a = new Assembler(ast);
+ let res = a.assemble();
+
+ assert.lengthOf(res, 9);
+ assert.equal(res[5], (4 /* word count */ << 16) | 5 /* opcode */);
+ assert.equal(res[6], 1 /* %mains */);
+ assert.equal(res[7], 0x64636261 /* abcd */);
+ assert.equal(res[8], 0x00006665 /* ef */);
+ });
+
+ it("assembles 'abcdefg'", () => {
+ let input = `OpName %mains "abcdefg"`;
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+
+ let a = new Assembler(ast);
+ let res = a.assemble();
+
+ assert.lengthOf(res, 9);
+ assert.equal(res[5], (4 /* word count */ << 16) | 5 /* opcode */);
+ assert.equal(res[6], 1 /* %mains */);
+ assert.equal(res[7], 0x64636261 /* abcd */);
+ assert.equal(res[8], 0x00676665 /* efg */);
+ });
+ });
+});
diff --git a/tools/sva/src/ast.js b/tools/sva/src/ast.js
new file mode 100644
index 0000000..d396d2f
--- /dev/null
+++ b/tools/sva/src/ast.js
@@ -0,0 +1,141 @@
+// Copyright 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.
+
+class Module {
+ constructor() {
+ this.instructions_ = [];
+ this.next_id_ = 1;
+
+ /**
+ * Maps {string, hash} where the string is the type name and the hash is:
+ * type- 'float' or 'int'
+ * width- number of bits needed to store number
+ * signed- the sign of the number
+ */
+ this.types_ = {};
+
+ /**
+ * Maps {string, number} where the string is the type name and the number is
+ * the id value.
+ */
+ this.assigned_ids_ = {};
+ }
+
+ instructions() { return this.instructions_; }
+
+ instruction(val) { return this.instructions_[val]; }
+
+ addInstruction(inst) {
+ this.instructions_.push(inst);
+
+ // Record type information
+ if (inst.name() === "OpTypeInt" || inst.name() === "OpTypeFloat") {
+ let is_int = inst.name() === "OpTypeInt";
+
+ this.types_[inst.operand(0).name()] = {
+ type: is_int ? "int" : "float",
+ width: inst.operand(1).value(),
+ signed: is_int ? inst.operand(2).value() : 1
+ };
+ }
+
+ // Record operand result id's
+ inst.operands().forEach((op) => {
+ if (op.rawValue() !== undefined && op.type() === "result_id") {
+ this.next_id_ = Math.max(this.next_id_, op.rawValue() + 1);
+ }
+ });
+ }
+
+ getType(name) { return this.types_[name]; }
+
+ getId(name) {
+ if (this.assigned_ids_[name] !== undefined) {
+ return this.assigned_ids_[name];
+ }
+
+ let next = this.next_id_;
+ this.assigned_ids_[name] = next;
+
+ this.next_id_ += 1;
+ return next;
+ }
+
+ getIdBounds() { return this.next_id_; }
+}
+
+class Instruction {
+ constructor(name, opcode, operands) {
+ this.name_ = name;
+ this.opcode_ = opcode;
+ this.operands_ = operands;
+ }
+
+ name() { return this.name_; }
+
+ opcode() { return this.opcode_; }
+
+ operands() { return this.operands_; }
+
+ operand(val) { return this.operands_[val]; }
+}
+
+class Operand {
+ constructor(mod, name, type, value, params) {
+ this.module_ = mod;
+ this.name_ = name;
+ this.type_ = type;
+ this.value_ = value;
+ this.params_ = params;
+ }
+
+ name() { return this.name_; }
+
+ length() {
+ // Get the value just to force it to be filled.
+ this.value();
+
+ if (this.type_ === "string") {
+ return Math.ceil((this.value_.length + 1) / 4);
+ }
+
+ let size = 1;
+ for (const param of this.params_) {
+ size += param.length();
+ }
+ return size;
+ }
+
+ type() { return this.type_; }
+
+ rawValue() { return this.value_; }
+
+ // This method should only be called on ResultId's after the full parse is
+ // complete. This is because the AST will only have the maximum seen numeric
+ // ResultId when the parse is done.
+ value() {
+ if (this.value_ === undefined) {
+ this.value_ = this.module_.getId(this.name_);
+ }
+ return this.value_;
+ }
+
+ params() { return this.params_; }
+}
+
+export {
+ Module,
+ Instruction,
+ Operand
+};
diff --git a/tools/sva/src/lexer.js b/tools/sva/src/lexer.js
new file mode 100644
index 0000000..b39f93a
--- /dev/null
+++ b/tools/sva/src/lexer.js
@@ -0,0 +1,363 @@
+// Copyright 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.
+
+import { Token, TokenType } from "./token.js";
+
+export default class Lexer {
+ /**
+ * @param {String} input The input string to tokenize.
+ */
+ constructor(input) {
+ this.input_ = input;
+ this.len_ = input.length;
+ this.cur_pos_ = 0;
+ this.cur_line_ = 1;
+
+ this.num_regex_ = /^[0-9]+$/;
+ this.alpha_regex_ = /^[a-zA-Z_]+$/;
+ this.op_regex_ = /^Op[A-Z][^\s]*$/;
+ this.hex_regex_ = /^[0-9a-fA-F]$/;
+ }
+
+ /**
+ * Parses the next token from the input stream.
+ * @return {Token} the next token.
+ */
+ next() {
+ this.skipWhitespace();
+ this.skipComments();
+
+ if (this.cur_pos_ >= this.len_)
+ return new Token(TokenType.kEOF, this.cur_line_);
+
+ let n = this.tryHexInteger();
+ if (n !== undefined)
+ return n;
+
+ n = this.tryFloat();
+ if (n !== undefined)
+ return n;
+
+ n = this.tryInteger();
+ if (n !== undefined)
+ return n;
+
+ n = this.tryString();
+ if (n !== undefined)
+ return n;
+
+ n = this.tryOp();
+ if (n !== undefined)
+ return n;
+
+ n = this.tryPunctuation();
+ if (n !== undefined)
+ return n;
+
+ n = this.tryResultId();
+ if (n !== undefined)
+ return n;
+
+ n = this.tryIdent();
+ if (n !== undefined)
+ return n;
+
+ return new Token(TokenType.kError, this.cur_line_, "Failed to match token");
+ }
+
+ is(str) {
+ if (this.len_ <= this.cur_pos_ + (str.length - 1))
+ return false;
+
+ for (let i = 0; i < str.length; ++i) {
+ if (this.input_[this.cur_pos_ + i] !== str[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ isNum(ch) {
+ return ch.match(this.num_regex_);
+ }
+
+ isAlpha(ch) {
+ return ch.match(this.alpha_regex_);
+ }
+
+ isAlphaNum(ch) {
+ return this.isNum(ch) || this.isAlpha(ch);
+ }
+
+ isHex(char) {
+ return char.match(this.hex_regex_);
+ }
+
+ isCurWhitespace() {
+ return this.is(" ") || this.is("\t") || this.is("\r") || this.is("\n");
+ }
+
+ skipWhitespace() {
+ for(;;) {
+ let cur_pos = this.cur_pos_;
+ while (this.cur_pos_ < this.len_ &&
+ this.isCurWhitespace()) {
+ if (this.is("\n"))
+ this.cur_line_ += 1;
+
+ this.cur_pos_ += 1;
+ }
+
+ this.skipComments();
+
+ // Cursor didn't move so no whitespace matched.
+ if (cur_pos === this.cur_pos_)
+ break;
+ }
+ }
+
+ skipComments() {
+ if (!this.is(";"))
+ return;
+
+ while (this.cur_pos_ < this.len_ && !this.is("\n"))
+ this.cur_pos_ += 1;
+ }
+
+ /**
+ * Attempt to parse the next part of the input as a float.
+ * @return {Token|undefined} returns a Token if a float is matched,
+ * undefined otherwise.
+ */
+ tryFloat() {
+ let start = this.cur_pos_;
+ let end = start;
+
+ if (this.cur_pos_ >= this.len_)
+ return undefined;
+ if (this.input_[end] === "-")
+ end += 1;
+
+ while (end < this.len_ && this.isNum(this.input_[end]))
+ end += 1;
+
+ // Must have a "." in a float
+ if (end >= this.len_ || this.input_[end] !== ".")
+ return undefined;
+
+ end += 1;
+ while (end < this.len_ && this.isNum(this.input_[end]))
+ end += 1;
+
+ let substr = this.input_.substr(start, end - start);
+ if (substr === "." || substr === "-.")
+ return undefined;
+
+ this.cur_pos_ = end;
+
+ return new Token(TokenType.kFloatLiteral, this.cur_line_, parseFloat(substr));
+ }
+
+ /**
+ * Attempt to parse a hex encoded integer.
+ * @return {Token|undefined} returns a Token if a Hex number is matched,
+ * undefined otherwise.
+ */
+ tryHexInteger() {
+ let start = this.cur_pos_;
+ let end = start;
+
+ if (this.cur_pos_ >= this.len_)
+ return undefined;
+ if (end + 2 >= this.len_ || this.input_[end] !== "0" ||
+ this.input_[end + 1] !== "x") {
+ return undefined;
+ }
+
+ end += 2;
+
+ while (end < this.len_ && this.isHex(this.input_[end]))
+ end += 1;
+
+ this.cur_pos_ = end;
+
+ let val = parseInt(this.input_.substr(start, end - start), 16);
+ return new Token(TokenType.kIntegerLiteral, this.cur_line_, val);
+ }
+
+ /**
+ * Attempt to parse an encoded integer.
+ * @return {Token|undefined} returns a Token if a number is matched,
+ * undefined otherwise.
+ */
+ tryInteger() {
+ let start = this.cur_pos_;
+ let end = start;
+
+ if (this.cur_pos_ >= this.len_)
+ return undefined;
+ if (this.input_[end] === "-")
+ end += 1;
+
+ if (end >= this.len_ || !this.isNum(this.input_[end]))
+ return undefined;
+
+ while (end < this.len_ && this.isNum(this.input_[end]))
+ end += 1;
+
+ this.cur_pos_ = end;
+
+ let val = parseInt(this.input_.substr(start, end - start), 10);
+ return new Token(TokenType.kIntegerLiteral, this.cur_line_, val);
+ }
+
+ /**
+ * Attempt to parse a result id.
+ * @return {Token|undefined} returns a Token if a result id is matched,
+ * undefined otherwise.
+ */
+ tryResultId() {
+ let start = this.cur_pos_;
+ if (start >= this.len_)
+ return undefined;
+ if (!this.is("%"))
+ return undefined;
+
+ start += 1;
+ this.cur_pos_ += 1;
+ while (this.cur_pos_ < this.len_ &&
+ (this.isAlphaNum(this.input_[this.cur_pos_]) || this.is("_"))) {
+ this.cur_pos_ += 1;
+ }
+
+ let ident = this.input_.substr(start, this.cur_pos_ - start);
+ let value = undefined;
+ if (ident.match(this.num_regex_))
+ value = parseInt(ident, 10);
+
+ return new Token(TokenType.kResultId, this.cur_line_, {
+ name: ident,
+ val: value
+ });
+ }
+
+ /**
+ * Attempt to parse an identifier.
+ * @return {Token|undefined} returns a Token if an identifier is matched,
+ * undefined otherwise.
+ */
+ tryIdent() {
+ let start = this.cur_pos_;
+ if (start >= this.len_)
+ return undefined;
+
+ while (this.cur_pos_ < this.len_ &&
+ (this.isAlphaNum(this.input_[this.cur_pos_]) || this.is("_"))) {
+ this.cur_pos_ += 1;
+ }
+
+ let ident = this.input_.substr(start, this.cur_pos_ - start);
+ return new Token(TokenType.kIdentifier, this.cur_line_, ident);
+ }
+
+ /**
+ * Attempt to parse an Op command.
+ * @return {Token|undefined} returns a Token if an Op command is matched,
+ * undefined otherwise.
+ */
+ tryOp() {
+ let start = this.cur_pos_;
+ if (this.cur_pos_ >= this.len_ || (this.cur_pos_ + 1 >= this.len_))
+ return undefined;
+
+ if (this.input_[this.cur_pos_] !== "O" ||
+ this.input_[this.cur_pos_ + 1] !== "p") {
+ return undefined;
+ }
+
+ while (this.cur_pos_ < this.len_ &&
+ !this.isCurWhitespace()) {
+ this.cur_pos_ += 1;
+ }
+
+ return new Token(TokenType.kOp, this.cur_line_, {
+ name: this.input_.substr(start, this.cur_pos_ - start)
+ });
+ }
+
+ /**
+ * Attempts to match punctuation strings against the input
+ * @return {Token|undefined} Returns the Token for the punctuation or
+ * undefined if no matches found.
+ */
+ tryPunctuation() {
+ let type = undefined;
+ if (this.is("="))
+ type = TokenType.kEqual;
+ else if (this.is("|"))
+ type = TokenType.kPipe;
+
+ if (type === undefined)
+ return undefined;
+
+ this.cur_pos_ += type.length;
+ return new Token(type, this.cur_line_, type);
+ }
+
+ /**
+ * Attempts to match strings against the input
+ * @return {Token|undefined} Returns the Token for the string or undefined
+ * if no match found.
+ */
+ tryString() {
+ let start = this.cur_pos_;
+
+ // Must have at least 2 chars for a string.
+ if (this.cur_pos_ >= this.len_ || (this.cur_pos_ + 1 >= this.len_))
+ return undefined;
+ if (!this.is("\""))
+ return undefined;
+
+ this.cur_pos_ += 1;
+ let str = "";
+ while (this.cur_pos_ <= this.len_) {
+ if (this.is("\""))
+ break;
+
+ if (this.is("\\")) {
+ this.cur_pos_ += 1;
+ if (this.cur_pos_ >= this.len_)
+ return undefined;
+
+ if (this.is("\\")) {
+ str += "\\";
+ } else if (this.is("\"")) {
+ str += '"';
+ } else {
+ str += this.input_[this.cur_pos_];
+ }
+ } else {
+ str += this.input_[this.cur_pos_];
+ }
+ this.cur_pos_ += 1;
+ }
+
+ if (this.cur_pos_ >= this.len_)
+ return undefined;
+
+ this.cur_pos_ += 1;
+
+ return new Token(TokenType.kStringLiteral, this.cur_line_, str);
+ }
+}
diff --git a/tools/sva/src/lexer_test.js b/tools/sva/src/lexer_test.js
new file mode 100644
index 0000000..32b24c7
--- /dev/null
+++ b/tools/sva/src/lexer_test.js
@@ -0,0 +1,191 @@
+// Copyright 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.
+
+import { assert } from "chai";
+import Lexer from "./lexer";
+import { TokenType } from "./token";
+
+describe("lexer", () => {
+ describe("skipped content", () => {
+ it("skips whitespace", () => {
+ let input = " \t\r\n\t \tOpKill\t\n\t \r ";
+ let l = new Lexer(input);
+
+ let t = l.next();
+ assert.equal(t.type, TokenType.kOp);
+ assert.equal(t.line, 2);
+ assert.equal(t.data.name, "OpKill");
+
+ t = l.next();
+ assert.equal(t.type, TokenType.kEOF);
+ assert.equal(t.line, 3);
+ });
+
+ it("skips ; comments", () => {
+ let input = `; start with comment
+OpKill ; end of line comment
+; another comment
+%1`;
+
+ let l = new Lexer(input);
+ let t = l.next();
+ assert.equal(t.type, TokenType.kOp);
+ assert.equal(t.data.name, "OpKill");
+ assert.equal(t.line, 2);
+
+ t = l.next();
+ assert.equal(t.type, TokenType.kResultId);
+ assert.equal(t.data.name, "1");
+ assert.equal(t.data.val, 1);
+ assert.equal(t.line, 4);
+ });
+ });
+
+ describe("numerics", () => {
+ it("parses floats", () => {
+ let input = ["0.0", "0.", ".0", "5.7", "5.", ".7", "-0.0", "-.0",
+ "-0.", "-5.7", "-5.", "-.7"];
+
+ let results = [0.0, 0.0, 0.0, 5.7, 5.0, 0.7, 0.0, 0.0, 0.0, -5.7, -5.0,
+ -0.7];
+ input.forEach((val, idx) => {
+ let l = new Lexer(val);
+ let t = l.next();
+
+ assert.equal(t.type, TokenType.kFloatLiteral,
+ `expected ${val} to be a float got ${t.type}`);
+ assert.equal(t.data, results[idx],
+ `expected ${results[idx]} === ${t.data}`);
+
+ t = l.next();
+ assert.equal(t.type, TokenType.kEOF);
+ assert.equal(t.data, undefined);
+ });
+ });
+
+ it("handles invalid floats", () => {
+ let input = [".", "-."];
+ input.forEach((val) => {
+ let l = new Lexer(val);
+ let t = l.next();
+
+ assert.notEqual(t.type, TokenType.kFloatLiteral,
+ `expect ${val} to not match type float`);
+ });
+ });
+
+ it("parses integers", () => {
+ let input = ["0", "-0", "123", "-123", "2147483647", "-2147483648",
+ "4294967295", "0x00", "0x24"];
+ let results = [0, 0, 123, -123,2147483647, -2147483648, 4294967295,
+ 0x0, 0x24];
+
+ input.forEach((val, idx) => {
+ let l = new Lexer(val);
+ let t = l.next();
+
+ assert.equal(t.type, TokenType.kIntegerLiteral,
+ `expected ${val} to be an integer got ${t.type}`);
+ assert.equal(t.data, results[idx],
+ `expected ${results[idx]} === ${t.data}`);
+
+ t = l.next();
+ assert.equal(t.type, TokenType.kEOF);
+ assert.equal(t.data, undefined);
+ });
+ });
+ });
+
+ it("matches result_ids", () => {
+ let input = `%123
+%001
+%main
+%_a_b_c`;
+
+ let result = [
+ {name: "123", val: 123},
+ {name: "001", val: 1},
+ {name: "main", val: undefined},
+ {name: "_a_b_c", val: undefined}
+ ];
+
+ let l = new Lexer(input);
+ for (let i = 0; i < result.length; ++i) {
+ let t = l.next();
+ assert.equal(t.type, TokenType.kResultId);
+ assert.equal(t.data.name, result[i].name);
+ assert.equal(t.data.val, result[i].val);
+ }
+ });
+
+ it("matches punctuation", () => {
+ let input = "=";
+ let results = [TokenType.kEqual];
+
+ let l = new Lexer(input);
+ for (let i = 0; i < results.length; ++i) {
+ let t = l.next();
+ assert.equal(t.type, results[i]);
+ assert.equal(t.line, i + 1);
+ }
+
+ let t = l.next();
+ assert.equal(t.type, TokenType.kEOF);
+ });
+
+ describe("strings", () => {
+ it("matches strings", () => {
+ let input = "\"GLSL.std.450\"";
+
+ let l = new Lexer(input);
+ let t = l.next();
+ assert.equal(t.type, TokenType.kStringLiteral);
+ assert.equal(t.data, "GLSL.std.450");
+ });
+
+ it("handles unfinished strings", () => {
+ let input = "\"GLSL.std.450";
+
+ let l = new Lexer(input);
+ let t = l.next();
+ assert.equal(t.type, TokenType.kError);
+ });
+
+ it("handles escapes", () => {
+ let input = `"embedded\\"quote"
+"embedded\\\\slash"
+"embedded\\nchar"`;
+ let results = [`embedded\"quote`, `embedded\\slash`, `embeddednchar`];
+
+ let l = new Lexer(input);
+ for (let i = 0; i < results.length; ++i) {
+ let t = l.next();
+ assert.equal(t.type, TokenType.kStringLiteral, results[i]);
+ assert.equal(t.data, results[i]);
+ }
+ });
+ });
+
+ it("matches keywords", () => {
+ let input = "GLSL Function";
+ let results = ["GLSL", "Function"];
+
+ let l = new Lexer(input);
+ for (let i = 0; i < results.length; ++i) {
+ let t = l.next();
+ assert.equal(t.type, TokenType.kIdentifier, results[i]);
+ assert.equal(t.data, results[i]);
+ }
+ });
+});
diff --git a/tools/sva/src/parser.js b/tools/sva/src/parser.js
new file mode 100644
index 0000000..ccf872a
--- /dev/null
+++ b/tools/sva/src/parser.js
@@ -0,0 +1,283 @@
+// Copyright 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.
+
+import { TokenType } from "./token.js";
+import * as AST from "./ast.js";
+
+export default class Parser {
+ /**
+ * @param {Hash} The SPIR-V grammar
+ * @param {Lexer} The lexer
+ * @return {AST} Attempts to build an AST from the tokens returned by the
+ * given lexer
+ */
+ constructor(grammar, lexer) {
+ this.grammar_ = grammar;
+ this.lexer_ = lexer;
+
+ this.peek_ = [];
+ this.error_ = "";
+ }
+
+ get error() { return this.error_; }
+
+ next() {
+ return this.peek_.shift() || this.lexer_.next();
+ }
+
+ peek(idx) {
+ while (this.peek_.length <= idx) {
+ this.peek_.push(this.lexer_.next());
+ }
+ return this.peek_[idx];
+ }
+
+ /**
+ * Executes the parser.
+ *
+ * @return {AST|undefined} returns a parsed AST on success or undefined
+ * on error. The error message can be retrieved by
+ * calling error().
+ */
+ parse() {
+ let ast = new AST.Module();
+ for(;;) {
+ let token = this.next();
+ if (token === TokenType.kError) {
+ this.error_ = token.line() + ": " + token.data();
+ return undefined;
+ }
+ if (token.type === TokenType.kEOF)
+ break;
+
+ let result_id = undefined;
+ if (token.type === TokenType.kResultId) {
+ result_id = token;
+
+ token = this.next();
+ if (token.type !== TokenType.kEqual) {
+ this.error_ = token.line + ": expected = after result id";
+ return undefined;
+ }
+
+ token = this.next();
+ }
+
+ if (token.type !== TokenType.kOp) {
+ this.error_ = token.line + ": expected Op got " + token.type;
+ return undefined;
+ }
+
+ let name = token.data.name;
+ let data = this.getInstructionData(name);
+ let operands = [];
+ let result_type = undefined;
+
+ for (let operand of data.operands) {
+ if (operand.kind === "IdResult") {
+ if (result_id === undefined) {
+ this.error_ = token.line + ": expected result id";
+ return undefined;
+ }
+ let o = new AST.Operand(ast, result_id.data.name, "result_id",
+ result_id.data.val, []);
+ if (o === undefined) {
+ return undefined;
+ }
+ operands.push(o);
+ } else {
+ if (operand.quantifier === "?") {
+ if (this.nextIsNewInstr()) {
+ break;
+ }
+ } else if (operand.quantifier === "*") {
+ while (!this.nextIsNewInstr()) {
+ let o = this.extractOperand(ast, result_type, operand);
+ if (o === undefined) {
+ return undefined;
+ }
+ operands.push(o);
+ }
+ break;
+ }
+
+ let o = this.extractOperand(ast, result_type, operand);
+ if (o === undefined) {
+ return undefined;
+ }
+
+ // Store the result type away so we can use it for context dependent
+ // numbers if needed.
+ if (operand.kind === "IdResultType") {
+ result_type = ast.getType(o.name());
+ }
+
+ operands.push(o);
+ }
+ }
+
+ // Verify only GLSL extended instructions are used
+ if (name === "OpExtInstImport" && operands[1].value() !== "GLSL.std.450") {
+ this.error_ = token.line + ": Only GLSL.std.450 external instructions supported";
+ return undefined;
+ }
+
+ let inst = new AST.Instruction(name, data.opcode, operands);
+
+ ast.addInstruction(inst);
+ }
+ return ast;
+ }
+
+ getInstructionData(name) {
+ return this.grammar_["instructions"][name];
+ }
+
+ nextIsNewInstr() {
+ let n0 = this.peek(0);
+ if (n0.type === TokenType.kOp || n0.type === TokenType.kEOF) {
+ return true;
+ }
+
+ let n1 = this.peek(1);
+ if (n1.type === TokenType.kEOF) {
+ return false;
+ }
+ if (n0.type === TokenType.kResultId && n1.type === TokenType.kEqual)
+ return true;
+
+ return false;
+ }
+
+ extractOperand(ast, result_type, data) {
+ let t = this.next();
+
+ let name = undefined;
+ let kind = undefined;
+ let value = undefined;
+ let params = [];
+
+ // TODO(dsinclair): There are a bunch of missing types here. See
+ // https://github.com/KhronosGroup/SPIRV-Tools/blob/master/source/text.cpp#L210
+ //
+ // LiteralSpecConstantOpInteger
+ // PairLiteralIntegerIdRef
+ // PairIdRefLiteralInteger
+ // PairIdRefIdRef
+ if (data.kind === "IdResult" || data.kind === "IdRef"
+ || data.kind === "IdResultType" || data.kind === "IdScope"
+ || data.kind === "IdMemorySemantics") {
+ if (t.type !== TokenType.kResultId) {
+ this.error_ = t.line + ": expected result id";
+ return undefined;
+ }
+
+ name = t.data.name;
+ kind = "result_id";
+ value = t.data.val;
+ } else if (data.kind === "LiteralString") {
+ if (t.type !== TokenType.kStringLiteral) {
+ this.error_ = t.line + ": expected string not found";
+ return undefined;
+ }
+
+ name = t.data;
+ kind = "string";
+ value = t.data;
+ } else if (data.kind === "LiteralInteger") {
+ if (t.type !== TokenType.kIntegerLiteral) {
+ this.error_ = t.line + ": expected integer not found";
+ return undefined;
+ }
+
+ name = "" + t.data;
+ kind = t.type;
+ value = t.data;
+ } else if (data.kind === "LiteralContextDependentNumber") {
+ if (result_type === undefined) {
+ this.error_ = t.line +
+ ": missing result type for context dependent number";
+ return undefined;
+ }
+ if (t.type !== TokenType.kIntegerLiteral
+ && t.type !== TokenType.kFloatLiteral) {
+ this.error_ = t.line + ": expected number not found";
+ return undefined;
+ }
+
+ name = "" + t.data;
+ kind = result_type.type;
+ value = t.data;
+
+ } else if (data.kind === "LiteralExtInstInteger") {
+ if (t.type !== TokenType.kIdentifier) {
+ this.error_ = t.line + ": expected instruction identifier";
+ return undefined;
+ }
+
+ if (this.grammar_.ext[t.data] === undefined) {
+ this.error_ = t.line + `: unable to find extended instruction (${t.data})`;
+ return undefined;
+ }
+
+ name = t.data;
+ kind = "integer";
+ value = this.grammar_.ext[t.data];
+
+ } else {
+ let d = this.grammar_.operand_kinds[data.kind];
+ if (d === undefined) {
+ this.error_ = t.line + ": expected " + data.kind + " not found";
+ return undefined;
+ }
+
+ let val = d.values[t.data]["value"];
+ let names = [t.data];
+ if (d.type === "BitEnum") {
+ for(;;) {
+ let tmp = this.peek(0);
+ if (tmp.type !== TokenType.kPipe) {
+ break;
+ }
+
+ this.next(); // skip pipe
+ tmp = this.next();
+
+ if (tmp.type !== TokenType.kIdentifier) {
+ this.error_ = tmp.line() + ": expected identifier";
+ return undefined;
+ }
+
+ val |= d.values[tmp.data]["value"];
+ names.push(tmp.data);
+ }
+ }
+
+ name = names.join("|");
+ kind = d.type;
+ value = val;
+
+ for (const op_name of names) {
+ if (d.values[op_name]['params'] === undefined) {
+ continue;
+ }
+
+ for (const param of d.values[op_name]["params"]) {
+ params.push(this.extractOperand(ast, result_type, { kind: param }));
+ }
+ }
+ }
+ return new AST.Operand(ast, name, kind, value, params);
+ }
+}
diff --git a/tools/sva/src/parser_test.js b/tools/sva/src/parser_test.js
new file mode 100644
index 0000000..dffc0b3
--- /dev/null
+++ b/tools/sva/src/parser_test.js
@@ -0,0 +1,489 @@
+// Copyright 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.
+
+import { assert } from "chai";
+import Lexer from "./lexer";
+import Parser from "./parser";
+import grammar from "./spirv.data.js";
+
+describe("parser", () => {
+ it("parses an opcode", () => {
+ let input = "OpKill";
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpKill");
+ assert.equal(inst.opcode(), 252);
+ assert.lengthOf(inst.operands, 0);
+ });
+
+ it("parses an opcode with an identifier", () => {
+ let input = "OpCapability Shader";
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpCapability");
+ assert.equal(inst.opcode(), 17);
+ assert.lengthOf(inst.operands(), 1);
+
+ let op = inst.operand(0);
+ assert.equal(op.name(), "Shader");
+ assert.equal(op.type(), "ValueEnum");
+ assert.equal(op.value(), 1);
+ });
+
+ it("parses an opcode with a result", () => {
+ let input = "%void = OpTypeVoid";
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpTypeVoid");
+ assert.equal(inst.opcode(), 19);
+ assert.lengthOf(inst.operands(), 1);
+
+ let op = inst.operand(0);
+ assert.equal(op.name(), "void");
+ assert.equal(op.value(), 1);
+ });
+
+ it("sets module bounds based on numeric result", () => {
+ let input = "%3 = OpTypeVoid";
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.equal(ast.getId("next"), 4);
+ });
+
+ it("returns the same value for a named result_id", () => {
+ let input = "%3 = OpTypeFunction %int %int";
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ let op1 = inst.operand(1);
+ assert.equal(op1.name(), "int");
+ assert.equal(op1.value(), 4);
+
+ let op2 = inst.operand(2);
+ assert.equal(op2.name(), "int");
+ assert.equal(op2.value(), 4);
+ });
+
+ it("parses an opcode with a string", () => {
+ let input = "OpEntryPoint Fragment %main \"main\"";
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ let op = inst.operand(2);
+ assert.equal(op.name(), "main");
+ assert.equal(op.value(), "main");
+ });
+
+ describe("numerics", () => {
+ describe("integers", () => {
+ it("parses an opcode with an integer", () => {
+ let input = "OpSource GLSL 440";
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ let op0 = inst.operand(0);
+ assert.equal(op0.name(), "GLSL");
+ assert.equal(op0.type(), "ValueEnum");
+ assert.equal(op0.value(), 2);
+
+ let op1 = inst.operand(1);
+ assert.equal(op1.name(), "440");
+ assert.equal(op1.value(), 440);
+ });
+
+ it("parses an opcode with a hex integer", () => {
+ let input = "OpSource GLSL 0x440";
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ let op0 = inst.operand(0);
+ assert.equal(op0.name(), "GLSL");
+ assert.equal(op0.type(), "ValueEnum");
+ assert.equal(op0.value(), 2);
+
+ let op1 = inst.operand(1);
+ assert.equal(op1.name(), "1088");
+ assert.equal(op1.value(), 0x440);
+ });
+
+ it.skip("parses immediate integers", () => {
+ // TODO(dsinclair): Support or skip?
+ });
+ });
+
+ describe("floats", () => {
+ it("parses floats", () => {
+ let input = `%float = OpTypeFloat 32
+ %float1 = OpConstant %float 0.400000006`;
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(1);
+ let op2 = inst.operand(2);
+ assert.equal(op2.value(), 0.400000006);
+ });
+
+ // TODO(dsinclair): Make hex encoded floats parse ...
+ it.skip("parses hex floats", () => {
+ let input = `%float = OpTypeFloat 32
+ %nfloat = OpConstant %float -0.4p+2
+ %pfloat = OpConstant %float 0.4p-2
+ %inf = OpConstant %float32 0x1p+128
+ %neginf = OpConstant %float32 -0x1p+128
+ %aNaN = OpConstant %float32 0x1.8p+128
+ %moreNaN = OpConstant %float32 -0x1.0002p+128`;
+
+ let results = [-40.0, .004, 0x00000, 0x00000, 0x7fc00000, 0xff800100];
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+ assert.lengthOf(ast.instructions(), 7);
+
+ for (const idx in results) {
+ let inst = ast.instruction(idx);
+ let op2 = inst.operand(2);
+ assert.equal(op2.value(), results[idx]);
+ }
+ });
+
+ it("parses a float that looks like an int", () => {
+ let input = `%float = OpTypeFloat 32
+ %float1 = OpConstant %float 1`;
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(1);
+ let op2 = inst.operand(2);
+ assert.equal(op2.value(), 1);
+ assert.equal(op2.type(), "float");
+ });
+ });
+ });
+
+ describe("enums", () => {
+ it("parses enum values", () => {
+ let input = `%1 = OpTypeFloat 32
+ %30 = OpImageSampleExplicitLod %1 %20 %18 Grad|ConstOffset %22 %24 %29`;
+
+ let vals = [{val: 1, name: "1"},
+ {val: 30, name: "30"},
+ {val: 20, name: "20"},
+ {val: 18, name: "18"},
+ {val: 12, name: "Grad|ConstOffset"}];
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(1);
+ for (let idx in vals) {
+ let op = inst.operand(idx);
+ assert.equal(op.name(), vals[idx].name);
+ assert.equal(op.value(), vals[idx].val);
+ }
+
+ // BitEnum
+ let params = inst.operand(4).params();
+ assert.lengthOf(params, 3);
+ assert.equal(params[0].name(), "22");
+ assert.equal(params[0].value(), 22);
+ assert.equal(params[1].name(), "24");
+ assert.equal(params[1].value(), 24);
+ assert.equal(params[2].name(), "29");
+ assert.equal(params[2].value(), 29);
+ });
+
+ it("parses enumerants with parameters", () => {
+ let input ="OpExecutionMode %main LocalSize 2 3 4";
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpExecutionMode");
+ assert.lengthOf(inst.operands(), 2);
+ assert.equal(inst.operand(0).name(), "main");
+ assert.equal(inst.operand(1).name(), "LocalSize");
+
+ let params = inst.operand(1).params();
+ assert.lengthOf(params, 3);
+ assert.equal(params[0].name(), "2");
+ assert.equal(params[1].name(), "3");
+ assert.equal(params[2].name(), "4");
+ });
+ });
+
+ it("parses result into second operand if needed", () => {
+ let input = `%int = OpTypeInt 32 1
+ %int_3 = OpConstant %int 3`;
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(1);
+ assert.equal(inst.name(), "OpConstant");
+ assert.equal(inst.opcode(), 43);
+ assert.lengthOf(inst.operands(), 3);
+
+ let op0 = inst.operand(0);
+ assert.equal(op0.name(), "int");
+ assert.equal(op0.value(), 1);
+
+ let op1 = inst.operand(1);
+ assert.equal(op1.name(), "int_3");
+ assert.equal(op1.value(), 2);
+
+ let op2 = inst.operand(2);
+ assert.equal(op2.name(), "3");
+ assert.equal(op2.value(), 3);
+ });
+
+ describe("quantifiers", () => {
+ describe("?", () => {
+ it("skips if missing", () => {
+ let input = `OpImageWrite %1 %2 %3
+OpKill`;
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpImageWrite");
+ assert.lengthOf(inst.operands(), 3);
+ });
+
+ it("skips if missing at EOF", () => {
+ let input = "OpImageWrite %1 %2 %3";
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpImageWrite");
+ assert.lengthOf(inst.operands(), 3);
+ });
+
+ it("extracts if available", () => {
+ let input = `OpImageWrite %1 %2 %3 ConstOffset %2
+OpKill`;
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpImageWrite");
+ assert.lengthOf(inst.operands(), 4);
+ assert.equal(inst.operand(3).name(), "ConstOffset");
+ });
+ });
+
+ describe("*", () => {
+ it("skips if missing", () => {
+ let input = `OpEntryPoint Fragment %main "main"
+OpKill`;
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpEntryPoint");
+ assert.lengthOf(inst.operands(), 3);
+ assert.equal(inst.operand(2).name(), "main");
+ });
+
+ it("extracts one if available", () => {
+ let input = `OpEntryPoint Fragment %main "main" %2
+OpKill`;
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpEntryPoint");
+ assert.lengthOf(inst.operands(), 4);
+ assert.equal(inst.operand(3).name(), "2");
+ });
+
+ it("extracts multiple if available", () => {
+ let input = `OpEntryPoint Fragment %main "main" %2 %3 %4 %5
+OpKill`;
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(0);
+ assert.equal(inst.name(), "OpEntryPoint");
+ assert.lengthOf(inst.operands(), 7);
+ assert.equal(inst.operand(3).name(), "2");
+ assert.equal(inst.operand(4).name(), "3");
+ assert.equal(inst.operand(5).name(), "4");
+ assert.equal(inst.operand(6).name(), "5");
+ });
+ });
+ });
+
+ describe("extended instructions", () => {
+ it("errors on non-glsl extensions", () => {
+ let input = "%1 = OpExtInstImport \"OpenCL.std.100\"";
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ assert.isUndefined(p.parse());
+ });
+
+ it("handles extended instructions", () => {
+ let input = `%1 = OpExtInstImport "GLSL.std.450"
+ %44 = OpExtInst %7 %1 Sqrt %43`;
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+ assert.lengthOf(ast.instructions(), 2);
+
+ let inst = ast.instruction(1);
+ assert.lengthOf(inst.operands(), 5);
+ assert.equal(inst.operand(3).value(), 31);
+ assert.equal(inst.operand(3).name(), "Sqrt");
+ assert.equal(inst.operand(4).value(), 43);
+ assert.equal(inst.operand(4).name(), "43");
+ });
+ });
+
+ it.skip("handles spec constant ops", () => {
+ // let input = "%sum = OpSpecConstantOp %i32 IAdd %a %b";
+ });
+
+ it("handles OpCopyMemory", () => {
+ let input = "OpCopyMemory %1 %2 " +
+ "Volatile|Nontemporal|MakePointerVisible %3 " +
+ "Aligned|MakePointerAvailable|NonPrivatePointer 16 %4";
+
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ assert.exists(ast, p.error);
+ assert.lengthOf(ast.instructions(), 1);
+
+ let inst = ast.instruction(0);
+ assert.lengthOf(inst.operands(), 4);
+ assert.equal(inst.operand(0).value(), 1);
+ assert.equal(inst.operand(1).value(), 2);
+
+ assert.equal(inst.operand(2).name(),
+ "Volatile|Nontemporal|MakePointerVisible");
+ assert.equal(inst.operand(2).value(), 21);
+ assert.lengthOf(inst.operand(2).params(), 1);
+ assert.equal(inst.operand(2).params()[0].value(), 3);
+
+ assert.equal(inst.operand(3).name(),
+ "Aligned|MakePointerAvailable|NonPrivatePointer");
+ assert.equal(inst.operand(3).value(), 42);
+ assert.lengthOf(inst.operand(3).params(), 2);
+ assert.equal(inst.operand(3).params()[0].value(), 16);
+ assert.equal(inst.operand(3).params()[1].value(), 4);
+ });
+});
diff --git a/tools/sva/src/spirv.data.js b/tools/sva/src/spirv.data.js
new file mode 100644
index 0000000..ba969d8
--- /dev/null
+++ b/tools/sva/src/spirv.data.js
@@ -0,0 +1,4567 @@
+/*Copyright (c) 2014-2016 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and/or associated documentation files (the "Materials"),
+to deal in the Materials without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Materials, and to permit persons to whom the
+Materials are furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Materials.
+
+MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
+STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
+HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
+IN THE MATERIALS.*/
+
+// THIS FILE IS GENERATED WITH tools/process_grammar.rb
+
+export default {
+ "magic": "0x07230203",
+ "version": [
+ 1,
+ 5
+ ],
+ "instructions": {
+ "OpNop": {
+ "opcode": 0,
+ "operands": [
+
+ ]
+ },
+ "OpUndef": {
+ "opcode": 1,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpSourceContinued": {
+ "opcode": 2,
+ "operands": [
+ {
+ "kind": "LiteralString"
+ }
+ ]
+ },
+ "OpSource": {
+ "opcode": 3,
+ "operands": [
+ {
+ "kind": "SourceLanguage"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "?"
+ },
+ {
+ "kind": "LiteralString",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpSourceExtension": {
+ "opcode": 4,
+ "operands": [
+ {
+ "kind": "LiteralString"
+ }
+ ]
+ },
+ "OpName": {
+ "opcode": 5,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralString"
+ }
+ ]
+ },
+ "OpMemberName": {
+ "opcode": 6,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "LiteralString"
+ }
+ ]
+ },
+ "OpString": {
+ "opcode": 7,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralString"
+ }
+ ]
+ },
+ "OpLine": {
+ "opcode": 8,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "LiteralInteger"
+ }
+ ]
+ },
+ "OpExtension": {
+ "opcode": 10,
+ "operands": [
+ {
+ "kind": "LiteralString"
+ }
+ ]
+ },
+ "OpExtInstImport": {
+ "opcode": 11,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralString"
+ }
+ ]
+ },
+ "OpExtInst": {
+ "opcode": 12,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralExtInstInteger"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpMemoryModel": {
+ "opcode": 14,
+ "operands": [
+ {
+ "kind": "AddressingModel"
+ },
+ {
+ "kind": "MemoryModel"
+ }
+ ]
+ },
+ "OpEntryPoint": {
+ "opcode": 15,
+ "operands": [
+ {
+ "kind": "ExecutionModel"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralString"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpExecutionMode": {
+ "opcode": 16,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ExecutionMode"
+ }
+ ]
+ },
+ "OpCapability": {
+ "opcode": 17,
+ "operands": [
+ {
+ "kind": "Capability"
+ }
+ ]
+ },
+ "OpTypeVoid": {
+ "opcode": 19,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpTypeBool": {
+ "opcode": 20,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpTypeInt": {
+ "opcode": 21,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "LiteralInteger"
+ }
+ ]
+ },
+ "OpTypeFloat": {
+ "opcode": 22,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralInteger"
+ }
+ ]
+ },
+ "OpTypeVector": {
+ "opcode": 23,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger"
+ }
+ ]
+ },
+ "OpTypeMatrix": {
+ "opcode": 24,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger"
+ }
+ ]
+ },
+ "OpTypeImage": {
+ "opcode": 25,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "Dim"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "ImageFormat"
+ },
+ {
+ "kind": "AccessQualifier",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpTypeSampler": {
+ "opcode": 26,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpTypeSampledImage": {
+ "opcode": 27,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpTypeArray": {
+ "opcode": 28,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpTypeRuntimeArray": {
+ "opcode": 29,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpTypeStruct": {
+ "opcode": 30,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpTypePointer": {
+ "opcode": 32,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "StorageClass"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpTypeFunction": {
+ "opcode": 33,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpConstantTrue": {
+ "opcode": 41,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpConstantFalse": {
+ "opcode": 42,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpConstant": {
+ "opcode": 43,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralContextDependentNumber"
+ }
+ ]
+ },
+ "OpConstantComposite": {
+ "opcode": 44,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpConstantNull": {
+ "opcode": 46,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpSpecConstantTrue": {
+ "opcode": 48,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpSpecConstantFalse": {
+ "opcode": 49,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpSpecConstant": {
+ "opcode": 50,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralContextDependentNumber"
+ }
+ ]
+ },
+ "OpSpecConstantComposite": {
+ "opcode": 51,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpSpecConstantOp": {
+ "opcode": 52,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralSpecConstantOpInteger"
+ }
+ ]
+ },
+ "OpFunction": {
+ "opcode": 54,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "FunctionControl"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFunctionParameter": {
+ "opcode": 55,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpFunctionEnd": {
+ "opcode": 56,
+ "operands": [
+
+ ]
+ },
+ "OpFunctionCall": {
+ "opcode": 57,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpVariable": {
+ "opcode": 59,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "StorageClass"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImageTexelPointer": {
+ "opcode": 60,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpLoad": {
+ "opcode": 61,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpStore": {
+ "opcode": 62,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpCopyMemory": {
+ "opcode": 63,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpAccessChain": {
+ "opcode": 65,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpInBoundsAccessChain": {
+ "opcode": 66,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpArrayLength": {
+ "opcode": 68,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger"
+ }
+ ]
+ },
+ "OpDecorate": {
+ "opcode": 71,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ]
+ },
+ "OpMemberDecorate": {
+ "opcode": 72,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ]
+ },
+ "OpDecorationGroup": {
+ "opcode": 73,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpGroupDecorate": {
+ "opcode": 74,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpGroupMemberDecorate": {
+ "opcode": 75,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "PairIdRefLiteralInteger",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpVectorExtractDynamic": {
+ "opcode": 77,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpVectorInsertDynamic": {
+ "opcode": 78,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpVectorShuffle": {
+ "opcode": 79,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpCompositeConstruct": {
+ "opcode": 80,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpCompositeExtract": {
+ "opcode": 81,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpCompositeInsert": {
+ "opcode": 82,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpCopyObject": {
+ "opcode": 83,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpTranspose": {
+ "opcode": 84,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSampledImage": {
+ "opcode": 86,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpImageSampleImplicitLod": {
+ "opcode": 87,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImageSampleExplicitLod": {
+ "opcode": 88,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ]
+ },
+ "OpImageSampleDrefImplicitLod": {
+ "opcode": 89,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImageSampleDrefExplicitLod": {
+ "opcode": 90,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ]
+ },
+ "OpImageSampleProjImplicitLod": {
+ "opcode": 91,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImageSampleProjExplicitLod": {
+ "opcode": 92,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ]
+ },
+ "OpImageSampleProjDrefImplicitLod": {
+ "opcode": 93,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImageSampleProjDrefExplicitLod": {
+ "opcode": 94,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ]
+ },
+ "OpImageFetch": {
+ "opcode": 95,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImageGather": {
+ "opcode": 96,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImageDrefGather": {
+ "opcode": 97,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImageRead": {
+ "opcode": 98,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImageWrite": {
+ "opcode": 99,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ "OpImage": {
+ "opcode": 100,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpImageQuerySizeLod": {
+ "opcode": 103,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpImageQuerySize": {
+ "opcode": 104,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpImageQueryLod": {
+ "opcode": 105,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpImageQueryLevels": {
+ "opcode": 106,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpImageQuerySamples": {
+ "opcode": 107,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpConvertFToU": {
+ "opcode": 109,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpConvertFToS": {
+ "opcode": 110,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpConvertSToF": {
+ "opcode": 111,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpConvertUToF": {
+ "opcode": 112,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpUConvert": {
+ "opcode": 113,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSConvert": {
+ "opcode": 114,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFConvert": {
+ "opcode": 115,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpQuantizeToF16": {
+ "opcode": 116,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBitcast": {
+ "opcode": 124,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSNegate": {
+ "opcode": 126,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFNegate": {
+ "opcode": 127,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpIAdd": {
+ "opcode": 128,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFAdd": {
+ "opcode": 129,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpISub": {
+ "opcode": 130,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFSub": {
+ "opcode": 131,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpIMul": {
+ "opcode": 132,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFMul": {
+ "opcode": 133,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpUDiv": {
+ "opcode": 134,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSDiv": {
+ "opcode": 135,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFDiv": {
+ "opcode": 136,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpUMod": {
+ "opcode": 137,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSRem": {
+ "opcode": 138,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSMod": {
+ "opcode": 139,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFRem": {
+ "opcode": 140,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFMod": {
+ "opcode": 141,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpVectorTimesScalar": {
+ "opcode": 142,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpMatrixTimesScalar": {
+ "opcode": 143,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpVectorTimesMatrix": {
+ "opcode": 144,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpMatrixTimesVector": {
+ "opcode": 145,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpMatrixTimesMatrix": {
+ "opcode": 146,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpOuterProduct": {
+ "opcode": 147,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpDot": {
+ "opcode": 148,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpIAddCarry": {
+ "opcode": 149,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpISubBorrow": {
+ "opcode": 150,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpUMulExtended": {
+ "opcode": 151,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSMulExtended": {
+ "opcode": 152,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAny": {
+ "opcode": 154,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAll": {
+ "opcode": 155,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpIsNan": {
+ "opcode": 156,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpIsInf": {
+ "opcode": 157,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpLogicalEqual": {
+ "opcode": 164,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpLogicalNotEqual": {
+ "opcode": 165,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpLogicalOr": {
+ "opcode": 166,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpLogicalAnd": {
+ "opcode": 167,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpLogicalNot": {
+ "opcode": 168,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSelect": {
+ "opcode": 169,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpIEqual": {
+ "opcode": 170,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpINotEqual": {
+ "opcode": 171,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpUGreaterThan": {
+ "opcode": 172,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSGreaterThan": {
+ "opcode": 173,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpUGreaterThanEqual": {
+ "opcode": 174,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSGreaterThanEqual": {
+ "opcode": 175,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpULessThan": {
+ "opcode": 176,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSLessThan": {
+ "opcode": 177,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpULessThanEqual": {
+ "opcode": 178,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpSLessThanEqual": {
+ "opcode": 179,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFOrdEqual": {
+ "opcode": 180,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFUnordEqual": {
+ "opcode": 181,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFOrdNotEqual": {
+ "opcode": 182,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFUnordNotEqual": {
+ "opcode": 183,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFOrdLessThan": {
+ "opcode": 184,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFUnordLessThan": {
+ "opcode": 185,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFOrdGreaterThan": {
+ "opcode": 186,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFUnordGreaterThan": {
+ "opcode": 187,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFOrdLessThanEqual": {
+ "opcode": 188,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFUnordLessThanEqual": {
+ "opcode": 189,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFOrdGreaterThanEqual": {
+ "opcode": 190,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFUnordGreaterThanEqual": {
+ "opcode": 191,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpShiftRightLogical": {
+ "opcode": 194,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpShiftRightArithmetic": {
+ "opcode": 195,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpShiftLeftLogical": {
+ "opcode": 196,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBitwiseOr": {
+ "opcode": 197,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBitwiseXor": {
+ "opcode": 198,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBitwiseAnd": {
+ "opcode": 199,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpNot": {
+ "opcode": 200,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBitFieldInsert": {
+ "opcode": 201,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBitFieldSExtract": {
+ "opcode": 202,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBitFieldUExtract": {
+ "opcode": 203,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBitReverse": {
+ "opcode": 204,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBitCount": {
+ "opcode": 205,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpDPdx": {
+ "opcode": 207,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpDPdy": {
+ "opcode": 208,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFwidth": {
+ "opcode": 209,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpDPdxFine": {
+ "opcode": 210,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpDPdyFine": {
+ "opcode": 211,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFwidthFine": {
+ "opcode": 212,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpDPdxCoarse": {
+ "opcode": 213,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpDPdyCoarse": {
+ "opcode": 214,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpFwidthCoarse": {
+ "opcode": 215,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpControlBarrier": {
+ "opcode": 224,
+ "operands": [
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ }
+ ]
+ },
+ "OpMemoryBarrier": {
+ "opcode": 225,
+ "operands": [
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ }
+ ]
+ },
+ "OpAtomicLoad": {
+ "opcode": 227,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ }
+ ]
+ },
+ "OpAtomicStore": {
+ "opcode": 228,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicExchange": {
+ "opcode": 229,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicCompareExchange": {
+ "opcode": 230,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicIIncrement": {
+ "opcode": 232,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ }
+ ]
+ },
+ "OpAtomicIDecrement": {
+ "opcode": 233,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ }
+ ]
+ },
+ "OpAtomicIAdd": {
+ "opcode": 234,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicISub": {
+ "opcode": 235,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicSMin": {
+ "opcode": 236,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicUMin": {
+ "opcode": 237,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicSMax": {
+ "opcode": 238,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicUMax": {
+ "opcode": 239,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicAnd": {
+ "opcode": 240,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicOr": {
+ "opcode": 241,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpAtomicXor": {
+ "opcode": 242,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdScope"
+ },
+ {
+ "kind": "IdMemorySemantics"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpPhi": {
+ "opcode": 245,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "PairIdRefIdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpLoopMerge": {
+ "opcode": 246,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LoopControl"
+ }
+ ]
+ },
+ "OpSelectionMerge": {
+ "opcode": 247,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "SelectionControl"
+ }
+ ]
+ },
+ "OpLabel": {
+ "opcode": 248,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ "OpBranch": {
+ "opcode": 249,
+ "operands": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpBranchConditional": {
+ "opcode": 250,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpSwitch": {
+ "opcode": 251,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "PairLiteralIntegerIdRef",
+ "quantifier": "*"
+ }
+ ]
+ },
+ "OpKill": {
+ "opcode": 252,
+ "operands": [
+
+ ]
+ },
+ "OpReturn": {
+ "opcode": 253,
+ "operands": [
+
+ ]
+ },
+ "OpReturnValue": {
+ "opcode": 254,
+ "operands": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpUnreachable": {
+ "opcode": 255,
+ "operands": [
+
+ ]
+ },
+ "OpNoLine": {
+ "opcode": 317,
+ "operands": [
+
+ ]
+ },
+ "OpModuleProcessed": {
+ "opcode": 330,
+ "operands": [
+ {
+ "kind": "LiteralString"
+ }
+ ]
+ },
+ "OpExecutionModeId": {
+ "opcode": 331,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "ExecutionMode"
+ }
+ ]
+ },
+ "OpDecorateId": {
+ "opcode": 332,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ]
+ },
+ "OpCopyLogical": {
+ "opcode": 400,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpPtrEqual": {
+ "opcode": 401,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpPtrNotEqual": {
+ "opcode": 402,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ "OpDecorateString": {
+ "opcode": 5632,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ]
+ },
+ "OpDecorateStringGOOGLE": {
+ "opcode": 5632,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ]
+ },
+ "OpMemberDecorateString": {
+ "opcode": 5633,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ]
+ },
+ "OpMemberDecorateStringGOOGLE": {
+ "opcode": 5633,
+ "operands": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "LiteralInteger"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ]
+ }
+ },
+ "operand_kinds": {
+ "ImageOperands": {
+ "type": "BitEnum",
+ "values": {
+ "None": {
+ "value": 0
+ },
+ "Bias": {
+ "value": 1,
+ "params": [
+ "IdRef"
+ ]
+ },
+ "Lod": {
+ "value": 2,
+ "params": [
+ "IdRef"
+ ]
+ },
+ "Grad": {
+ "value": 4,
+ "params": [
+ "IdRef",
+ "IdRef"
+ ]
+ },
+ "ConstOffset": {
+ "value": 8,
+ "params": [
+ "IdRef"
+ ]
+ },
+ "Sample": {
+ "value": 64,
+ "params": [
+ "IdRef"
+ ]
+ },
+ "MakeTexelAvailable": {
+ "value": 256,
+ "params": [
+ "IdScope"
+ ]
+ },
+ "MakeTexelAvailableKHR": {
+ "value": 256,
+ "params": [
+ "IdScope"
+ ]
+ },
+ "MakeTexelVisible": {
+ "value": 512,
+ "params": [
+ "IdScope"
+ ]
+ },
+ "MakeTexelVisibleKHR": {
+ "value": 512,
+ "params": [
+ "IdScope"
+ ]
+ },
+ "NonPrivateTexel": {
+ "value": 1024
+ },
+ "NonPrivateTexelKHR": {
+ "value": 1024
+ },
+ "VolatileTexel": {
+ "value": 2048
+ },
+ "VolatileTexelKHR": {
+ "value": 2048
+ },
+ "SignExtend": {
+ "value": 4096
+ },
+ "ZeroExtend": {
+ "value": 8192
+ }
+ }
+ },
+ "FPFastMathMode": {
+ "type": "BitEnum",
+ "values": {
+ "None": {
+ "value": 0
+ }
+ }
+ },
+ "SelectionControl": {
+ "type": "BitEnum",
+ "values": {
+ "None": {
+ "value": 0
+ },
+ "Flatten": {
+ "value": 1
+ },
+ "DontFlatten": {
+ "value": 2
+ }
+ }
+ },
+ "LoopControl": {
+ "type": "BitEnum",
+ "values": {
+ "None": {
+ "value": 0
+ },
+ "Unroll": {
+ "value": 1
+ },
+ "DontUnroll": {
+ "value": 2
+ },
+ "DependencyInfinite": {
+ "value": 4
+ },
+ "DependencyLength": {
+ "value": 8,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "MinIterations": {
+ "value": 16,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "MaxIterations": {
+ "value": 32,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "IterationMultiple": {
+ "value": 64,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "PeelCount": {
+ "value": 128,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "PartialCount": {
+ "value": 256,
+ "params": [
+ "LiteralInteger"
+ ]
+ }
+ }
+ },
+ "FunctionControl": {
+ "type": "BitEnum",
+ "values": {
+ "None": {
+ "value": 0
+ },
+ "Inline": {
+ "value": 1
+ },
+ "DontInline": {
+ "value": 2
+ },
+ "Pure": {
+ "value": 4
+ },
+ "Const": {
+ "value": 8
+ }
+ }
+ },
+ "MemorySemantics": {
+ "type": "BitEnum",
+ "values": {
+ "Relaxed": {
+ "value": 0
+ },
+ "None": {
+ "value": 0
+ },
+ "Acquire": {
+ "value": 2
+ },
+ "Release": {
+ "value": 4
+ },
+ "AcquireRelease": {
+ "value": 8
+ },
+ "SequentiallyConsistent": {
+ "value": 16
+ },
+ "UniformMemory": {
+ "value": 64
+ },
+ "SubgroupMemory": {
+ "value": 128
+ },
+ "WorkgroupMemory": {
+ "value": 256
+ },
+ "CrossWorkgroupMemory": {
+ "value": 512
+ },
+ "ImageMemory": {
+ "value": 2048
+ },
+ "OutputMemory": {
+ "value": 4096
+ },
+ "OutputMemoryKHR": {
+ "value": 4096
+ },
+ "MakeAvailable": {
+ "value": 8192
+ },
+ "MakeAvailableKHR": {
+ "value": 8192
+ },
+ "MakeVisible": {
+ "value": 16384
+ },
+ "MakeVisibleKHR": {
+ "value": 16384
+ },
+ "Volatile": {
+ "value": 32768
+ }
+ }
+ },
+ "MemoryAccess": {
+ "type": "BitEnum",
+ "values": {
+ "None": {
+ "value": 0
+ },
+ "Volatile": {
+ "value": 1
+ },
+ "Aligned": {
+ "value": 2,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "Nontemporal": {
+ "value": 4
+ },
+ "MakePointerAvailable": {
+ "value": 8,
+ "params": [
+ "IdScope"
+ ]
+ },
+ "MakePointerAvailableKHR": {
+ "value": 8,
+ "params": [
+ "IdScope"
+ ]
+ },
+ "MakePointerVisible": {
+ "value": 16,
+ "params": [
+ "IdScope"
+ ]
+ },
+ "MakePointerVisibleKHR": {
+ "value": 16,
+ "params": [
+ "IdScope"
+ ]
+ },
+ "NonPrivatePointer": {
+ "value": 32
+ },
+ "NonPrivatePointerKHR": {
+ "value": 32
+ }
+ }
+ },
+ "KernelProfilingInfo": {
+ "type": "BitEnum",
+ "values": {
+ "None": {
+ "value": 0
+ }
+ }
+ },
+ "SourceLanguage": {
+ "type": "ValueEnum",
+ "values": {
+ "Unknown": {
+ "value": 0
+ },
+ "ESSL": {
+ "value": 1
+ },
+ "GLSL": {
+ "value": 2
+ },
+ "OpenCL_C": {
+ "value": 3
+ },
+ "OpenCL_CPP": {
+ "value": 4
+ },
+ "HLSL": {
+ "value": 5
+ }
+ }
+ },
+ "ExecutionModel": {
+ "type": "ValueEnum",
+ "values": {
+ "Vertex": {
+ "value": 0
+ },
+ "Fragment": {
+ "value": 4
+ },
+ "GLCompute": {
+ "value": 5
+ }
+ }
+ },
+ "AddressingModel": {
+ "type": "ValueEnum",
+ "values": {
+ "Logical": {
+ "value": 0
+ }
+ }
+ },
+ "MemoryModel": {
+ "type": "ValueEnum",
+ "values": {
+ "Simple": {
+ "value": 0
+ },
+ "GLSL450": {
+ "value": 1
+ },
+ "Vulkan": {
+ "value": 3
+ },
+ "VulkanKHR": {
+ "value": 3
+ }
+ }
+ },
+ "ExecutionMode": {
+ "type": "ValueEnum",
+ "values": {
+ "PixelCenterInteger": {
+ "value": 6
+ },
+ "OriginUpperLeft": {
+ "value": 7
+ },
+ "OriginLowerLeft": {
+ "value": 8
+ },
+ "EarlyFragmentTests": {
+ "value": 9
+ },
+ "DepthReplacing": {
+ "value": 12
+ },
+ "DepthGreater": {
+ "value": 14
+ },
+ "DepthLess": {
+ "value": 15
+ },
+ "DepthUnchanged": {
+ "value": 16
+ },
+ "LocalSize": {
+ "value": 17,
+ "params": [
+ "LiteralInteger",
+ "LiteralInteger",
+ "LiteralInteger"
+ ]
+ },
+ "LocalSizeId": {
+ "value": 38,
+ "params": [
+ "IdRef",
+ "IdRef",
+ "IdRef"
+ ]
+ }
+ }
+ },
+ "StorageClass": {
+ "type": "ValueEnum",
+ "values": {
+ "UniformConstant": {
+ "value": 0
+ },
+ "Input": {
+ "value": 1
+ },
+ "Uniform": {
+ "value": 2
+ },
+ "Output": {
+ "value": 3
+ },
+ "Workgroup": {
+ "value": 4
+ },
+ "CrossWorkgroup": {
+ "value": 5
+ },
+ "Private": {
+ "value": 6
+ },
+ "Function": {
+ "value": 7
+ },
+ "PushConstant": {
+ "value": 9
+ },
+ "Image": {
+ "value": 11
+ },
+ "StorageBuffer": {
+ "value": 12
+ }
+ }
+ },
+ "Dim": {
+ "type": "ValueEnum",
+ "values": {
+ "1D": {
+ "value": 0
+ },
+ "2D": {
+ "value": 1
+ },
+ "3D": {
+ "value": 2
+ },
+ "Cube": {
+ "value": 3
+ }
+ }
+ },
+ "ImageFormat": {
+ "type": "ValueEnum",
+ "values": {
+ "Unknown": {
+ "value": 0
+ },
+ "Rgba32f": {
+ "value": 1
+ },
+ "Rgba16f": {
+ "value": 2
+ },
+ "R32f": {
+ "value": 3
+ },
+ "Rgba8": {
+ "value": 4
+ },
+ "Rgba8Snorm": {
+ "value": 5
+ },
+ "Rgba32i": {
+ "value": 21
+ },
+ "Rgba16i": {
+ "value": 22
+ },
+ "Rgba8i": {
+ "value": 23
+ },
+ "R32i": {
+ "value": 24
+ },
+ "Rgba32ui": {
+ "value": 30
+ },
+ "Rgba16ui": {
+ "value": 31
+ },
+ "Rgba8ui": {
+ "value": 32
+ },
+ "R32ui": {
+ "value": 33
+ }
+ }
+ },
+ "FPRoundingMode": {
+ "type": "ValueEnum",
+ "values": {
+ "RTE": {
+ "value": 0
+ },
+ "RTZ": {
+ "value": 1
+ },
+ "RTP": {
+ "value": 2
+ },
+ "RTN": {
+ "value": 3
+ }
+ }
+ },
+ "Decoration": {
+ "type": "ValueEnum",
+ "values": {
+ "RelaxedPrecision": {
+ "value": 0
+ },
+ "SpecId": {
+ "value": 1,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "Block": {
+ "value": 2
+ },
+ "BufferBlock": {
+ "value": 3
+ },
+ "RowMajor": {
+ "value": 4
+ },
+ "ColMajor": {
+ "value": 5
+ },
+ "ArrayStride": {
+ "value": 6,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "MatrixStride": {
+ "value": 7,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "GLSLShared": {
+ "value": 8
+ },
+ "GLSLPacked": {
+ "value": 9
+ },
+ "BuiltIn": {
+ "value": 11,
+ "params": [
+ "BuiltIn"
+ ]
+ },
+ "NoPerspective": {
+ "value": 13
+ },
+ "Flat": {
+ "value": 14
+ },
+ "Centroid": {
+ "value": 16
+ },
+ "Invariant": {
+ "value": 18
+ },
+ "Restrict": {
+ "value": 19
+ },
+ "Aliased": {
+ "value": 20
+ },
+ "Volatile": {
+ "value": 21
+ },
+ "Coherent": {
+ "value": 23
+ },
+ "NonWritable": {
+ "value": 24
+ },
+ "NonReadable": {
+ "value": 25
+ },
+ "Uniform": {
+ "value": 26
+ },
+ "UniformId": {
+ "value": 27,
+ "params": [
+ "IdScope"
+ ]
+ },
+ "Location": {
+ "value": 30,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "Component": {
+ "value": 31,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "Index": {
+ "value": 32,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "Binding": {
+ "value": 33,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "DescriptorSet": {
+ "value": 34,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "Offset": {
+ "value": 35,
+ "params": [
+ "LiteralInteger"
+ ]
+ },
+ "FPRoundingMode": {
+ "value": 39,
+ "params": [
+ "FPRoundingMode"
+ ]
+ },
+ "NoContraction": {
+ "value": 42
+ },
+ "NoSignedWrap": {
+ "value": 4469
+ },
+ "NoUnsignedWrap": {
+ "value": 4470
+ },
+ "ExplicitInterpAMD": {
+ "value": 4999
+ },
+ "CounterBuffer": {
+ "value": 5634,
+ "params": [
+ "IdRef"
+ ]
+ },
+ "HlslCounterBufferGOOGLE": {
+ "value": 5634,
+ "params": [
+ "IdRef"
+ ]
+ },
+ "UserSemantic": {
+ "value": 5635,
+ "params": [
+ "LiteralString"
+ ]
+ },
+ "HlslSemanticGOOGLE": {
+ "value": 5635,
+ "params": [
+ "LiteralString"
+ ]
+ },
+ "UserTypeGOOGLE": {
+ "value": 5636,
+ "params": [
+ "LiteralString"
+ ]
+ }
+ }
+ },
+ "BuiltIn": {
+ "type": "ValueEnum",
+ "values": {
+ "Position": {
+ "value": 0
+ },
+ "PointSize": {
+ "value": 1
+ },
+ "VertexId": {
+ "value": 5
+ },
+ "InstanceId": {
+ "value": 6
+ },
+ "FragCoord": {
+ "value": 15
+ },
+ "PointCoord": {
+ "value": 16
+ },
+ "FrontFacing": {
+ "value": 17
+ },
+ "SampleMask": {
+ "value": 20
+ },
+ "FragDepth": {
+ "value": 22
+ },
+ "HelperInvocation": {
+ "value": 23
+ },
+ "NumWorkgroups": {
+ "value": 24
+ },
+ "WorkgroupSize": {
+ "value": 25
+ },
+ "WorkgroupId": {
+ "value": 26
+ },
+ "LocalInvocationId": {
+ "value": 27
+ },
+ "GlobalInvocationId": {
+ "value": 28
+ },
+ "LocalInvocationIndex": {
+ "value": 29
+ },
+ "VertexIndex": {
+ "value": 42
+ },
+ "InstanceIndex": {
+ "value": 43
+ },
+ "BaryCoordNoPerspAMD": {
+ "value": 4992
+ },
+ "BaryCoordNoPerspCentroidAMD": {
+ "value": 4993
+ },
+ "BaryCoordNoPerspSampleAMD": {
+ "value": 4994
+ },
+ "BaryCoordSmoothAMD": {
+ "value": 4995
+ },
+ "BaryCoordSmoothCentroidAMD": {
+ "value": 4996
+ },
+ "BaryCoordSmoothSampleAMD": {
+ "value": 4997
+ },
+ "BaryCoordPullModelAMD": {
+ "value": 4998
+ }
+ }
+ },
+ "Scope": {
+ "type": "ValueEnum",
+ "values": {
+ "CrossDevice": {
+ "value": 0
+ },
+ "Device": {
+ "value": 1
+ },
+ "Workgroup": {
+ "value": 2
+ },
+ "Subgroup": {
+ "value": 3
+ },
+ "Invocation": {
+ "value": 4
+ },
+ "QueueFamily": {
+ "value": 5
+ },
+ "QueueFamilyKHR": {
+ "value": 5
+ }
+ }
+ },
+ "Capability": {
+ "type": "ValueEnum",
+ "values": {
+ "Matrix": {
+ "value": 0
+ },
+ "Shader": {
+ "value": 1
+ },
+ "Geometry": {
+ "value": 2
+ },
+ "Tessellation": {
+ "value": 3
+ },
+ "Addresses": {
+ "value": 4
+ },
+ "Linkage": {
+ "value": 5
+ },
+ "Kernel": {
+ "value": 6
+ },
+ "Float16": {
+ "value": 9
+ },
+ "Float64": {
+ "value": 10
+ },
+ "Int64": {
+ "value": 11
+ },
+ "Groups": {
+ "value": 18
+ },
+ "AtomicStorage": {
+ "value": 21
+ },
+ "Int16": {
+ "value": 22
+ },
+ "ImageGatherExtended": {
+ "value": 25
+ },
+ "StorageImageMultisample": {
+ "value": 27
+ },
+ "UniformBufferArrayDynamicIndexing": {
+ "value": 28
+ },
+ "SampledImageArrayDynamicIndexing": {
+ "value": 29
+ },
+ "StorageBufferArrayDynamicIndexing": {
+ "value": 30
+ },
+ "StorageImageArrayDynamicIndexing": {
+ "value": 31
+ },
+ "ClipDistance": {
+ "value": 32
+ },
+ "CullDistance": {
+ "value": 33
+ },
+ "SampleRateShading": {
+ "value": 35
+ },
+ "SampledRect": {
+ "value": 37
+ },
+ "Int8": {
+ "value": 39
+ },
+ "InputAttachment": {
+ "value": 40
+ },
+ "SparseResidency": {
+ "value": 41
+ },
+ "MinLod": {
+ "value": 42
+ },
+ "Sampled1D": {
+ "value": 43
+ },
+ "Image1D": {
+ "value": 44
+ },
+ "SampledCubeArray": {
+ "value": 45
+ },
+ "SampledBuffer": {
+ "value": 46
+ },
+ "ImageMSArray": {
+ "value": 48
+ },
+ "StorageImageExtendedFormats": {
+ "value": 49
+ },
+ "ImageQuery": {
+ "value": 50
+ },
+ "DerivativeControl": {
+ "value": 51
+ },
+ "InterpolationFunction": {
+ "value": 52
+ },
+ "TransformFeedback": {
+ "value": 53
+ },
+ "StorageImageReadWithoutFormat": {
+ "value": 55
+ },
+ "StorageImageWriteWithoutFormat": {
+ "value": 56
+ },
+ "GroupNonUniform": {
+ "value": 61
+ },
+ "ShaderLayer": {
+ "value": 69
+ },
+ "ShaderViewportIndex": {
+ "value": 70
+ },
+ "SubgroupBallotKHR": {
+ "value": 4423
+ },
+ "DrawParameters": {
+ "value": 4427
+ },
+ "SubgroupVoteKHR": {
+ "value": 4431
+ },
+ "StorageBuffer16BitAccess": {
+ "value": 4433
+ },
+ "StorageUniformBufferBlock16": {
+ "value": 4433
+ },
+ "StoragePushConstant16": {
+ "value": 4435
+ },
+ "StorageInputOutput16": {
+ "value": 4436
+ },
+ "DeviceGroup": {
+ "value": 4437
+ },
+ "MultiView": {
+ "value": 4439
+ },
+ "VariablePointersStorageBuffer": {
+ "value": 4441
+ },
+ "AtomicStorageOps": {
+ "value": 4445
+ },
+ "SampleMaskPostDepthCoverage": {
+ "value": 4447
+ },
+ "StorageBuffer8BitAccess": {
+ "value": 4448
+ },
+ "StoragePushConstant8": {
+ "value": 4450
+ },
+ "DenormPreserve": {
+ "value": 4464
+ },
+ "DenormFlushToZero": {
+ "value": 4465
+ },
+ "SignedZeroInfNanPreserve": {
+ "value": 4466
+ },
+ "RoundingModeRTE": {
+ "value": 4467
+ },
+ "RoundingModeRTZ": {
+ "value": 4468
+ },
+ "Float16ImageAMD": {
+ "value": 5008
+ },
+ "ImageGatherBiasLodAMD": {
+ "value": 5009
+ },
+ "FragmentMaskAMD": {
+ "value": 5010
+ },
+ "StencilExportEXT": {
+ "value": 5013
+ },
+ "ImageReadWriteLodAMD": {
+ "value": 5015
+ },
+ "ShaderClockKHR": {
+ "value": 5055
+ },
+ "FragmentFullyCoveredEXT": {
+ "value": 5265
+ },
+ "MeshShadingNV": {
+ "value": 5266
+ },
+ "ImageFootprintNV": {
+ "value": 5282
+ },
+ "FragmentBarycentricNV": {
+ "value": 5284
+ },
+ "ComputeDerivativeGroupQuadsNV": {
+ "value": 5288
+ },
+ "FragmentDensityEXT": {
+ "value": 5291
+ },
+ "ShadingRateNV": {
+ "value": 5291
+ },
+ "GroupNonUniformPartitionedNV": {
+ "value": 5297
+ },
+ "ShaderNonUniform": {
+ "value": 5301
+ },
+ "ShaderNonUniformEXT": {
+ "value": 5301
+ },
+ "RuntimeDescriptorArray": {
+ "value": 5302
+ },
+ "RuntimeDescriptorArrayEXT": {
+ "value": 5302
+ },
+ "RayTracingNV": {
+ "value": 5340
+ },
+ "VulkanMemoryModel": {
+ "value": 5345
+ },
+ "VulkanMemoryModelKHR": {
+ "value": 5345
+ },
+ "VulkanMemoryModelDeviceScope": {
+ "value": 5346
+ },
+ "VulkanMemoryModelDeviceScopeKHR": {
+ "value": 5346
+ },
+ "PhysicalStorageBufferAddresses": {
+ "value": 5347
+ },
+ "PhysicalStorageBufferAddressesEXT": {
+ "value": 5347
+ },
+ "ComputeDerivativeGroupLinearNV": {
+ "value": 5350
+ },
+ "CooperativeMatrixNV": {
+ "value": 5357
+ },
+ "FragmentShaderSampleInterlockEXT": {
+ "value": 5363
+ },
+ "FragmentShaderShadingRateInterlockEXT": {
+ "value": 5372
+ },
+ "ShaderSMBuiltinsNV": {
+ "value": 5373
+ },
+ "FragmentShaderPixelInterlockEXT": {
+ "value": 5378
+ },
+ "DemoteToHelperInvocationEXT": {
+ "value": 5379
+ },
+ "SubgroupShuffleINTEL": {
+ "value": 5568
+ },
+ "SubgroupBufferBlockIOINTEL": {
+ "value": 5569
+ },
+ "SubgroupImageBlockIOINTEL": {
+ "value": 5570
+ },
+ "SubgroupImageMediaBlockIOINTEL": {
+ "value": 5579
+ },
+ "IntegerFunctions2INTEL": {
+ "value": 5584
+ },
+ "SubgroupAvcMotionEstimationINTEL": {
+ "value": 5696
+ },
+ "SubgroupAvcMotionEstimationIntraINTEL": {
+ "value": 5697
+ },
+ "SubgroupAvcMotionEstimationChromaINTEL": {
+ "value": 5698
+ }
+ }
+ }
+ },
+ "ext": {
+ "Round": 1,
+ "RoundEven": 2,
+ "Trunc": 3,
+ "FAbs": 4,
+ "SAbs": 5,
+ "FSign": 6,
+ "SSign": 7,
+ "Floor": 8,
+ "Ceil": 9,
+ "Fract": 10,
+ "Radians": 11,
+ "Degrees": 12,
+ "Sin": 13,
+ "Cos": 14,
+ "Tan": 15,
+ "Asin": 16,
+ "Acos": 17,
+ "Atan": 18,
+ "Sinh": 19,
+ "Cosh": 20,
+ "Tanh": 21,
+ "Asinh": 22,
+ "Acosh": 23,
+ "Atanh": 24,
+ "Atan2": 25,
+ "Pow": 26,
+ "Exp": 27,
+ "Log": 28,
+ "Exp2": 29,
+ "Log2": 30,
+ "Sqrt": 31,
+ "InverseSqrt": 32,
+ "Determinant": 33,
+ "MatrixInverse": 34,
+ "Modf": 35,
+ "ModfStruct": 36,
+ "FMin": 37,
+ "UMin": 38,
+ "SMin": 39,
+ "FMax": 40,
+ "UMax": 41,
+ "SMax": 42,
+ "FClamp": 43,
+ "UClamp": 44,
+ "SClamp": 45,
+ "FMix": 46,
+ "IMix": 47,
+ "Step": 48,
+ "SmoothStep": 49,
+ "Fma": 50,
+ "Frexp": 51,
+ "FrexpStruct": 52,
+ "Ldexp": 53,
+ "PackSnorm4x8": 54,
+ "PackUnorm4x8": 55,
+ "PackSnorm2x16": 56,
+ "PackUnorm2x16": 57,
+ "PackHalf2x16": 58,
+ "PackDouble2x32": 59,
+ "UnpackSnorm2x16": 60,
+ "UnpackUnorm2x16": 61,
+ "UnpackHalf2x16": 62,
+ "UnpackSnorm4x8": 63,
+ "UnpackUnorm4x8": 64,
+ "UnpackDouble2x32": 65,
+ "Length": 66,
+ "Distance": 67,
+ "Cross": 68,
+ "Normalize": 69,
+ "FaceForward": 70,
+ "Reflect": 71,
+ "Refract": 72,
+ "FindILsb": 73,
+ "FindSMsb": 74,
+ "FindUMsb": 75,
+ "InterpolateAtCentroid": 76,
+ "InterpolateAtSample": 77,
+ "InterpolateAtOffset": 78,
+ "NMin": 79,
+ "NMax": 80,
+ "NClamp": 81
+ }
+}
diff --git a/tools/sva/src/sva.js b/tools/sva/src/sva.js
new file mode 100644
index 0000000..c76ed29
--- /dev/null
+++ b/tools/sva/src/sva.js
@@ -0,0 +1,40 @@
+// Copyright 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.
+
+import Parser from "./parser.js";
+import Lexer from "./lexer.js";
+import Assembler from "./assembler.js";
+
+import grammar from "./spirv.data.js";
+
+export default class SVA {
+ /**
+ * Attempts to convert |input| SPIR-V assembly into SPIR-V binary.
+ *
+ * @param {String} the input string containing the assembly
+ * @return {Uint32Array|string} returns a Uint32Array containing the binary
+ * SPIR-V or a string on error.
+ */
+ static assemble(input) {
+ let l = new Lexer(input);
+ let p = new Parser(grammar, l);
+
+ let ast = p.parse();
+ if (ast === undefined)
+ return p.error;
+
+ let a = new Assembler(ast);
+ return a.assemble();
+ }
+}
diff --git a/tools/sva/src/token.js b/tools/sva/src/token.js
new file mode 100644
index 0000000..3813191
--- /dev/null
+++ b/tools/sva/src/token.js
@@ -0,0 +1,55 @@
+// Copyright 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.
+
+const TokenType = {
+ kEOF: "end of file",
+ kError: "error",
+
+ kIdentifier: "identifier",
+
+ kIntegerLiteral: "integer_literal",
+ kFloatLiteral: "float_literal",
+ kStringLiteral: "string_literal",
+ kResultId: "result_id",
+
+ kOp: "Op",
+ kEqual: "=",
+ kPipe: "|",
+};
+
+class Token {
+ /**
+ * @param {TokenType} type The type of token
+ * @param {Integer} line The line number this token was on
+ * @param {Any} data Data attached to the token
+ * @param {Integer} bits If the type is a float or integer the bit width
+ */
+ constructor(type, line, data) {
+ this.type_ = type;
+ this.line_ = line;
+ this.data_ = data;
+ this.bits_ = 0;
+ }
+
+ get type() { return this.type_; }
+ get line() { return this.line_; }
+
+ get data() { return this.data_; }
+ set data(val) { this.data_ = val; }
+
+ get bits() { return this.bits_; }
+ set bits(val) { this.bits_ = val; }
+}
+
+export {Token, TokenType};
diff --git a/tools/sva/tests/empty_main.spv_asm b/tools/sva/tests/empty_main.spv_asm
new file mode 100644
index 0000000..ad6e64b
--- /dev/null
+++ b/tools/sva/tests/empty_main.spv_asm
@@ -0,0 +1,18 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 6
+; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 440
+ OpName %main "main"
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/tools/sva/tests/index.html b/tools/sva/tests/index.html
new file mode 100644
index 0000000..dd02847
--- /dev/null
+++ b/tools/sva/tests/index.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset='utf-8'>
+</head>
+<body>
+ <pre id='code'><code></code></pre>
+
+ <script type="module">
+ let c = document.getElementById('code');
+
+ import SVA from "/build/sva.js";
+
+ let assembly = SVA.assemble("OpCapability Shader");
+ if (typeof assembly === "string") {
+ c.innerText = assembly;
+ } else {
+ c.innerText = Array.from(assembly)
+ .map(b => b.toString(16).padStart(8, "0")).join(" ");
+ }
+ </script>
+</body>
+</html>
diff --git a/tools/sva/tests/simple.spv_asm b/tools/sva/tests/simple.spv_asm
new file mode 100644
index 0000000..b4b3f67
--- /dev/null
+++ b/tools/sva/tests/simple.spv_asm
@@ -0,0 +1,30 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 14
+; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %gl_FragColor
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 330
+ OpName %main "main"
+ OpName %gl_FragColor "gl_FragColor"
+ OpDecorate %gl_FragColor Location 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%gl_FragColor = OpVariable %_ptr_Output_v4float Output
+%float_0_400000006 = OpConstant %float 0.400000006
+%float_0_800000012 = OpConstant %float 0.800000012
+ %float_1 = OpConstant %float 1
+ %13 = OpConstantComposite %v4float %float_0_400000006 %float_0_400000006 %float_0_800000012 %float_1
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpStore %gl_FragColor %13
+ OpReturn
+ OpFunctionEnd
+
diff --git a/tools/sva/tools/process_grammar.rb b/tools/sva/tools/process_grammar.rb
new file mode 100755
index 0000000..1bbff68
--- /dev/null
+++ b/tools/sva/tools/process_grammar.rb
@@ -0,0 +1,119 @@
+#!/usr/bin/env ruby
+
+# Copyright 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.
+
+require 'json'
+
+GRAMMAR = "../../external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json"
+GLSL = "../../external/spirv-headers/include/spirv/unified1/extinst.glsl.std.450.grammar.json"
+
+CAPABILITIES = %w(
+ Matrix
+ Shader
+ Sampled1D
+ Image1D
+ DerivativeControl
+ ImageQuery
+ VulkanMemoryModel
+)
+
+g = JSON.parse(File.open(GRAMMAR).read)
+magic = g['magic_number']
+vers = [g['major_version'], g['minor_version']]
+instructions = {}
+
+g['instructions'].each do |inst|
+ if (inst.has_key?('capabilities'))
+ skip = true
+ inst['capabilities'].each do |cap|
+ if CAPABILITIES.include?(cap)
+ skip = false
+ break
+ end
+ end
+ next if skip
+ end
+
+ op = {
+ opcode: inst['opcode'],
+ operands: []
+ }
+
+ if !inst['operands'].nil?
+ inst['operands'].each do |operand|
+ operand.delete('name')
+ op[:operands] << operand
+ end
+ end
+
+ instructions[inst['opname']] = op
+end
+
+operand_kinds = {}
+g['operand_kinds'].each do |op_kind|
+ next if op_kind['category'] !~ /Enum/
+
+ kind = {
+ type: op_kind['category'],
+ values: {}
+ }
+
+ op_kind['enumerants'].each do |enum|
+ if (enum.has_key?('capabilities'))
+ skip = true
+ enum['capabilities'].each do |cap|
+ if CAPABILITIES.include?(cap)
+ skip = false
+ break
+ end
+ end
+ next if skip
+ end
+
+ v = if op_kind['category'] == 'BitEnum'
+ enum['value'].to_i(16)
+ else
+ enum['value'].to_i
+ end
+ params = []
+ if enum.has_key?('parameters')
+ enum['parameters'].each do |param|
+ params << param['kind']
+ end
+ end
+ kind[:values][enum['enumerant']] = {value: v}
+ kind[:values][enum['enumerant']][:params] = params unless params.empty?
+ end
+
+ next if kind[:values].empty?
+ operand_kinds[op_kind['kind']] = kind
+end
+
+# We only support GLSL extensions at the moment.
+ext = {}
+glsl = JSON.parse(File.open(GLSL).read)
+glsl['instructions'].each do |inst|
+ ext[inst['opname']] = inst['opcode']
+end
+
+puts "/*#{g['copyright'].join("\n")}*/"
+puts "\n// THIS FILE IS GENERATED WITH tools/process_grammar.rb\n\n"
+puts "export default " + JSON.pretty_generate({
+ magic: magic,
+ version: vers,
+ instructions: instructions,
+ operand_kinds: operand_kinds,
+ ext: ext
+})
diff --git a/tools/sva/yarn.lock b/tools/sva/yarn.lock
new file mode 100644
index 0000000..be19e7c
--- /dev/null
+++ b/tools/sva/yarn.lock
@@ -0,0 +1,1778 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@^7.0.0":
+ version "7.5.5"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
+ integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==
+ dependencies:
+ "@babel/highlight" "^7.0.0"
+
+"@babel/highlight@^7.0.0":
+ version "7.5.0"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540"
+ integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==
+ dependencies:
+ chalk "^2.0.0"
+ esutils "^2.0.2"
+ js-tokens "^4.0.0"
+
+"@types/estree@0.0.39":
+ version "0.0.39"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
+ integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+
+"@types/node@^12.7.5":
+ version "12.7.5"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.5.tgz#e19436e7f8e9b4601005d73673b6dc4784ffcc2f"
+ integrity sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==
+
+"@zeit/schemas@2.6.0":
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.6.0.tgz#004e8e553b4cd53d538bd38eac7bcbf58a867fe3"
+ integrity sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==
+
+accepts@~1.3.5:
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
+ integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+ dependencies:
+ mime-types "~2.1.24"
+ negotiator "0.6.2"
+
+acorn-jsx@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f"
+ integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==
+
+acorn@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a"
+ integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==
+
+ajv@6.5.3:
+ version "6.5.3"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9"
+ integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==
+ dependencies:
+ fast-deep-equal "^2.0.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ajv@^6.10.0, ajv@^6.10.2:
+ version "6.10.2"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
+ integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
+ dependencies:
+ fast-deep-equal "^2.0.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ansi-align@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
+ integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
+ dependencies:
+ string-width "^2.0.0"
+
+ansi-colors@3.2.3:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
+ integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
+
+ansi-escapes@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
+ integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+ integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+
+ansi-regex@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
+ integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
+
+ansi-styles@^3.2.0, ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+arch@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e"
+ integrity sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg==
+
+arg@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/arg/-/arg-2.0.0.tgz#c06e7ff69ab05b3a4a03ebe0407fac4cba657545"
+ integrity sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+assertion-error@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
+ integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
+
+astral-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
+ integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
+
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+ integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+boxen@1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
+ integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
+ dependencies:
+ ansi-align "^2.0.0"
+ camelcase "^4.0.0"
+ chalk "^2.0.1"
+ cli-boxes "^1.0.0"
+ string-width "^2.0.0"
+ term-size "^1.2.0"
+ widest-line "^2.0.0"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+browser-stdout@1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
+ integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
+
+bytes@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
+ integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
+
+callsites@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camelcase@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
+ integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
+
+camelcase@^5.0.0:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+chai@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5"
+ integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==
+ dependencies:
+ assertion-error "^1.1.0"
+ check-error "^1.0.2"
+ deep-eql "^3.0.1"
+ get-func-name "^2.0.0"
+ pathval "^1.1.0"
+ type-detect "^4.0.5"
+
+chalk@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
+ integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+chardet@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+ integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
+check-error@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
+ integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
+
+cli-boxes@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
+ integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
+
+cli-cursor@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
+ integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
+ dependencies:
+ restore-cursor "^2.0.0"
+
+cli-width@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
+ integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+
+clipboardy@1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef"
+ integrity sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==
+ dependencies:
+ arch "^2.1.0"
+ execa "^0.8.0"
+
+cliui@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
+ integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==
+ dependencies:
+ string-width "^2.1.1"
+ strip-ansi "^4.0.0"
+ wrap-ansi "^2.0.0"
+
+code-point-at@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+ integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
+
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+compressible@~2.0.14:
+ version "2.0.17"
+ resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1"
+ integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==
+ dependencies:
+ mime-db ">= 1.40.0 < 2"
+
+compression@1.7.3:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db"
+ integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==
+ dependencies:
+ accepts "~1.3.5"
+ bytes "3.0.0"
+ compressible "~2.0.14"
+ debug "2.6.9"
+ on-headers "~1.0.1"
+ safe-buffer "5.1.2"
+ vary "~1.1.2"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+content-disposition@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
+ integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
+
+cross-spawn@^5.0.1:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
+ integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
+ dependencies:
+ lru-cache "^4.0.1"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
+cross-spawn@^6.0.0, cross-spawn@^6.0.5:
+ version "6.0.5"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
+ integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
+ dependencies:
+ nice-try "^1.0.4"
+ path-key "^2.0.1"
+ semver "^5.5.0"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
+debug@2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@3.2.6:
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
+ integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+ dependencies:
+ ms "^2.1.1"
+
+debug@^4.0.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
+ integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+ dependencies:
+ ms "^2.1.1"
+
+decamelize@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+ integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+deep-eql@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
+ integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==
+ dependencies:
+ type-detect "^4.0.0"
+
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+deep-is@~0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+ integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
+
+define-properties@^1.1.2, define-properties@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+ integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+ dependencies:
+ object-keys "^1.0.12"
+
+diff@3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
+ integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+
+doctrine@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+ dependencies:
+ esutils "^2.0.2"
+
+emoji-regex@^7.0.1:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
+ integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+
+end-of-stream@^1.1.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
+ integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
+ dependencies:
+ once "^1.4.0"
+
+es-abstract@^1.5.1:
+ version "1.14.2"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497"
+ integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==
+ dependencies:
+ es-to-primitive "^1.2.0"
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.0"
+ is-callable "^1.1.4"
+ is-regex "^1.0.4"
+ object-inspect "^1.6.0"
+ object-keys "^1.1.1"
+ string.prototype.trimleft "^2.0.0"
+ string.prototype.trimright "^2.0.0"
+
+es-to-primitive@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377"
+ integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==
+ dependencies:
+ is-callable "^1.1.4"
+ is-date-object "^1.0.1"
+ is-symbol "^1.0.2"
+
+escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+eslint-scope@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9"
+ integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint-utils@^1.4.2:
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab"
+ integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==
+ dependencies:
+ eslint-visitor-keys "^1.0.0"
+
+eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
+ integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
+
+eslint@^6.3.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.4.0.tgz#5aa9227c3fbe921982b2eda94ba0d7fae858611a"
+ integrity sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ ajv "^6.10.0"
+ chalk "^2.1.0"
+ cross-spawn "^6.0.5"
+ debug "^4.0.1"
+ doctrine "^3.0.0"
+ eslint-scope "^5.0.0"
+ eslint-utils "^1.4.2"
+ eslint-visitor-keys "^1.1.0"
+ espree "^6.1.1"
+ esquery "^1.0.1"
+ esutils "^2.0.2"
+ file-entry-cache "^5.0.1"
+ functional-red-black-tree "^1.0.1"
+ glob-parent "^5.0.0"
+ globals "^11.7.0"
+ ignore "^4.0.6"
+ import-fresh "^3.0.0"
+ imurmurhash "^0.1.4"
+ inquirer "^6.4.1"
+ is-glob "^4.0.0"
+ js-yaml "^3.13.1"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.3.0"
+ lodash "^4.17.14"
+ minimatch "^3.0.4"
+ mkdirp "^0.5.1"
+ natural-compare "^1.4.0"
+ optionator "^0.8.2"
+ progress "^2.0.0"
+ regexpp "^2.0.1"
+ semver "^6.1.2"
+ strip-ansi "^5.2.0"
+ strip-json-comments "^3.0.1"
+ table "^5.2.3"
+ text-table "^0.2.0"
+ v8-compile-cache "^2.0.3"
+
+esm@^3.2.25:
+ version "3.2.25"
+ resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
+ integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
+
+espree@^6.1.1:
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de"
+ integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==
+ dependencies:
+ acorn "^7.0.0"
+ acorn-jsx "^5.0.2"
+ eslint-visitor-keys "^1.1.0"
+
+esprima@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esquery@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
+ integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
+ dependencies:
+ estraverse "^4.0.0"
+
+esrecurse@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+ integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
+ dependencies:
+ estraverse "^4.1.0"
+
+estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+esutils@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+ integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+execa@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
+ integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
+execa@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da"
+ integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
+execa@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
+ integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
+ dependencies:
+ cross-spawn "^6.0.0"
+ get-stream "^4.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
+external-editor@^3.0.3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+ integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
+ dependencies:
+ chardet "^0.7.0"
+ iconv-lite "^0.4.24"
+ tmp "^0.0.33"
+
+fast-deep-equal@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
+ integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
+ integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
+
+fast-levenshtein@~2.0.4:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+
+fast-url-parser@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d"
+ integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=
+ dependencies:
+ punycode "^1.3.2"
+
+figures@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
+ integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
+ dependencies:
+ escape-string-regexp "^1.0.5"
+
+file-entry-cache@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
+ integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
+ dependencies:
+ flat-cache "^2.0.1"
+
+find-up@3.0.0, find-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+ integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+ dependencies:
+ locate-path "^3.0.0"
+
+flat-cache@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
+ integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
+ dependencies:
+ flatted "^2.0.0"
+ rimraf "2.6.3"
+ write "1.0.3"
+
+flat@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2"
+ integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==
+ dependencies:
+ is-buffer "~2.0.3"
+
+flatted@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
+ integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+function-bind@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+ integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+functional-red-black-tree@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
+ integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
+
+get-caller-file@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
+ integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
+
+get-caller-file@^2.0.1:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-func-name@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
+ integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
+
+get-stream@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+ integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
+
+get-stream@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
+ integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
+ dependencies:
+ pump "^3.0.0"
+
+glob-parent@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954"
+ integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob@7.1.3:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
+ integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^7.1.3:
+ version "7.1.4"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
+ integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+globals@^11.7.0:
+ version "11.12.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+growl@1.10.5:
+ version "1.10.5"
+ resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
+ integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
+ integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
+
+has@^1.0.1, has@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+ dependencies:
+ function-bind "^1.1.1"
+
+he@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+ integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+iconv-lite@^0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+ignore@^4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+ integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+
+import-fresh@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118"
+ integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ 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==
+
+inquirer@^6.4.1:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca"
+ integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==
+ dependencies:
+ ansi-escapes "^3.2.0"
+ chalk "^2.4.2"
+ cli-cursor "^2.1.0"
+ cli-width "^2.0.0"
+ external-editor "^3.0.3"
+ figures "^2.0.0"
+ lodash "^4.17.12"
+ mute-stream "0.0.7"
+ run-async "^2.2.0"
+ rxjs "^6.4.0"
+ string-width "^2.1.0"
+ strip-ansi "^5.1.0"
+ through "^2.3.6"
+
+invert-kv@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
+ integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
+
+is-buffer@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
+ integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
+
+is-callable@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
+ integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
+
+is-date-object@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
+ integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-fullwidth-code-point@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+ integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+ integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+
+is-glob@^4.0.0, is-glob@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
+ integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-promise@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
+ integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
+
+is-regex@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
+ integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=
+ dependencies:
+ has "^1.0.1"
+
+is-stream@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+ integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+
+is-symbol@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
+ integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==
+ dependencies:
+ has-symbols "^1.0.0"
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@3.13.1, js-yaml@^3.13.1:
+ version "3.13.1"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
+ integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+
+lcid@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
+ integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==
+ dependencies:
+ invert-kv "^2.0.0"
+
+levn@^0.3.0, levn@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+ integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
+ dependencies:
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+
+locate-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+ integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
+ dependencies:
+ p-locate "^3.0.0"
+ path-exists "^3.0.0"
+
+lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14:
+ version "4.17.15"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
+ integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
+
+log-symbols@2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
+ integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
+ dependencies:
+ chalk "^2.0.1"
+
+lru-cache@^4.0.1:
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
+ integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
+ dependencies:
+ pseudomap "^1.0.2"
+ yallist "^2.1.2"
+
+map-age-cleaner@^0.1.1:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
+ integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
+ dependencies:
+ p-defer "^1.0.0"
+
+mem@^4.0.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
+ integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==
+ dependencies:
+ map-age-cleaner "^0.1.1"
+ mimic-fn "^2.0.0"
+ p-is-promise "^2.0.0"
+
+mime-db@1.40.0:
+ version "1.40.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
+ integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
+
+"mime-db@>= 1.40.0 < 2":
+ version "1.41.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.41.0.tgz#9110408e1f6aa1b34aef51f2c9df3caddf46b6a0"
+ integrity sha512-B5gxBI+2K431XW8C2rcc/lhppbuji67nf9v39eH8pkWoZDxnAL0PxdpH32KYRScniF8qDHBDlI+ipgg5WrCUYw==
+
+mime-db@~1.33.0:
+ version "1.33.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
+ integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==
+
+mime-types@2.1.18:
+ version "2.1.18"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
+ integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==
+ dependencies:
+ mime-db "~1.33.0"
+
+mime-types@~2.1.24:
+ version "2.1.24"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
+ integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
+ dependencies:
+ mime-db "1.40.0"
+
+mimic-fn@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
+ integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+
+mimic-fn@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+minimatch@3.0.4, minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimist@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+ integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+
+minimist@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+ integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+
+mkdirp@0.5.1, mkdirp@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+ dependencies:
+ minimist "0.0.8"
+
+mocha@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.0.tgz#f896b642843445d1bb8bca60eabd9206b8916e56"
+ integrity sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==
+ dependencies:
+ ansi-colors "3.2.3"
+ browser-stdout "1.3.1"
+ debug "3.2.6"
+ diff "3.5.0"
+ escape-string-regexp "1.0.5"
+ find-up "3.0.0"
+ glob "7.1.3"
+ growl "1.10.5"
+ he "1.2.0"
+ js-yaml "3.13.1"
+ log-symbols "2.2.0"
+ minimatch "3.0.4"
+ mkdirp "0.5.1"
+ ms "2.1.1"
+ node-environment-flags "1.0.5"
+ object.assign "4.1.0"
+ strip-json-comments "2.0.1"
+ supports-color "6.0.0"
+ which "1.3.1"
+ wide-align "1.1.3"
+ yargs "13.2.2"
+ yargs-parser "13.0.0"
+ yargs-unparser "1.5.0"
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+ integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
+ms@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+mute-stream@0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
+ integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
+
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
+
+negotiator@0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
+ integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+
+nice-try@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
+ integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+
+node-environment-flags@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a"
+ integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==
+ dependencies:
+ object.getownpropertydescriptors "^2.0.3"
+ semver "^5.7.0"
+
+npm-run-path@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+ integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
+ dependencies:
+ path-key "^2.0.0"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+ integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+
+object-inspect@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b"
+ integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==
+
+object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object.assign@4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+ integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+ dependencies:
+ define-properties "^1.1.2"
+ function-bind "^1.1.1"
+ has-symbols "^1.0.0"
+ object-keys "^1.0.11"
+
+object.getownpropertydescriptors@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
+ integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.5.1"
+
+on-headers@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
+ integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+ dependencies:
+ wrappy "1"
+
+onetime@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
+ integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
+ dependencies:
+ mimic-fn "^1.0.0"
+
+optionator@^0.8.2:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+ integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=
+ dependencies:
+ deep-is "~0.1.3"
+ fast-levenshtein "~2.0.4"
+ levn "~0.3.0"
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+ wordwrap "~1.0.0"
+
+os-locale@^3.0.0, os-locale@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
+ integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
+ dependencies:
+ execa "^1.0.0"
+ lcid "^2.0.0"
+ mem "^4.0.0"
+
+os-tmpdir@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+ integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
+
+p-defer@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
+ integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
+
+p-finally@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+ integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
+
+p-is-promise@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
+ integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
+
+p-limit@^2.0.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537"
+ integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==
+ dependencies:
+ p-try "^2.0.0"
+
+p-locate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+ integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+ dependencies:
+ p-limit "^2.0.0"
+
+p-try@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
+path-exists@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+ integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-is-inside@1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+ integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+
+path-key@^2.0.0, path-key@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+ integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+
+path-to-regexp@2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45"
+ integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==
+
+pathval@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
+ integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA=
+
+prelude-ls@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+ integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
+
+progress@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+ integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
+pseudomap@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+ integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
+
+pump@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+punycode@^1.3.2:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+ integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
+
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+ integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+range-parser@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
+ integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
+
+rc@^1.0.1, rc@^1.1.6:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+regexpp@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
+ integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
+
+registry-auth-token@3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20"
+ integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==
+ dependencies:
+ rc "^1.1.6"
+ safe-buffer "^5.0.1"
+
+registry-url@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
+ integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
+ dependencies:
+ rc "^1.0.1"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+
+require-main-filename@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+ integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
+
+require-main-filename@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
+ integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+restore-cursor@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
+ integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
+ dependencies:
+ onetime "^2.0.0"
+ signal-exit "^3.0.2"
+
+rimraf@2.6.3:
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+ integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+ dependencies:
+ glob "^7.1.3"
+
+rollup@^1.21.4:
+ version "1.21.4"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.21.4.tgz#00a41a30f90095db890301b226cbe2918e4cf54d"
+ integrity sha512-Pl512XVCmVzgcBz5h/3Li4oTaoDcmpuFZ+kdhS/wLreALz//WuDAMfomD3QEYl84NkDu6Z6wV9twlcREb4qQsw==
+ dependencies:
+ "@types/estree" "0.0.39"
+ "@types/node" "^12.7.5"
+ acorn "^7.0.0"
+
+run-async@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
+ integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
+ dependencies:
+ is-promise "^2.1.0"
+
+rxjs@^6.4.0:
+ version "6.5.3"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a"
+ integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==
+ dependencies:
+ tslib "^1.9.0"
+
+safe-buffer@5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-buffer@^5.0.1:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
+ integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+
+"safer-buffer@>= 2.1.2 < 3":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+semver@^5.5.0, semver@^5.7.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+ integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
+semver@^6.1.2:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+ integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+
+serve-handler@6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.0.tgz#f1606dc6ff8f9029a1ee042c11dfe7903a5cb92e"
+ integrity sha512-63N075Tn3PsFYcu0NVV7tb367UbiW3gnC+/50ohL4oqOhAG6bmbaWqiRcXQgbzqc0ALBjSAzg7VTfa0Qw4E3hA==
+ dependencies:
+ bytes "3.0.0"
+ content-disposition "0.5.2"
+ fast-url-parser "1.1.3"
+ mime-types "2.1.18"
+ minimatch "3.0.4"
+ path-is-inside "1.0.2"
+ path-to-regexp "2.2.1"
+ range-parser "1.2.0"
+
+serve@^11.1.0:
+ version "11.1.0"
+ resolved "https://registry.yarnpkg.com/serve/-/serve-11.1.0.tgz#1bfe2f4a08d0130cbf44711cdb7996cb742172e0"
+ integrity sha512-+4wpDtOSS+4ZLyDWMxThutA3iOTawX2+yDovOI8cjOUOmemyvNlHyFAsezBlSgbZKTYChI3tzA1Mh0z6XZ62qA==
+ dependencies:
+ "@zeit/schemas" "2.6.0"
+ ajv "6.5.3"
+ arg "2.0.0"
+ boxen "1.3.0"
+ chalk "2.4.1"
+ clipboardy "1.2.3"
+ compression "1.7.3"
+ serve-handler "6.1.0"
+ update-check "1.5.2"
+
+set-blocking@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+ integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+
+shebang-command@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+ integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
+ dependencies:
+ shebang-regex "^1.0.0"
+
+shebang-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+ integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+
+signal-exit@^3.0.0, signal-exit@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+ integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+
+slice-ansi@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
+ integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
+ dependencies:
+ ansi-styles "^3.2.0"
+ astral-regex "^1.0.0"
+ is-fullwidth-code-point "^2.0.0"
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
+string-width@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+ integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ strip-ansi "^3.0.0"
+
+"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+ integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^4.0.0"
+
+string-width@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
+ integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
+ dependencies:
+ emoji-regex "^7.0.1"
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^5.1.0"
+
+string.prototype.trimleft@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634"
+ integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==
+ dependencies:
+ define-properties "^1.1.3"
+ function-bind "^1.1.1"
+
+string.prototype.trimright@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58"
+ integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==
+ dependencies:
+ define-properties "^1.1.3"
+ function-bind "^1.1.1"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+ integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+ dependencies:
+ ansi-regex "^3.0.0"
+
+strip-ansi@^5.1.0, strip-ansi@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
+ integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+ dependencies:
+ ansi-regex "^4.1.0"
+
+strip-eof@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+ integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+
+strip-json-comments@2.0.1, strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+ integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+
+strip-json-comments@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
+ integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==
+
+supports-color@6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a"
+ integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^5.3.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+table@^5.2.3:
+ version "5.4.6"
+ resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
+ integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==
+ dependencies:
+ ajv "^6.10.2"
+ lodash "^4.17.14"
+ slice-ansi "^2.1.0"
+ string-width "^3.0.0"
+
+term-size@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
+ integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
+ dependencies:
+ execa "^0.7.0"
+
+text-table@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+
+through@^2.3.6:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+ integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
+
+tmp@^0.0.33:
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+ integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+ dependencies:
+ os-tmpdir "~1.0.2"
+
+tslib@^1.9.0:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
+ integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
+
+type-check@~0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+ integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
+ dependencies:
+ prelude-ls "~1.1.2"
+
+type-detect@^4.0.0, type-detect@^4.0.5:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
+ integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+
+update-check@1.5.2:
+ version "1.5.2"
+ resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.2.tgz#2fe09f725c543440b3d7dabe8971f2d5caaedc28"
+ integrity sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==
+ dependencies:
+ registry-auth-token "3.3.2"
+ registry-url "3.1.0"
+
+uri-js@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+ integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ dependencies:
+ punycode "^2.1.0"
+
+v8-compile-cache@^2.0.3:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
+ integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
+
+vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+
+which-module@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
+ integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
+
+which@1.3.1, which@^1.2.9:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ dependencies:
+ isexe "^2.0.0"
+
+wide-align@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+ integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+ dependencies:
+ string-width "^1.0.2 || 2"
+
+widest-line@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
+ integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
+ dependencies:
+ string-width "^2.1.1"
+
+wordwrap@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+ integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
+
+wrap-ansi@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+ integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+write@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
+ integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
+ dependencies:
+ mkdirp "^0.5.1"
+
+"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
+ integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
+
+yallist@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+ integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
+
+yargs-parser@13.0.0:
+ version "13.0.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b"
+ integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
+yargs-parser@^11.1.1:
+ version "11.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
+ integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
+yargs-parser@^13.0.0:
+ version "13.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
+ integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
+yargs-unparser@1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d"
+ integrity sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==
+ dependencies:
+ flat "^4.1.0"
+ lodash "^4.17.11"
+ yargs "^12.0.5"
+
+yargs@13.2.2:
+ version "13.2.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993"
+ integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==
+ dependencies:
+ cliui "^4.0.0"
+ find-up "^3.0.0"
+ get-caller-file "^2.0.1"
+ os-locale "^3.1.0"
+ require-directory "^2.1.1"
+ require-main-filename "^2.0.0"
+ set-blocking "^2.0.0"
+ string-width "^3.0.0"
+ which-module "^2.0.0"
+ y18n "^4.0.0"
+ yargs-parser "^13.0.0"
+
+yargs@^12.0.5:
+ version "12.0.5"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
+ integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
+ dependencies:
+ cliui "^4.0.0"
+ decamelize "^1.2.0"
+ find-up "^3.0.0"
+ get-caller-file "^1.0.1"
+ os-locale "^3.0.0"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^2.0.0"
+ which-module "^2.0.0"
+ y18n "^3.2.1 || ^4.0.0"
+ yargs-parser "^11.1.1"
diff --git a/tools/util/cli_consumer.h b/tools/util/cli_consumer.h
index ca3d91b..64a5e46 100644
--- a/tools/util/cli_consumer.h
+++ b/tools/util/cli_consumer.h
@@ -15,7 +15,7 @@
#ifndef SOURCE_UTIL_CLI_CONSUMMER_H_
#define SOURCE_UTIL_CLI_CONSUMMER_H_
-#include <include/spirv-tools/libspirv.h>
+#include "include/spirv-tools/libspirv.h"
namespace spvtools {
namespace utils {
diff --git a/tools/val/val.cpp b/tools/val/val.cpp
index 6a8542d..19b8c77 100644
--- a/tools/val/val.cpp
+++ b/tools/val/val.cpp
@@ -74,7 +74,7 @@
int main(int argc, char** argv) {
const char* inFile = nullptr;
- spv_target_env target_env = SPV_ENV_UNIVERSAL_1_4;
+ spv_target_env target_env = SPV_ENV_UNIVERSAL_1_5;
spvtools::ValidatorOptions options;
bool continue_processing = true;
int return_code = 0;
@@ -108,12 +108,13 @@
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),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_3),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_4),
+ spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_5),
spvTargetEnvDescription(SPV_ENV_OPENCL_2_2),
spvTargetEnvDescription(SPV_ENV_VULKAN_1_0),
spvTargetEnvDescription(SPV_ENV_VULKAN_1_1),
diff --git a/utils/check_copyright.py b/utils/check_copyright.py
index 5a95e32..cfeef80 100755
--- a/utils/check_copyright.py
+++ b/utils/check_copyright.py
@@ -30,7 +30,8 @@
'LunarG Inc.',
'Google Inc.',
'Google LLC',
- 'Pierre Moreau']
+ 'Pierre Moreau',
+ 'Samsung Inc']
CURRENT_YEAR='2019'
YEARS = '(2014-2016|2015-2016|2016|2016-2017|2017|2018|2019)'
diff --git a/utils/generate_grammar_tables.py b/utils/generate_grammar_tables.py
index 13f392a..ed24bd0 100755
--- a/utils/generate_grammar_tables.py
+++ b/utils/generate_grammar_tables.py
@@ -653,6 +653,30 @@
def precondition_operand_kinds(operand_kinds):
"""For operand kinds that have the same number, make sure they all have the
same extension list."""
+
+ # Map operand kind and value to list of the union of extensions
+ # for same-valued enumerants.
+ exts = {}
+ for kind_entry in operand_kinds:
+ kind = kind_entry.get('kind')
+ for enum_entry in kind_entry.get('enumerants', []):
+ value = enum_entry.get('value')
+ key = kind + '.' + str(value)
+ if key in exts:
+ exts[key].extend(enum_entry.get('extensions', []))
+ else:
+ exts[key] = enum_entry.get('extensions', [])
+ exts[key] = sorted(set(exts[key]))
+
+ # Now make each entry the same list.
+ for kind_entry in operand_kinds:
+ kind = kind_entry.get('kind')
+ for enum_entry in kind_entry.get('enumerants', []):
+ value = enum_entry.get('value')
+ key = kind + '.' + str(value)
+ if len(exts[key]) > 0:
+ enum_entry['extensions'] = exts[key]
+
return operand_kinds
diff --git a/utils/update_build_version.py b/utils/update_build_version.py
index 119bb05..321de74 100755
--- a/utils/update_build_version.py
+++ b/utils/update_build_version.py
@@ -86,7 +86,7 @@
# Linux.
pattern = re.compile(r'^(v\d+\.\d+(-dev)?) \d\d\d\d-\d\d-\d\d\s*$')
changes_file = os.path.join(directory, 'CHANGES')
- with open(changes_file, mode='rU') as f:
+ with open(changes_file, mode='r') as f:
for line in f.readlines():
match = pattern.match(line)
if match:
@@ -116,10 +116,10 @@
# e.g. because the source tree might not be in a git tree.
# In this case, usually use a timestamp. However, to ensure
# reproducible builds, allow the builder to override the wall
- # clock time with enviornment variable SOURCE_DATE_EPOCH
+ # clock time with environment variable SOURCE_DATE_EPOCH
# containing a (presumably) fixed timestamp.
timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))
- formatted = datetime.date.fromtimestamp(timestamp).isoformat()
+ formatted = datetime.datetime.utcfromtimestamp(timestamp).isoformat()
return 'unknown hash, {}'.format(formatted)
diff --git a/utils/vscode/.gitignore b/utils/vscode/.gitignore
new file mode 100644
index 0000000..e934adf
--- /dev/null
+++ b/utils/vscode/.gitignore
@@ -0,0 +1 @@
+cache/
diff --git a/utils/vscode/README.md b/utils/vscode/README.md
new file mode 100644
index 0000000..afbb246
--- /dev/null
+++ b/utils/vscode/README.md
@@ -0,0 +1,7 @@
+# Visual Studio Code extension for SPIR-V disassembly files
+
+This directory holds a Visual Studio Code extension adding syntax highlighting for SPIR-V disassembly files (.spirv)
+
+## Installing (macOS / Linux)
+
+Simply run `install.sh`
diff --git a/utils/vscode/extension.js b/utils/vscode/extension.js
new file mode 100644
index 0000000..f220172
--- /dev/null
+++ b/utils/vscode/extension.js
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+var path = require('path');
+var vscode = require('vscode');
+var langClient = require('vscode-languageclient');
+
+var LanguageClient = langClient.LanguageClient;
+
+// this method is called when your extension is activated
+// your extension is activated the very first time the command is executed
+function activate(context) {
+ let serverModule = path.join(context.extensionPath, 'langsvr');
+ let debugOptions = {};
+
+ // If the extension is launched in debug mode then the debug server options are used
+ // Otherwise the run options are used
+ let serverOptions = {
+ run: { command: serverModule, transport: langClient.stdio },
+ debug: { command: serverModule, transport: langClient.stdio, options: debugOptions }
+ }
+
+ // Options to control the language client
+ let clientOptions = {
+ documentSelector: ['spirv'],
+ synchronize: {
+ // Synchronize the setting section 'spirv' to the server
+ configurationSection: 'spirv',
+ // Notify the server about file changes to .spvasm files contained in the workspace
+ fileEvents: vscode.workspace.createFileSystemWatcher('**/*.spvasm')
+ }
+ }
+
+ // Create the language client and start the client.
+ let disposable = new LanguageClient('spirv', serverOptions, clientOptions).start();
+
+ // Push the disposable to the context's subscriptions so that the
+ // client can be deactivated on extension deactivation
+ context.subscriptions.push(disposable);
+
+ // Set the language configuration here instead of a language configuration
+ // file to work around https://github.com/microsoft/vscode/issues/42649.
+ vscode.languages.setLanguageConfiguration("spirv", {
+ comments: { "lineComment": ";" },
+ wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
+ });
+}
+exports.activate = activate;
+
+// this method is called when your extension is deactivated
+function deactivate() {
+}
+exports.deactivate = deactivate;
\ No newline at end of file
diff --git a/utils/vscode/install.sh b/utils/vscode/install.sh
new file mode 100755
index 0000000..01fc914
--- /dev/null
+++ b/utils/vscode/install.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+# 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.
+
+set -e # Fail on any error.
+
+EXT_PATH=~/.vscode/extensions/google.spirvls-0.0.1
+ROOT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+
+go run ${ROOT_PATH}/src/tools/gen-grammar.go --cache ${ROOT_PATH}/cache --template ${ROOT_PATH}/spirv.json.tmpl --out ${ROOT_PATH}/spirv.json
+go run ${ROOT_PATH}/src/tools/gen-grammar.go --cache ${ROOT_PATH}/cache --template ${ROOT_PATH}/src/schema/schema.go.tmpl --out ${ROOT_PATH}/src/schema/schema.go
+
+mkdir -p ${EXT_PATH}
+cp ${ROOT_PATH}/extension.js ${EXT_PATH}
+cp ${ROOT_PATH}/package.json ${EXT_PATH}
+cp ${ROOT_PATH}/spirv.json ${EXT_PATH}
+
+go build -o ${EXT_PATH}/langsvr ${ROOT_PATH}/src/langsvr.go
+
+cd ${EXT_PATH}
+npm install
diff --git a/utils/vscode/package.json b/utils/vscode/package.json
new file mode 100644
index 0000000..76fb348
--- /dev/null
+++ b/utils/vscode/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "spirvls",
+ "description": "Language support for SPIR-V disassembly files",
+ "author": "Google",
+ "license": "Apache-2.0",
+ "version": "0.0.1",
+ "private": true,
+ "publisher": "Google",
+ "engines": {
+ "vscode": "^0.10.10"
+ },
+ "categories": [
+ "Programming Languages"
+ ],
+ "contributes": {
+ "languages": [
+ {
+ "id": "spirv",
+ "extensions": [
+ "spvasm"
+ ]
+ }
+ ],
+ "grammars": [
+ {
+ "language": "spirv",
+ "scopeName": "source.spirv",
+ "path": "spirv.json"
+ }
+ ]
+ },
+ "dependencies": {
+ "vscode-languageclient": "~4.3.0"
+ },
+ "activationEvents": [
+ "*"
+ ],
+ "main": "./extension.js"
+}
diff --git a/utils/vscode/spirv.json b/utils/vscode/spirv.json
new file mode 100644
index 0000000..30573d4
--- /dev/null
+++ b/utils/vscode/spirv.json
@@ -0,0 +1,212 @@
+{
+ "scopeName": "source.spirv",
+ "name": "SPIR-V",
+ "comment": "Generated by gen-grammar.go --template=../../spirv.json.tmpl --out=../../spirv.json. Do not modify this file directly.",
+ "patterns": [
+ { "include": "#BitEnum_ImageOperands" },
+ { "include": "#BitEnum_FPFastMathMode" },
+ { "include": "#BitEnum_SelectionControl" },
+ { "include": "#BitEnum_LoopControl" },
+ { "include": "#BitEnum_FunctionControl" },
+ { "include": "#BitEnum_MemorySemantics" },
+ { "include": "#BitEnum_MemoryAccess" },
+ { "include": "#BitEnum_KernelProfilingInfo" },
+ { "include": "#ValueEnum_SourceLanguage" },
+ { "include": "#ValueEnum_ExecutionModel" },
+ { "include": "#ValueEnum_AddressingModel" },
+ { "include": "#ValueEnum_MemoryModel" },
+ { "include": "#ValueEnum_ExecutionMode" },
+ { "include": "#ValueEnum_StorageClass" },
+ { "include": "#ValueEnum_Dim" },
+ { "include": "#ValueEnum_SamplerAddressingMode" },
+ { "include": "#ValueEnum_SamplerFilterMode" },
+ { "include": "#ValueEnum_ImageFormat" },
+ { "include": "#ValueEnum_ImageChannelOrder" },
+ { "include": "#ValueEnum_ImageChannelDataType" },
+ { "include": "#ValueEnum_FPRoundingMode" },
+ { "include": "#ValueEnum_LinkageType" },
+ { "include": "#ValueEnum_AccessQualifier" },
+ { "include": "#ValueEnum_FunctionParameterAttribute" },
+ { "include": "#ValueEnum_Decoration" },
+ { "include": "#ValueEnum_BuiltIn" },
+ { "include": "#ValueEnum_Scope" },
+ { "include": "#ValueEnum_GroupOperation" },
+ { "include": "#ValueEnum_KernelEnqueueFlags" },
+ { "include": "#ValueEnum_Capability" },
+ { "include": "#opcode" },
+ { "include": "#identifier" },
+ { "include": "#number" },
+ { "include": "#string" },
+ { "include": "#comment" },
+ { "include": "#operator" }
+ ],
+ "repository": {
+ "BitEnum_ImageOperands": {
+ "match": "\\b(None|Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod|MakeTexelAvailable|MakeTexelAvailableKHR|MakeTexelVisible|MakeTexelVisibleKHR|NonPrivateTexel|NonPrivateTexelKHR|VolatileTexel|VolatileTexelKHR|SignExtend|ZeroExtend)\\b",
+ "name": "keyword.spirv"
+ },
+ "BitEnum_FPFastMathMode": {
+ "match": "\\b(None|NotNaN|NotInf|NSZ|AllowRecip|Fast)\\b",
+ "name": "keyword.spirv"
+ },
+ "BitEnum_SelectionControl": {
+ "match": "\\b(None|Flatten|DontFlatten)\\b",
+ "name": "keyword.spirv"
+ },
+ "BitEnum_LoopControl": {
+ "match": "\\b(None|Unroll|DontUnroll|DependencyInfinite|DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount)\\b",
+ "name": "keyword.spirv"
+ },
+ "BitEnum_FunctionControl": {
+ "match": "\\b(None|Inline|DontInline|Pure|Const)\\b",
+ "name": "keyword.spirv"
+ },
+ "BitEnum_MemorySemantics": {
+ "match": "\\b(Relaxed|None|Acquire|Release|AcquireRelease|SequentiallyConsistent|UniformMemory|SubgroupMemory|WorkgroupMemory|CrossWorkgroupMemory|AtomicCounterMemory|ImageMemory|OutputMemory|OutputMemoryKHR|MakeAvailable|MakeAvailableKHR|MakeVisible|MakeVisibleKHR|Volatile)\\b",
+ "name": "keyword.spirv"
+ },
+ "BitEnum_MemoryAccess": {
+ "match": "\\b(None|Volatile|Aligned|Nontemporal|MakePointerAvailable|MakePointerAvailableKHR|MakePointerVisible|MakePointerVisibleKHR|NonPrivatePointer|NonPrivatePointerKHR)\\b",
+ "name": "keyword.spirv"
+ },
+ "BitEnum_KernelProfilingInfo": {
+ "match": "\\b(None|CmdExecTime)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_SourceLanguage": {
+ "match": "\\b(Unknown|ESSL|GLSL|OpenCL_C|OpenCL_CPP|HLSL)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_ExecutionModel": {
+ "match": "\\b(Vertex|TessellationControl|TessellationEvaluation|Geometry|Fragment|GLCompute|Kernel|TaskNV|MeshNV|RayGenerationNV|IntersectionNV|AnyHitNV|ClosestHitNV|MissNV|CallableNV)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_AddressingModel": {
+ "match": "\\b(Logical|Physical32|Physical64|PhysicalStorageBuffer64|PhysicalStorageBuffer64EXT)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_MemoryModel": {
+ "match": "\\b(Simple|GLSL450|OpenCL|Vulkan|VulkanKHR)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_ExecutionMode": {
+ "match": "\\b(Invocations|SpacingEqual|SpacingFractionalEven|SpacingFractionalOdd|VertexOrderCw|VertexOrderCcw|PixelCenterInteger|OriginUpperLeft|OriginLowerLeft|EarlyFragmentTests|PointMode|Xfb|DepthReplacing|DepthGreater|DepthLess|DepthUnchanged|LocalSize|LocalSizeHint|InputPoints|InputLines|InputLinesAdjacency|Triangles|InputTrianglesAdjacency|Quads|Isolines|OutputVertices|OutputPoints|OutputLineStrip|OutputTriangleStrip|VecTypeHint|ContractionOff|Initializer|Finalizer|SubgroupSize|SubgroupsPerWorkgroup|SubgroupsPerWorkgroupId|LocalSizeId|LocalSizeHintId|PostDepthCoverage|DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|StencilRefReplacingEXT|OutputLinesNV|OutputPrimitivesNV|DerivativeGroupQuadsNV|DerivativeGroupLinearNV|OutputTrianglesNV|PixelInterlockOrderedEXT|PixelInterlockUnorderedEXT|SampleInterlockOrderedEXT|SampleInterlockUnorderedEXT|ShadingRateInterlockOrderedEXT|ShadingRateInterlockUnorderedEXT)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_StorageClass": {
+ "match": "\\b(UniformConstant|Input|Uniform|Output|Workgroup|CrossWorkgroup|Private|Function|Generic|PushConstant|AtomicCounter|Image|StorageBuffer|CallableDataNV|IncomingCallableDataNV|RayPayloadNV|HitAttributeNV|IncomingRayPayloadNV|ShaderRecordBufferNV|PhysicalStorageBuffer|PhysicalStorageBufferEXT)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_Dim": {
+ "match": "\\b(1D|2D|3D|Cube|Rect|Buffer|SubpassData)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_SamplerAddressingMode": {
+ "match": "\\b(None|ClampToEdge|Clamp|Repeat|RepeatMirrored)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_SamplerFilterMode": {
+ "match": "\\b(Nearest|Linear)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_ImageFormat": {
+ "match": "\\b(Unknown|Rgba32f|Rgba16f|R32f|Rgba8|Rgba8Snorm|Rg32f|Rg16f|R11fG11fB10f|R16f|Rgba16|Rgb10A2|Rg16|Rg8|R16|R8|Rgba16Snorm|Rg16Snorm|Rg8Snorm|R16Snorm|R8Snorm|Rgba32i|Rgba16i|Rgba8i|R32i|Rg32i|Rg16i|Rg8i|R16i|R8i|Rgba32ui|Rgba16ui|Rgba8ui|R32ui|Rgb10a2ui|Rg32ui|Rg16ui|Rg8ui|R16ui|R8ui)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_ImageChannelOrder": {
+ "match": "\\b(R|A|RG|RA|RGB|RGBA|BGRA|ARGB|Intensity|Luminance|Rx|RGx|RGBx|Depth|DepthStencil|sRGB|sRGBx|sRGBA|sBGRA|ABGR)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_ImageChannelDataType": {
+ "match": "\\b(SnormInt8|SnormInt16|UnormInt8|UnormInt16|UnormShort565|UnormShort555|UnormInt101010|SignedInt8|SignedInt16|SignedInt32|UnsignedInt8|UnsignedInt16|UnsignedInt32|HalfFloat|Float|UnormInt24|UnormInt101010_2)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_FPRoundingMode": {
+ "match": "\\b(RTE|RTZ|RTP|RTN)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_LinkageType": {
+ "match": "\\b(Export|Import)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_AccessQualifier": {
+ "match": "\\b(ReadOnly|WriteOnly|ReadWrite)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_FunctionParameterAttribute": {
+ "match": "\\b(Zext|Sext|ByVal|Sret|NoAlias|NoCapture|NoWrite|NoReadWrite)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_Decoration": {
+ "match": "\\b(RelaxedPrecision|SpecId|Block|BufferBlock|RowMajor|ColMajor|ArrayStride|MatrixStride|GLSLShared|GLSLPacked|CPacked|BuiltIn|NoPerspective|Flat|Patch|Centroid|Sample|Invariant|Restrict|Aliased|Volatile|Constant|Coherent|NonWritable|NonReadable|Uniform|UniformId|SaturatedConversion|Stream|Location|Component|Index|Binding|DescriptorSet|Offset|XfbBuffer|XfbStride|FuncParamAttr|FPRoundingMode|FPFastMathMode|LinkageAttributes|NoContraction|InputAttachmentIndex|Alignment|MaxByteOffset|AlignmentId|MaxByteOffsetId|NoSignedWrap|NoUnsignedWrap|ExplicitInterpAMD|OverrideCoverageNV|PassthroughNV|ViewportRelativeNV|SecondaryViewportRelativeNV|PerPrimitiveNV|PerViewNV|PerTaskNV|PerVertexNV|NonUniform|NonUniformEXT|RestrictPointer|RestrictPointerEXT|AliasedPointer|AliasedPointerEXT|CounterBuffer|HlslCounterBufferGOOGLE|UserSemantic|HlslSemanticGOOGLE|UserTypeGOOGLE)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_BuiltIn": {
+ "match": "\\b(Position|PointSize|ClipDistance|CullDistance|VertexId|InstanceId|PrimitiveId|InvocationId|Layer|ViewportIndex|TessLevelOuter|TessLevelInner|TessCoord|PatchVertices|FragCoord|PointCoord|FrontFacing|SampleId|SamplePosition|SampleMask|FragDepth|HelperInvocation|NumWorkgroups|WorkgroupSize|WorkgroupId|LocalInvocationId|GlobalInvocationId|LocalInvocationIndex|WorkDim|GlobalSize|EnqueuedWorkgroupSize|GlobalOffset|GlobalLinearId|SubgroupSize|SubgroupMaxSize|NumSubgroups|NumEnqueuedSubgroups|SubgroupId|SubgroupLocalInvocationId|VertexIndex|InstanceIndex|SubgroupEqMask|SubgroupGeMask|SubgroupGtMask|SubgroupLeMask|SubgroupLtMask|SubgroupEqMaskKHR|SubgroupGeMaskKHR|SubgroupGtMaskKHR|SubgroupLeMaskKHR|SubgroupLtMaskKHR|BaseVertex|BaseInstance|DrawIndex|DeviceIndex|ViewIndex|BaryCoordNoPerspAMD|BaryCoordNoPerspCentroidAMD|BaryCoordNoPerspSampleAMD|BaryCoordSmoothAMD|BaryCoordSmoothCentroidAMD|BaryCoordSmoothSampleAMD|BaryCoordPullModelAMD|FragStencilRefEXT|ViewportMaskNV|SecondaryPositionNV|SecondaryViewportMaskNV|PositionPerViewNV|ViewportMaskPerViewNV|FullyCoveredEXT|TaskCountNV|PrimitiveCountNV|PrimitiveIndicesNV|ClipDistancePerViewNV|CullDistancePerViewNV|LayerPerViewNV|MeshViewCountNV|MeshViewIndicesNV|BaryCoordNV|BaryCoordNoPerspNV|FragSizeEXT|FragmentSizeNV|FragInvocationCountEXT|InvocationsPerPixelNV|LaunchIdNV|LaunchSizeNV|WorldRayOriginNV|WorldRayDirectionNV|ObjectRayOriginNV|ObjectRayDirectionNV|RayTminNV|RayTmaxNV|InstanceCustomIndexNV|ObjectToWorldNV|WorldToObjectNV|HitTNV|HitKindNV|IncomingRayFlagsNV|WarpsPerSMNV|SMCountNV|WarpIDNV|SMIDNV)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_Scope": {
+ "match": "\\b(CrossDevice|Device|Workgroup|Subgroup|Invocation|QueueFamily|QueueFamilyKHR)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_GroupOperation": {
+ "match": "\\b(Reduce|InclusiveScan|ExclusiveScan|ClusteredReduce|PartitionedReduceNV|PartitionedInclusiveScanNV|PartitionedExclusiveScanNV)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_KernelEnqueueFlags": {
+ "match": "\\b(NoWait|WaitKernel|WaitWorkGroup)\\b",
+ "name": "keyword.spirv"
+ },
+ "ValueEnum_Capability": {
+ "match": "\\b(Matrix|Shader|Geometry|Tessellation|Addresses|Linkage|Kernel|Vector16|Float16Buffer|Float16|Float64|Int64|Int64Atomics|ImageBasic|ImageReadWrite|ImageMipmap|Pipes|Groups|DeviceEnqueue|LiteralSampler|AtomicStorage|Int16|TessellationPointSize|GeometryPointSize|ImageGatherExtended|StorageImageMultisample|UniformBufferArrayDynamicIndexing|SampledImageArrayDynamicIndexing|StorageBufferArrayDynamicIndexing|StorageImageArrayDynamicIndexing|ClipDistance|CullDistance|ImageCubeArray|SampleRateShading|ImageRect|SampledRect|GenericPointer|Int8|InputAttachment|SparseResidency|MinLod|Sampled1D|Image1D|SampledCubeArray|SampledBuffer|ImageBuffer|ImageMSArray|StorageImageExtendedFormats|ImageQuery|DerivativeControl|InterpolationFunction|TransformFeedback|GeometryStreams|StorageImageReadWithoutFormat|StorageImageWriteWithoutFormat|MultiViewport|SubgroupDispatch|NamedBarrier|PipeStorage|GroupNonUniform|GroupNonUniformVote|GroupNonUniformArithmetic|GroupNonUniformBallot|GroupNonUniformShuffle|GroupNonUniformShuffleRelative|GroupNonUniformClustered|GroupNonUniformQuad|ShaderLayer|ShaderViewportIndex|SubgroupBallotKHR|DrawParameters|SubgroupVoteKHR|StorageBuffer16BitAccess|StorageUniformBufferBlock16|UniformAndStorageBuffer16BitAccess|StorageUniform16|StoragePushConstant16|StorageInputOutput16|DeviceGroup|MultiView|VariablePointersStorageBuffer|VariablePointers|AtomicStorageOps|SampleMaskPostDepthCoverage|StorageBuffer8BitAccess|UniformAndStorageBuffer8BitAccess|StoragePushConstant8|DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|Float16ImageAMD|ImageGatherBiasLodAMD|FragmentMaskAMD|StencilExportEXT|ImageReadWriteLodAMD|ShaderClockKHR|SampleMaskOverrideCoverageNV|GeometryShaderPassthroughNV|ShaderViewportIndexLayerEXT|ShaderViewportIndexLayerNV|ShaderViewportMaskNV|ShaderStereoViewNV|PerViewAttributesNV|FragmentFullyCoveredEXT|MeshShadingNV|ImageFootprintNV|FragmentBarycentricNV|ComputeDerivativeGroupQuadsNV|FragmentDensityEXT|ShadingRateNV|GroupNonUniformPartitionedNV|ShaderNonUniform|ShaderNonUniformEXT|RuntimeDescriptorArray|RuntimeDescriptorArrayEXT|InputAttachmentArrayDynamicIndexing|InputAttachmentArrayDynamicIndexingEXT|UniformTexelBufferArrayDynamicIndexing|UniformTexelBufferArrayDynamicIndexingEXT|StorageTexelBufferArrayDynamicIndexing|StorageTexelBufferArrayDynamicIndexingEXT|UniformBufferArrayNonUniformIndexing|UniformBufferArrayNonUniformIndexingEXT|SampledImageArrayNonUniformIndexing|SampledImageArrayNonUniformIndexingEXT|StorageBufferArrayNonUniformIndexing|StorageBufferArrayNonUniformIndexingEXT|StorageImageArrayNonUniformIndexing|StorageImageArrayNonUniformIndexingEXT|InputAttachmentArrayNonUniformIndexing|InputAttachmentArrayNonUniformIndexingEXT|UniformTexelBufferArrayNonUniformIndexing|UniformTexelBufferArrayNonUniformIndexingEXT|StorageTexelBufferArrayNonUniformIndexing|StorageTexelBufferArrayNonUniformIndexingEXT|RayTracingNV|VulkanMemoryModel|VulkanMemoryModelKHR|VulkanMemoryModelDeviceScope|VulkanMemoryModelDeviceScopeKHR|PhysicalStorageBufferAddresses|PhysicalStorageBufferAddressesEXT|ComputeDerivativeGroupLinearNV|CooperativeMatrixNV|FragmentShaderSampleInterlockEXT|FragmentShaderShadingRateInterlockEXT|ShaderSMBuiltinsNV|FragmentShaderPixelInterlockEXT|DemoteToHelperInvocationEXT|SubgroupShuffleINTEL|SubgroupBufferBlockIOINTEL|SubgroupImageBlockIOINTEL|SubgroupImageMediaBlockIOINTEL|IntegerFunctions2INTEL|SubgroupAvcMotionEstimationINTEL|SubgroupAvcMotionEstimationIntraINTEL|SubgroupAvcMotionEstimationChromaINTEL)\\b",
+ "name": "keyword.spirv"
+ },
+ "opcode": {
+ "match": "(Op[a-zA-Z]+)",
+ "name": "entity.name.function.spirv"
+ },
+ "identifier": {
+ "match": "%[a-zA-Z0-9_]+",
+ "name": "variable.spirv"
+ },
+ "number": {
+ "match": "\\b[0-9]+.?[0-9]*\\b",
+ "name": "constant.numeric.spirv"
+ },
+ "comment": {
+ "match": ";[^\n]*",
+ "name": "comment.line.spirv"
+ },
+ "operator": {
+ "match": "=",
+ "name": "keyword.operator.spirv"
+ },
+ "string": {
+ "begin": "\"",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.definition.string.begin.spirv"
+ }
+ },
+ "end": "\"",
+ "endCaptures": {
+ "0": {
+ "name": "punctuation.definition.string.end.spirv"
+ }
+ },
+ "name": "string.quoted.double.spirv",
+ "patterns": [ { "include": "#string_escaped_char" } ]
+ },
+ "string_escaped_char": {
+ "patterns": [
+ {
+ "match": "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})",
+ "name": "constant.character.escape.spirv"
+ }, {
+ "match": "\\\\[^0-7xuUabfnrtv\\'\"]",
+ "name": "invalid.illegal.unknown-escape.spirv"
+ }
+ ]
+ }
+ }
+}
diff --git a/utils/vscode/spirv.json.tmpl b/utils/vscode/spirv.json.tmpl
new file mode 100644
index 0000000..8582d03
--- /dev/null
+++ b/utils/vscode/spirv.json.tmpl
@@ -0,0 +1,67 @@
+{
+ "scopeName": "source.spirv",
+ "name": "SPIR-V",
+ "comment": "Generated by {{GenerateArguments}}. Do not modify this file directly.",
+ "patterns": [
+{{range $o := .OperandKinds}}{{if len $o.Enumerants}} { "include": "#{{$o.Category}}_{{$o.Kind}}" },
+{{end}}{{end}} { "include": "#opcode" },
+ { "include": "#identifier" },
+ { "include": "#number" },
+ { "include": "#string" },
+ { "include": "#comment" },
+ { "include": "#operator" }
+ ],
+ "repository": { {{range $o := .OperandKinds}}{{if len $o.Enumerants}}
+ "{{$o.Category}}_{{$o.Kind}}": {
+ "match": "\\b({{OperandKindsMatch $o}})\\b",
+ "name": "keyword.spirv"
+ },{{end}}{{end}}
+ "opcode": {
+ "match": "(Op[a-zA-Z]+)",
+ "name": "entity.name.function.spirv"
+ },
+ "identifier": {
+ "match": "%[a-zA-Z0-9_]+",
+ "name": "variable.spirv"
+ },
+ "number": {
+ "match": "\\b[0-9]+.?[0-9]*\\b",
+ "name": "constant.numeric.spirv"
+ },
+ "comment": {
+ "match": ";[^\n]*",
+ "name": "comment.line.spirv"
+ },
+ "operator": {
+ "match": "=",
+ "name": "keyword.operator.spirv"
+ },
+ "string": {
+ "begin": "\"",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.definition.string.begin.spirv"
+ }
+ },
+ "end": "\"",
+ "endCaptures": {
+ "0": {
+ "name": "punctuation.definition.string.end.spirv"
+ }
+ },
+ "name": "string.quoted.double.spirv",
+ "patterns": [ { "include": "#string_escaped_char" } ]
+ },
+ "string_escaped_char": {
+ "patterns": [
+ {
+ "match": "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})",
+ "name": "constant.character.escape.spirv"
+ }, {
+ "match": "\\\\[^0-7xuUabfnrtv\\'\"]",
+ "name": "invalid.illegal.unknown-escape.spirv"
+ }
+ ]
+ }
+ }
+}
diff --git a/utils/vscode/src/grammar/grammar.go b/utils/vscode/src/grammar/grammar.go
new file mode 100644
index 0000000..857a193
--- /dev/null
+++ b/utils/vscode/src/grammar/grammar.go
@@ -0,0 +1,81 @@
+// 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.
+
+// Package grammar holds the JSON type definitions for the SPIR-V grammar schema.
+//
+// See https://www.khronos.org/registry/spir-v/specs/unified1/MachineReadableGrammar.html
+// for more information.
+package grammar
+
+// Root is the top-level structure of the JSON grammar.
+type Root struct {
+ MagicNumber string `json:"magic_number"`
+ MajorVersion int `json:"major_version"`
+ MinorVersion int `json:"minor_version"`
+ Revision int `json:"revision"`
+ Instructions []Instruction `json:"instructions"`
+ OperandKinds []OperandKind `json:"operand_kinds"`
+}
+
+// Instruction holds information about a specific SPIR-V instruction.
+type Instruction struct {
+ Opname string `json:"opname"`
+ Class string `json:"class"`
+ Opcode int `json:"opcode"`
+ Operands []Operand `json:"operands"`
+}
+
+// Operand contains information about a logical operand for an instruction.
+type Operand struct {
+ Kind string `json:"kind"`
+ Name string `json:"name"`
+ Quantifier Quantifier `json:"quantifier"`
+}
+
+// OperandKind contains information about a specific operand kind.
+type OperandKind struct {
+ Category string `json:"category"`
+ Kind string `json:"kind"`
+ Enumerants []Enumerant `json:"enumerants"`
+ Bases []string `json:"bases"`
+}
+
+// Enumerant contains information about an enumerant in an enum.
+type Enumerant struct {
+ Enumerant string `json:"enumerant"`
+ Value interface{} `json:"value"`
+ Capabilities []string `json:"capabilities"`
+ Parameters []Parameter `json:"parameters"`
+ Version string `json:"version"`
+}
+
+// Parameter contains information about a logical parameter for an enumerant.
+type Parameter struct {
+ Kind string `json:"kind"`
+ Name string `json:"name"`
+}
+
+// Quantifier indicates the number of times the quantified term may appear.
+type Quantifier string
+
+const (
+ // Once indicates the quantified term may appear exactly once.
+ Once Quantifier = ""
+ // ZeroOrOnce indicates the quantified term may appear zero or one
+ // time; an optional term.
+ ZeroOrOnce Quantifier = "?"
+ // ZeroOrMany indicates the quantified term may appear any number of
+ // times.
+ ZeroOrMany Quantifier = "*"
+)
diff --git a/utils/vscode/src/langsvr.go b/utils/vscode/src/langsvr.go
new file mode 100644
index 0000000..d1b80dc
--- /dev/null
+++ b/utils/vscode/src/langsvr.go
@@ -0,0 +1,527 @@
+// 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.
+
+// langsvr implements a Language Server for the SPIRV assembly language.
+package main
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+ "sort"
+ "strings"
+ "sync"
+ "unicode/utf8"
+
+ "./parser"
+ "./schema"
+
+ "./lsp/jsonrpc2"
+ lsp "./lsp/protocol"
+)
+
+// rSpy is a reader 'spy' that wraps an io.Reader, and logs all data that passes
+// through it.
+type rSpy struct {
+ prefix string
+ r io.Reader
+}
+
+func (s rSpy) Read(p []byte) (n int, err error) {
+ n, err = s.r.Read(p)
+ log.Printf("%v %v", s.prefix, string(p[:n]))
+ return n, err
+}
+
+// wSpy is a reader 'spy' that wraps an io.Writer, and logs all data that passes
+// through it.
+type wSpy struct {
+ prefix string
+ w io.Writer
+}
+
+func (s wSpy) Write(p []byte) (n int, err error) {
+ n, err = s.w.Write(p)
+ log.Printf("%v %v", s.prefix, string(p))
+ return n, err
+}
+
+// main entry point.
+func main() {
+ // create a log file in the executable's directory.
+ if logfile, err := os.Create(path.Join(path.Dir(os.Args[0]), "log.txt")); err == nil {
+ defer logfile.Close()
+ log.SetOutput(logfile)
+ } else {
+ log.SetOutput(ioutil.Discard)
+ }
+
+ log.Println("language server started")
+
+ stream := jsonrpc2.NewHeaderStream(rSpy{"IDE", os.Stdin}, wSpy{"LS", os.Stdout})
+ s := server{
+ files: map[string]*file{},
+ }
+ s.ctx, s.conn, s.client = lsp.NewServer(context.Background(), stream, &s)
+ if err := s.conn.Run(s.ctx); err != nil {
+ log.Panicln(err)
+ os.Exit(1)
+ }
+
+ log.Println("language server stopped")
+}
+
+type server struct {
+ ctx context.Context
+ conn *jsonrpc2.Conn
+ client lsp.Client
+
+ files map[string]*file
+ filesMutex sync.Mutex
+}
+
+// file represents a source file
+type file struct {
+ fullRange parser.Range
+ res parser.Results
+}
+
+// tokAt returns the parser token at the given position lp
+func (f *file) tokAt(lp lsp.Position) *parser.Token {
+ toks := f.res.Tokens
+ p := parser.Position{Line: int(lp.Line) + 1, Column: int(lp.Character) + 1}
+ i := sort.Search(len(toks), func(i int) bool { return p.LessThan(toks[i].Range.End) })
+ if i == len(toks) {
+ return nil
+ }
+ if toks[i].Range.Contains(p) {
+ return toks[i]
+ }
+ return nil
+}
+
+func (s *server) DidChangeWorkspaceFolders(ctx context.Context, p *lsp.DidChangeWorkspaceFoldersParams) error {
+ log.Println("server.DidChangeWorkspaceFolders()")
+ return nil
+}
+func (s *server) Initialized(ctx context.Context, p *lsp.InitializedParams) error {
+ log.Println("server.Initialized()")
+ return nil
+}
+func (s *server) Exit(ctx context.Context) error {
+ log.Println("server.Exit()")
+ return nil
+}
+func (s *server) DidChangeConfiguration(ctx context.Context, p *lsp.DidChangeConfigurationParams) error {
+ log.Println("server.DidChangeConfiguration()")
+ return nil
+}
+func (s *server) DidOpen(ctx context.Context, p *lsp.DidOpenTextDocumentParams) error {
+ log.Println("server.DidOpen()")
+ return s.processFile(ctx, p.TextDocument.URI, p.TextDocument.Text)
+}
+func (s *server) DidChange(ctx context.Context, p *lsp.DidChangeTextDocumentParams) error {
+ log.Println("server.DidChange()")
+ return s.processFile(ctx, p.TextDocument.URI, p.ContentChanges[0].Text)
+}
+func (s *server) DidClose(ctx context.Context, p *lsp.DidCloseTextDocumentParams) error {
+ log.Println("server.DidClose()")
+ return nil
+}
+func (s *server) DidSave(ctx context.Context, p *lsp.DidSaveTextDocumentParams) error {
+ log.Println("server.DidSave()")
+ return nil
+}
+func (s *server) WillSave(ctx context.Context, p *lsp.WillSaveTextDocumentParams) error {
+ log.Println("server.WillSave()")
+ return nil
+}
+func (s *server) DidChangeWatchedFiles(ctx context.Context, p *lsp.DidChangeWatchedFilesParams) error {
+ log.Println("server.DidChangeWatchedFiles()")
+ return nil
+}
+func (s *server) Progress(ctx context.Context, p *lsp.ProgressParams) error {
+ log.Println("server.Progress()")
+ return nil
+}
+func (s *server) SetTraceNotification(ctx context.Context, p *lsp.SetTraceParams) error {
+ log.Println("server.SetTraceNotification()")
+ return nil
+}
+func (s *server) LogTraceNotification(ctx context.Context, p *lsp.LogTraceParams) error {
+ log.Println("server.LogTraceNotification()")
+ return nil
+}
+func (s *server) Implementation(ctx context.Context, p *lsp.ImplementationParams) ([]lsp.Location, error) {
+ log.Println("server.Implementation()")
+ return nil, nil
+}
+func (s *server) TypeDefinition(ctx context.Context, p *lsp.TypeDefinitionParams) ([]lsp.Location, error) {
+ log.Println("server.TypeDefinition()")
+ return nil, nil
+}
+func (s *server) DocumentColor(ctx context.Context, p *lsp.DocumentColorParams) ([]lsp.ColorInformation, error) {
+ log.Println("server.DocumentColor()")
+ return nil, nil
+}
+func (s *server) ColorPresentation(ctx context.Context, p *lsp.ColorPresentationParams) ([]lsp.ColorPresentation, error) {
+ log.Println("server.ColorPresentation()")
+ return nil, nil
+}
+func (s *server) FoldingRange(ctx context.Context, p *lsp.FoldingRangeParams) ([]lsp.FoldingRange, error) {
+ log.Println("server.FoldingRange()")
+ return nil, nil
+}
+func (s *server) Declaration(ctx context.Context, p *lsp.DeclarationParams) ([]lsp.DeclarationLink, error) {
+ log.Println("server.Declaration()")
+ return nil, nil
+}
+func (s *server) SelectionRange(ctx context.Context, p *lsp.SelectionRangeParams) ([]lsp.SelectionRange, error) {
+ log.Println("server.SelectionRange()")
+ return nil, nil
+}
+func (s *server) Initialize(ctx context.Context, p *lsp.ParamInitia) (*lsp.InitializeResult, error) {
+ log.Println("server.Initialize()")
+ res := lsp.InitializeResult{
+ Capabilities: lsp.ServerCapabilities{
+ TextDocumentSync: lsp.TextDocumentSyncOptions{
+ OpenClose: true,
+ Change: lsp.Full, // TODO: Implement incremental
+ },
+ HoverProvider: true,
+ DefinitionProvider: true,
+ ReferencesProvider: true,
+ RenameProvider: true,
+ DocumentFormattingProvider: true,
+ },
+ }
+ return &res, nil
+}
+func (s *server) Shutdown(ctx context.Context) error {
+ log.Println("server.Shutdown()")
+ return nil
+}
+func (s *server) WillSaveWaitUntil(ctx context.Context, p *lsp.WillSaveTextDocumentParams) ([]lsp.TextEdit, error) {
+ log.Println("server.WillSaveWaitUntil()")
+ return nil, nil
+}
+func (s *server) Completion(ctx context.Context, p *lsp.CompletionParams) (*lsp.CompletionList, error) {
+ log.Println("server.Completion()")
+ return nil, nil
+}
+func (s *server) Resolve(ctx context.Context, p *lsp.CompletionItem) (*lsp.CompletionItem, error) {
+ log.Println("server.Resolve()")
+ return nil, nil
+}
+func (s *server) Hover(ctx context.Context, p *lsp.HoverParams) (*lsp.Hover, error) {
+ log.Println("server.Hover()")
+ f := s.getFile(p.TextDocument.URI)
+ if f == nil {
+ return nil, fmt.Errorf("Unknown file")
+ }
+
+ if tok := f.tokAt(p.Position); tok != nil {
+ sb := strings.Builder{}
+ switch v := f.res.Mappings[tok].(type) {
+ default:
+ sb.WriteString(fmt.Sprintf("<Unhandled type '%T'>", v))
+ case *parser.Instruction:
+ sb.WriteString(fmt.Sprintf("```\n%v\n```", v.Opcode.Opname))
+ case *parser.Identifier:
+ sb.WriteString(fmt.Sprintf("```\n%v\n```", v.Definition.Range.Text(f.res.Lines)))
+ case *parser.Operand:
+ if v.Name != "" {
+ sb.WriteString(strings.Trim(v.Name, `'`))
+ sb.WriteString("\n\n")
+ }
+
+ switch v.Kind.Category {
+ case schema.OperandCategoryBitEnum:
+ case schema.OperandCategoryValueEnum:
+ sb.WriteString("```\n")
+ sb.WriteString(strings.Trim(v.Kind.Kind, `'`))
+ sb.WriteString("\n```")
+ case schema.OperandCategoryID:
+ if s := tok.Text(f.res.Lines); s != "" {
+ if id, ok := f.res.Identifiers[s]; ok && id.Definition != nil {
+ sb.WriteString("```\n")
+ sb.WriteString(id.Definition.Range.Text(f.res.Lines))
+ sb.WriteString("\n```")
+ }
+ }
+ case schema.OperandCategoryLiteral:
+ case schema.OperandCategoryComposite:
+ }
+ case nil:
+ }
+
+ if sb.Len() > 0 {
+ res := lsp.Hover{
+ Contents: lsp.MarkupContent{
+ Kind: "markdown",
+ Value: sb.String(),
+ },
+ }
+ return &res, nil
+ }
+ }
+
+ return nil, nil
+}
+func (s *server) SignatureHelp(ctx context.Context, p *lsp.SignatureHelpParams) (*lsp.SignatureHelp, error) {
+ log.Println("server.SignatureHelp()")
+ return nil, nil
+}
+func (s *server) Definition(ctx context.Context, p *lsp.DefinitionParams) ([]lsp.Location, error) {
+ log.Println("server.Definition()")
+ if f := s.getFile(p.TextDocument.URI); f != nil {
+ if tok := f.tokAt(p.Position); tok != nil {
+ if s := tok.Text(f.res.Lines); s != "" {
+ if id, ok := f.res.Identifiers[s]; ok {
+ loc := lsp.Location{
+ URI: p.TextDocument.URI,
+ Range: rangeToLSP(id.Definition.Range),
+ }
+ return []lsp.Location{loc}, nil
+ }
+ }
+ }
+ }
+ return nil, nil
+}
+func (s *server) References(ctx context.Context, p *lsp.ReferenceParams) ([]lsp.Location, error) {
+ log.Println("server.References()")
+ if f := s.getFile(p.TextDocument.URI); f != nil {
+ if tok := f.tokAt(p.Position); tok != nil {
+ if s := tok.Text(f.res.Lines); s != "" {
+ if id, ok := f.res.Identifiers[s]; ok {
+ locs := make([]lsp.Location, len(id.References))
+ for i, r := range id.References {
+ locs[i] = lsp.Location{
+ URI: p.TextDocument.URI,
+ Range: rangeToLSP(r.Range),
+ }
+ }
+ return locs, nil
+ }
+ }
+ }
+ }
+ return nil, nil
+}
+func (s *server) DocumentHighlight(ctx context.Context, p *lsp.DocumentHighlightParams) ([]lsp.DocumentHighlight, error) {
+ log.Println("server.DocumentHighlight()")
+ return nil, nil
+}
+func (s *server) DocumentSymbol(ctx context.Context, p *lsp.DocumentSymbolParams) ([]lsp.DocumentSymbol, error) {
+ log.Println("server.DocumentSymbol()")
+ return nil, nil
+}
+func (s *server) CodeAction(ctx context.Context, p *lsp.CodeActionParams) ([]lsp.CodeAction, error) {
+ log.Println("server.CodeAction()")
+ return nil, nil
+}
+func (s *server) Symbol(ctx context.Context, p *lsp.WorkspaceSymbolParams) ([]lsp.SymbolInformation, error) {
+ log.Println("server.Symbol()")
+ return nil, nil
+}
+func (s *server) CodeLens(ctx context.Context, p *lsp.CodeLensParams) ([]lsp.CodeLens, error) {
+ log.Println("server.CodeLens()")
+ return nil, nil
+}
+func (s *server) ResolveCodeLens(ctx context.Context, p *lsp.CodeLens) (*lsp.CodeLens, error) {
+ log.Println("server.ResolveCodeLens()")
+ return nil, nil
+}
+func (s *server) DocumentLink(ctx context.Context, p *lsp.DocumentLinkParams) ([]lsp.DocumentLink, error) {
+ log.Println("server.DocumentLink()")
+ return nil, nil
+}
+func (s *server) ResolveDocumentLink(ctx context.Context, p *lsp.DocumentLink) (*lsp.DocumentLink, error) {
+ log.Println("server.ResolveDocumentLink()")
+ return nil, nil
+}
+func (s *server) Formatting(ctx context.Context, p *lsp.DocumentFormattingParams) ([]lsp.TextEdit, error) {
+ log.Println("server.Formatting()")
+ if f := s.getFile(p.TextDocument.URI); f != nil {
+ // Start by measuring the distance from the start of each line to the
+ // first opcode on that line.
+ lineInstOffsets, maxInstOffset, instOffset, curOffset := []int{}, 0, 0, -1
+ for _, t := range f.res.Tokens {
+ curOffset++ // whitespace between tokens
+ switch t.Type {
+ case parser.Ident:
+ if _, isInst := schema.Opcodes[t.Text(f.res.Lines)]; isInst && instOffset == 0 {
+ instOffset = curOffset
+ continue
+ }
+ case parser.Newline:
+ lineInstOffsets = append(lineInstOffsets, instOffset)
+ if instOffset > maxInstOffset {
+ maxInstOffset = instOffset
+ }
+ curOffset, instOffset = -1, 0
+ default:
+ curOffset += utf8.RuneCountInString(t.Text(f.res.Lines))
+ }
+ }
+ lineInstOffsets = append(lineInstOffsets, instOffset)
+
+ // Now rewrite each of the lines, adding padding at the start of the
+ // line for alignment.
+ sb, newline := strings.Builder{}, true
+ for _, t := range f.res.Tokens {
+ if newline {
+ newline = false
+ indent := maxInstOffset - lineInstOffsets[0]
+ lineInstOffsets = lineInstOffsets[1:]
+ switch t.Type {
+ case parser.Newline, parser.Comment:
+ default:
+ for s := 0; s < indent; s++ {
+ sb.WriteRune(' ')
+ }
+ }
+ } else if t.Type != parser.Newline {
+ sb.WriteString(" ")
+ }
+
+ sb.WriteString(t.Text(f.res.Lines))
+ if t.Type == parser.Newline {
+ newline = true
+ }
+ }
+
+ // Every good file ends with a new line.
+ sb.WriteString("\n")
+
+ return []lsp.TextEdit{
+ lsp.TextEdit{
+ Range: rangeToLSP(f.fullRange),
+ NewText: sb.String(),
+ },
+ }, nil
+ }
+ return nil, nil
+}
+func (s *server) RangeFormatting(ctx context.Context, p *lsp.DocumentRangeFormattingParams) ([]lsp.TextEdit, error) {
+ log.Println("server.RangeFormatting()")
+ return nil, nil
+}
+func (s *server) OnTypeFormatting(ctx context.Context, p *lsp.DocumentOnTypeFormattingParams) ([]lsp.TextEdit, error) {
+ log.Println("server.OnTypeFormatting()")
+ return nil, nil
+}
+func (s *server) Rename(ctx context.Context, p *lsp.RenameParams) (*lsp.WorkspaceEdit, error) {
+ log.Println("server.Rename()")
+ if f := s.getFile(p.TextDocument.URI); f != nil {
+ if tok := f.tokAt(p.Position); tok != nil {
+ if s := tok.Text(f.res.Lines); s != "" {
+ if id, ok := f.res.Identifiers[s]; ok {
+ changes := make([]lsp.TextEdit, len(id.References))
+ for i, r := range id.References {
+ changes[i].Range = rangeToLSP(r.Range)
+ changes[i].NewText = p.NewName
+ }
+ m := map[string][]lsp.TextEdit{}
+ m[p.TextDocument.URI] = changes
+ return &lsp.WorkspaceEdit{Changes: &m}, nil
+ }
+ }
+ }
+ }
+ return nil, nil
+}
+func (s *server) PrepareRename(ctx context.Context, p *lsp.PrepareRenameParams) (*lsp.Range, error) {
+ log.Println("server.PrepareRename()")
+ return nil, nil
+}
+func (s *server) ExecuteCommand(ctx context.Context, p *lsp.ExecuteCommandParams) (interface{}, error) {
+ log.Println("server.ExecuteCommand()")
+ return nil, nil
+}
+
+func (s *server) processFile(ctx context.Context, uri, source string) error {
+ log.Println("server.DidOpen()")
+ res, err := parser.Parse(source)
+ if err != nil {
+ return err
+ }
+ fullRange := parser.Range{
+ Start: parser.Position{Line: 1, Column: 1},
+ End: parser.Position{Line: len(res.Lines), Column: utf8.RuneCountInString(res.Lines[len(res.Lines)-1]) + 1},
+ }
+
+ s.filesMutex.Lock()
+ s.files[uri] = &file{
+ fullRange: fullRange,
+ res: res,
+ }
+ s.filesMutex.Unlock()
+
+ dp := lsp.PublishDiagnosticsParams{URI: uri, Diagnostics: make([]lsp.Diagnostic, len(res.Diagnostics))}
+ for i, d := range res.Diagnostics {
+ dp.Diagnostics[i] = diagnosticToLSP(d)
+ }
+ s.client.PublishDiagnostics(ctx, &dp)
+ return nil
+}
+
+func (s *server) getFile(uri string) *file {
+ s.filesMutex.Lock()
+ defer s.filesMutex.Unlock()
+ return s.files[uri]
+}
+
+func diagnosticToLSP(d parser.Diagnostic) lsp.Diagnostic {
+ return lsp.Diagnostic{
+ Range: rangeToLSP(d.Range),
+ Severity: severityToLSP(d.Severity),
+ Message: d.Message,
+ }
+}
+
+func severityToLSP(s parser.Severity) lsp.DiagnosticSeverity {
+ switch s {
+ case parser.SeverityError:
+ return lsp.SeverityError
+ case parser.SeverityWarning:
+ return lsp.SeverityWarning
+ case parser.SeverityInformation:
+ return lsp.SeverityInformation
+ case parser.SeverityHint:
+ return lsp.SeverityHint
+ default:
+ log.Panicf("Invalid severity '%d'", int(s))
+ return lsp.SeverityError
+ }
+}
+
+func rangeToLSP(r parser.Range) lsp.Range {
+ return lsp.Range{
+ Start: positionToLSP(r.Start),
+ End: positionToLSP(r.End),
+ }
+}
+
+func positionToLSP(r parser.Position) lsp.Position {
+ return lsp.Position{
+ Line: float64(r.Line - 1),
+ Character: float64(r.Column - 1),
+ }
+}
diff --git a/utils/vscode/src/lsp/LICENSE b/utils/vscode/src/lsp/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/utils/vscode/src/lsp/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/utils/vscode/src/lsp/README.md b/utils/vscode/src/lsp/README.md
new file mode 100644
index 0000000..c78f183
--- /dev/null
+++ b/utils/vscode/src/lsp/README.md
@@ -0,0 +1,5 @@
+This directory contains code forked from https://github.com/golang/tools/tree/master/internal/lsp.
+
+This code has been modified to remove unneeded features and dependencies.
+
+Submitted on behalf of a third-party: The Go Authors
diff --git a/utils/vscode/src/lsp/jsonrpc2/handler.go b/utils/vscode/src/lsp/jsonrpc2/handler.go
new file mode 100644
index 0000000..20d4841
--- /dev/null
+++ b/utils/vscode/src/lsp/jsonrpc2/handler.go
@@ -0,0 +1,134 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+package jsonrpc2
+
+import (
+ "context"
+)
+
+// Handler is the interface used to hook into the message handling of an rpc
+// connection.
+type Handler interface {
+ // Deliver is invoked to handle incoming requests.
+ // If the request returns false from IsNotify then the Handler must eventually
+ // call Reply on the Conn with the supplied request.
+ // Handlers are called synchronously, they should pass the work off to a go
+ // routine if they are going to take a long time.
+ // If Deliver returns true all subsequent handlers will be invoked with
+ // delivered set to true, and should not attempt to deliver the message.
+ Deliver(ctx context.Context, r *Request, delivered bool) bool
+
+ // Cancel is invoked for cancelled outgoing requests.
+ // It is okay to use the connection to send notifications, but the context will
+ // be in the cancelled state, so you must do it with the background context
+ // instead.
+ // If Cancel returns true all subsequent handlers will be invoked with
+ // cancelled set to true, and should not attempt to cancel the message.
+ Cancel(ctx context.Context, conn *Conn, id ID, cancelled bool) bool
+
+ // Log is invoked for all messages flowing through a Conn.
+ // direction indicates if the message being received or sent
+ // id is the message id, if not set it was a notification
+ // elapsed is the time between a call being seen and the response, and is
+ // negative for anything that is not a response.
+ // method is the method name specified in the message
+ // payload is the parameters for a call or notification, and the result for a
+ // response
+
+ // Request is called near the start of processing any request.
+ Request(ctx context.Context, conn *Conn, direction Direction, r *WireRequest) context.Context
+ // Response is called near the start of processing any response.
+ Response(ctx context.Context, conn *Conn, direction Direction, r *WireResponse) context.Context
+ // Done is called when any request is fully processed.
+ // For calls, this means the response has also been processed, for notifies
+ // this is as soon as the message has been written to the stream.
+ // If err is set, it implies the request failed.
+ Done(ctx context.Context, err error)
+ // Read is called with a count each time some data is read from the stream.
+ // The read calls are delayed until after the data has been interpreted so
+ // that it can be attributed to a request/response.
+ Read(ctx context.Context, bytes int64) context.Context
+ // Wrote is called each time some data is written to the stream.
+ Wrote(ctx context.Context, bytes int64) context.Context
+ // Error is called with errors that cannot be delivered through the normal
+ // mechanisms, for instance a failure to process a notify cannot be delivered
+ // back to the other party.
+ Error(ctx context.Context, err error)
+}
+
+// Direction is used to indicate to a logger whether the logged message was being
+// sent or received.
+type Direction bool
+
+const (
+ // Send indicates the message is outgoing.
+ Send = Direction(true)
+ // Receive indicates the message is incoming.
+ Receive = Direction(false)
+)
+
+func (d Direction) String() string {
+ switch d {
+ case Send:
+ return "send"
+ case Receive:
+ return "receive"
+ default:
+ panic("unreachable")
+ }
+}
+
+type EmptyHandler struct{}
+
+func (EmptyHandler) Deliver(ctx context.Context, r *Request, delivered bool) bool {
+ return false
+}
+
+func (EmptyHandler) Cancel(ctx context.Context, conn *Conn, id ID, cancelled bool) bool {
+ return false
+}
+
+func (EmptyHandler) Request(ctx context.Context, conn *Conn, direction Direction, r *WireRequest) context.Context {
+ return ctx
+}
+
+func (EmptyHandler) Response(ctx context.Context, conn *Conn, direction Direction, r *WireResponse) context.Context {
+ return ctx
+}
+
+func (EmptyHandler) Done(ctx context.Context, err error) {
+}
+
+func (EmptyHandler) Read(ctx context.Context, bytes int64) context.Context {
+ return ctx
+}
+
+func (EmptyHandler) Wrote(ctx context.Context, bytes int64) context.Context {
+ return ctx
+}
+
+func (EmptyHandler) Error(ctx context.Context, err error) {}
+
+type defaultHandler struct{ EmptyHandler }
+
+func (defaultHandler) Deliver(ctx context.Context, r *Request, delivered bool) bool {
+ if delivered {
+ return false
+ }
+ if !r.IsNotify() {
+ r.Reply(ctx, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method))
+ }
+ return true
+}
diff --git a/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go b/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go
new file mode 100644
index 0000000..b8436d2
--- /dev/null
+++ b/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go
@@ -0,0 +1,416 @@
+// Copyright 2018 The Go Authors.
+//
+// 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.
+
+// Package jsonrpc2 is a minimal implementation of the JSON RPC 2 spec.
+// https://www.jsonrpc.org/specification
+// It is intended to be compatible with other implementations at the wire level.
+package jsonrpc2
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "sync"
+ "sync/atomic"
+)
+
+// Conn is a JSON RPC 2 client server connection.
+// Conn is bidirectional; it does not have a designated server or client end.
+type Conn struct {
+ seq int64 // must only be accessed using atomic operations
+ handlers []Handler
+ stream Stream
+ err error
+ pendingMu sync.Mutex // protects the pending map
+ pending map[ID]chan *WireResponse
+ handlingMu sync.Mutex // protects the handling map
+ handling map[ID]*Request
+}
+
+type requestState int
+
+const (
+ requestWaiting = requestState(iota)
+ requestSerial
+ requestParallel
+ requestReplied
+ requestDone
+)
+
+// Request is sent to a server to represent a Call or Notify operaton.
+type Request struct {
+ conn *Conn
+ cancel context.CancelFunc
+ state requestState
+ nextRequest chan struct{}
+
+ // The Wire values of the request.
+ WireRequest
+}
+
+// NewErrorf builds a Error struct for the supplied message and code.
+// If args is not empty, message and args will be passed to Sprintf.
+func NewErrorf(code int64, format string, args ...interface{}) *Error {
+ return &Error{
+ Code: code,
+ Message: fmt.Sprintf(format, args...),
+ }
+}
+
+// NewConn creates a new connection object around the supplied stream.
+// You must call Run for the connection to be active.
+func NewConn(s Stream) *Conn {
+ conn := &Conn{
+ handlers: []Handler{defaultHandler{}},
+ stream: s,
+ pending: make(map[ID]chan *WireResponse),
+ handling: make(map[ID]*Request),
+ }
+ return conn
+}
+
+// AddHandler adds a new handler to the set the connection will invoke.
+// Handlers are invoked in the reverse order of how they were added, this
+// allows the most recent addition to be the first one to attempt to handle a
+// message.
+func (c *Conn) AddHandler(handler Handler) {
+ // prepend the new handlers so we use them first
+ c.handlers = append([]Handler{handler}, c.handlers...)
+}
+
+// Cancel cancels a pending Call on the server side.
+// The call is identified by its id.
+// JSON RPC 2 does not specify a cancel message, so cancellation support is not
+// directly wired in. This method allows a higher level protocol to choose how
+// to propagate the cancel.
+func (c *Conn) Cancel(id ID) {
+ c.handlingMu.Lock()
+ handling, found := c.handling[id]
+ c.handlingMu.Unlock()
+ if found {
+ handling.cancel()
+ }
+}
+
+// Notify is called to send a notification request over the connection.
+// It will return as soon as the notification has been sent, as no response is
+// possible.
+func (c *Conn) Notify(ctx context.Context, method string, params interface{}) (err error) {
+ jsonParams, err := marshalToRaw(params)
+ if err != nil {
+ return fmt.Errorf("marshalling notify parameters: %v", err)
+ }
+ request := &WireRequest{
+ Method: method,
+ Params: jsonParams,
+ }
+ data, err := json.Marshal(request)
+ if err != nil {
+ return fmt.Errorf("marshalling notify request: %v", err)
+ }
+ for _, h := range c.handlers {
+ ctx = h.Request(ctx, c, Send, request)
+ }
+ defer func() {
+ for _, h := range c.handlers {
+ h.Done(ctx, err)
+ }
+ }()
+ n, err := c.stream.Write(ctx, data)
+ for _, h := range c.handlers {
+ ctx = h.Wrote(ctx, n)
+ }
+ return err
+}
+
+// Call sends a request over the connection and then waits for a response.
+// If the response is not an error, it will be decoded into result.
+// result must be of a type you an pass to json.Unmarshal.
+func (c *Conn) Call(ctx context.Context, method string, params, result interface{}) (err error) {
+ // generate a new request identifier
+ id := ID{Number: atomic.AddInt64(&c.seq, 1)}
+ jsonParams, err := marshalToRaw(params)
+ if err != nil {
+ return fmt.Errorf("marshalling call parameters: %v", err)
+ }
+ request := &WireRequest{
+ ID: &id,
+ Method: method,
+ Params: jsonParams,
+ }
+ // marshal the request now it is complete
+ data, err := json.Marshal(request)
+ if err != nil {
+ return fmt.Errorf("marshalling call request: %v", err)
+ }
+ for _, h := range c.handlers {
+ ctx = h.Request(ctx, c, Send, request)
+ }
+ // we have to add ourselves to the pending map before we send, otherwise we
+ // are racing the response
+ rchan := make(chan *WireResponse)
+ c.pendingMu.Lock()
+ c.pending[id] = rchan
+ c.pendingMu.Unlock()
+ defer func() {
+ // clean up the pending response handler on the way out
+ c.pendingMu.Lock()
+ delete(c.pending, id)
+ c.pendingMu.Unlock()
+ for _, h := range c.handlers {
+ h.Done(ctx, err)
+ }
+ }()
+ // now we are ready to send
+ n, err := c.stream.Write(ctx, data)
+ for _, h := range c.handlers {
+ ctx = h.Wrote(ctx, n)
+ }
+ if err != nil {
+ // sending failed, we will never get a response, so don't leave it pending
+ return err
+ }
+ // now wait for the response
+ select {
+ case response := <-rchan:
+ for _, h := range c.handlers {
+ ctx = h.Response(ctx, c, Receive, response)
+ }
+ // is it an error response?
+ if response.Error != nil {
+ return response.Error
+ }
+ if result == nil || response.Result == nil {
+ return nil
+ }
+ if err := json.Unmarshal(*response.Result, result); err != nil {
+ return fmt.Errorf("unmarshalling result: %v", err)
+ }
+ return nil
+ case <-ctx.Done():
+ // allow the handler to propagate the cancel
+ cancelled := false
+ for _, h := range c.handlers {
+ if h.Cancel(ctx, c, id, cancelled) {
+ cancelled = true
+ }
+ }
+ return ctx.Err()
+ }
+}
+
+// Conn returns the connection that created this request.
+func (r *Request) Conn() *Conn { return r.conn }
+
+// IsNotify returns true if this request is a notification.
+func (r *Request) IsNotify() bool {
+ return r.ID == nil
+}
+
+// Parallel indicates that the system is now allowed to process other requests
+// in parallel with this one.
+// It is safe to call any number of times, but must only be called from the
+// request handling go routine.
+// It is implied by both reply and by the handler returning.
+func (r *Request) Parallel() {
+ if r.state >= requestParallel {
+ return
+ }
+ r.state = requestParallel
+ close(r.nextRequest)
+}
+
+// Reply sends a reply to the given request.
+// It is an error to call this if request was not a call.
+// You must call this exactly once for any given request.
+// It should only be called from the handler go routine.
+// If err is set then result will be ignored.
+// If the request has not yet dropped into parallel mode
+// it will be before this function returns.
+func (r *Request) Reply(ctx context.Context, result interface{}, err error) error {
+ if r.state >= requestReplied {
+ return fmt.Errorf("reply invoked more than once")
+ }
+ if r.IsNotify() {
+ return fmt.Errorf("reply not invoked with a valid call")
+ }
+ // reply ends the handling phase of a call, so if we are not yet
+ // parallel we should be now. The go routine is allowed to continue
+ // to do work after replying, which is why it is important to unlock
+ // the rpc system at this point.
+ r.Parallel()
+ r.state = requestReplied
+
+ var raw *json.RawMessage
+ if err == nil {
+ raw, err = marshalToRaw(result)
+ }
+ response := &WireResponse{
+ Result: raw,
+ ID: r.ID,
+ }
+ if err != nil {
+ if callErr, ok := err.(*Error); ok {
+ response.Error = callErr
+ } else {
+ response.Error = NewErrorf(0, "%s", err)
+ }
+ }
+ data, err := json.Marshal(response)
+ if err != nil {
+ return err
+ }
+ for _, h := range r.conn.handlers {
+ ctx = h.Response(ctx, r.conn, Send, response)
+ }
+ n, err := r.conn.stream.Write(ctx, data)
+ for _, h := range r.conn.handlers {
+ ctx = h.Wrote(ctx, n)
+ }
+
+ if err != nil {
+ // TODO(iancottrell): if a stream write fails, we really need to shut down
+ // the whole stream
+ return err
+ }
+ return nil
+}
+
+func (c *Conn) setHandling(r *Request, active bool) {
+ if r.ID == nil {
+ return
+ }
+ r.conn.handlingMu.Lock()
+ defer r.conn.handlingMu.Unlock()
+ if active {
+ r.conn.handling[*r.ID] = r
+ } else {
+ delete(r.conn.handling, *r.ID)
+ }
+}
+
+// combined has all the fields of both Request and Response.
+// We can decode this and then work out which it is.
+type combined struct {
+ VersionTag VersionTag `json:"jsonrpc"`
+ ID *ID `json:"id,omitempty"`
+ Method string `json:"method"`
+ Params *json.RawMessage `json:"params,omitempty"`
+ Result *json.RawMessage `json:"result,omitempty"`
+ Error *Error `json:"error,omitempty"`
+}
+
+// Run blocks until the connection is terminated, and returns any error that
+// caused the termination.
+// It must be called exactly once for each Conn.
+// It returns only when the reader is closed or there is an error in the stream.
+func (c *Conn) Run(runCtx context.Context) error {
+ // we need to make the next request "lock" in an unlocked state to allow
+ // the first incoming request to proceed. All later requests are unlocked
+ // by the preceding request going to parallel mode.
+ nextRequest := make(chan struct{})
+ close(nextRequest)
+ for {
+ // get the data for a message
+ data, n, err := c.stream.Read(runCtx)
+ if err != nil {
+ // the stream failed, we cannot continue
+ return err
+ }
+ // read a combined message
+ msg := &combined{}
+ if err := json.Unmarshal(data, msg); err != nil {
+ // a badly formed message arrived, log it and continue
+ // we trust the stream to have isolated the error to just this message
+ for _, h := range c.handlers {
+ h.Error(runCtx, fmt.Errorf("unmarshal failed: %v", err))
+ }
+ continue
+ }
+ // work out which kind of message we have
+ switch {
+ case msg.Method != "":
+ // if method is set it must be a request
+ reqCtx, cancelReq := context.WithCancel(runCtx)
+ thisRequest := nextRequest
+ nextRequest = make(chan struct{})
+ req := &Request{
+ conn: c,
+ cancel: cancelReq,
+ nextRequest: nextRequest,
+ WireRequest: WireRequest{
+ VersionTag: msg.VersionTag,
+ Method: msg.Method,
+ Params: msg.Params,
+ ID: msg.ID,
+ },
+ }
+ for _, h := range c.handlers {
+ reqCtx = h.Request(reqCtx, c, Receive, &req.WireRequest)
+ reqCtx = h.Read(reqCtx, n)
+ }
+ c.setHandling(req, true)
+ go func() {
+ <-thisRequest
+ req.state = requestSerial
+ defer func() {
+ c.setHandling(req, false)
+ if !req.IsNotify() && req.state < requestReplied {
+ req.Reply(reqCtx, nil, NewErrorf(CodeInternalError, "method %q did not reply", req.Method))
+ }
+ req.Parallel()
+ for _, h := range c.handlers {
+ h.Done(reqCtx, err)
+ }
+ cancelReq()
+ }()
+ delivered := false
+ for _, h := range c.handlers {
+ if h.Deliver(reqCtx, req, delivered) {
+ delivered = true
+ }
+ }
+ }()
+ case msg.ID != nil:
+ // we have a response, get the pending entry from the map
+ c.pendingMu.Lock()
+ rchan := c.pending[*msg.ID]
+ if rchan != nil {
+ delete(c.pending, *msg.ID)
+ }
+ c.pendingMu.Unlock()
+ // and send the reply to the channel
+ response := &WireResponse{
+ Result: msg.Result,
+ Error: msg.Error,
+ ID: msg.ID,
+ }
+ rchan <- response
+ close(rchan)
+ default:
+ for _, h := range c.handlers {
+ h.Error(runCtx, fmt.Errorf("message not a call, notify or response, ignoring"))
+ }
+ }
+ }
+}
+
+func marshalToRaw(obj interface{}) (*json.RawMessage, error) {
+ data, err := json.Marshal(obj)
+ if err != nil {
+ return nil, err
+ }
+ raw := json.RawMessage(data)
+ return &raw, nil
+}
diff --git a/utils/vscode/src/lsp/jsonrpc2/stream.go b/utils/vscode/src/lsp/jsonrpc2/stream.go
new file mode 100644
index 0000000..2c6ad6d
--- /dev/null
+++ b/utils/vscode/src/lsp/jsonrpc2/stream.go
@@ -0,0 +1,160 @@
+// Copyright 2018 The Go Authors.
+//
+// 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.
+
+package jsonrpc2
+
+import (
+ "bufio"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+// Stream abstracts the transport mechanics from the JSON RPC protocol.
+// A Conn reads and writes messages using the stream it was provided on
+// construction, and assumes that each call to Read or Write fully transfers
+// a single message, or returns an error.
+type Stream interface {
+ // Read gets the next message from the stream.
+ // It is never called concurrently.
+ Read(context.Context) ([]byte, int64, error)
+ // Write sends a message to the stream.
+ // It must be safe for concurrent use.
+ Write(context.Context, []byte) (int64, error)
+}
+
+// NewStream returns a Stream built on top of an io.Reader and io.Writer
+// The messages are sent with no wrapping, and rely on json decode consistency
+// to determine message boundaries.
+func NewStream(in io.Reader, out io.Writer) Stream {
+ return &plainStream{
+ in: json.NewDecoder(in),
+ out: out,
+ }
+}
+
+type plainStream struct {
+ in *json.Decoder
+ outMu sync.Mutex
+ out io.Writer
+}
+
+func (s *plainStream) Read(ctx context.Context) ([]byte, int64, error) {
+ select {
+ case <-ctx.Done():
+ return nil, 0, ctx.Err()
+ default:
+ }
+ var raw json.RawMessage
+ if err := s.in.Decode(&raw); err != nil {
+ return nil, 0, err
+ }
+ return raw, int64(len(raw)), nil
+}
+
+func (s *plainStream) Write(ctx context.Context, data []byte) (int64, error) {
+ select {
+ case <-ctx.Done():
+ return 0, ctx.Err()
+ default:
+ }
+ s.outMu.Lock()
+ n, err := s.out.Write(data)
+ s.outMu.Unlock()
+ return int64(n), err
+}
+
+// NewHeaderStream returns a Stream built on top of an io.Reader and io.Writer
+// The messages are sent with HTTP content length and MIME type headers.
+// This is the format used by LSP and others.
+func NewHeaderStream(in io.Reader, out io.Writer) Stream {
+ return &headerStream{
+ in: bufio.NewReader(in),
+ out: out,
+ }
+}
+
+type headerStream struct {
+ in *bufio.Reader
+ outMu sync.Mutex
+ out io.Writer
+}
+
+func (s *headerStream) Read(ctx context.Context) ([]byte, int64, error) {
+ select {
+ case <-ctx.Done():
+ return nil, 0, ctx.Err()
+ default:
+ }
+ var total, length int64
+ // read the header, stop on the first empty line
+ for {
+ line, err := s.in.ReadString('\n')
+ total += int64(len(line))
+ if err != nil {
+ return nil, total, fmt.Errorf("failed reading header line %q", err)
+ }
+ line = strings.TrimSpace(line)
+ // check we have a header line
+ if line == "" {
+ break
+ }
+ colon := strings.IndexRune(line, ':')
+ if colon < 0 {
+ return nil, total, fmt.Errorf("invalid header line %q", line)
+ }
+ name, value := line[:colon], strings.TrimSpace(line[colon+1:])
+ switch name {
+ case "Content-Length":
+ if length, err = strconv.ParseInt(value, 10, 32); err != nil {
+ return nil, total, fmt.Errorf("failed parsing Content-Length: %v", value)
+ }
+ if length <= 0 {
+ return nil, total, fmt.Errorf("invalid Content-Length: %v", length)
+ }
+ default:
+ // ignoring unknown headers
+ }
+ }
+ if length == 0 {
+ return nil, total, fmt.Errorf("missing Content-Length header")
+ }
+ data := make([]byte, length)
+ if _, err := io.ReadFull(s.in, data); err != nil {
+ return nil, total, err
+ }
+ total += length
+ return data, total, nil
+}
+
+func (s *headerStream) Write(ctx context.Context, data []byte) (int64, error) {
+ select {
+ case <-ctx.Done():
+ return 0, ctx.Err()
+ default:
+ }
+ s.outMu.Lock()
+ defer s.outMu.Unlock()
+ n, err := fmt.Fprintf(s.out, "Content-Length: %v\r\n\r\n", len(data))
+ total := int64(n)
+ if err == nil {
+ n, err = s.out.Write(data)
+ total += int64(n)
+ }
+ return total, err
+}
diff --git a/utils/vscode/src/lsp/jsonrpc2/wire.go b/utils/vscode/src/lsp/jsonrpc2/wire.go
new file mode 100644
index 0000000..3e31c34
--- /dev/null
+++ b/utils/vscode/src/lsp/jsonrpc2/wire.go
@@ -0,0 +1,148 @@
+// Copyright 2018 The Go Authors.
+//
+// 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.
+
+package jsonrpc2
+
+import (
+ "encoding/json"
+ "fmt"
+ "strconv"
+)
+
+// this file contains the go forms of the wire specification
+// see http://www.jsonrpc.org/specification for details
+
+const (
+ // CodeUnknownError should be used for all non coded errors.
+ CodeUnknownError = -32001
+ // CodeParseError is used when invalid JSON was received by the server.
+ CodeParseError = -32700
+ //CodeInvalidRequest is used when the JSON sent is not a valid Request object.
+ CodeInvalidRequest = -32600
+ // CodeMethodNotFound should be returned by the handler when the method does
+ // not exist / is not available.
+ CodeMethodNotFound = -32601
+ // CodeInvalidParams should be returned by the handler when method
+ // parameter(s) were invalid.
+ CodeInvalidParams = -32602
+ // CodeInternalError is not currently returned but defined for completeness.
+ CodeInternalError = -32603
+
+ //CodeServerOverloaded is returned when a message was refused due to a
+ //server being temporarily unable to accept any new messages.
+ CodeServerOverloaded = -32000
+)
+
+// WireRequest is sent to a server to represent a Call or Notify operaton.
+type WireRequest struct {
+ // VersionTag is always encoded as the string "2.0"
+ VersionTag VersionTag `json:"jsonrpc"`
+ // Method is a string containing the method name to invoke.
+ Method string `json:"method"`
+ // Params is either a struct or an array with the parameters of the method.
+ Params *json.RawMessage `json:"params,omitempty"`
+ // The id of this request, used to tie the Response back to the request.
+ // Will be either a string or a number. If not set, the Request is a notify,
+ // and no response is possible.
+ ID *ID `json:"id,omitempty"`
+}
+
+// WireResponse is a reply to a Request.
+// It will always have the ID field set to tie it back to a request, and will
+// have either the Result or Error fields set depending on whether it is a
+// success or failure response.
+type WireResponse struct {
+ // VersionTag is always encoded as the string "2.0"
+ VersionTag VersionTag `json:"jsonrpc"`
+ // Result is the response value, and is required on success.
+ Result *json.RawMessage `json:"result,omitempty"`
+ // Error is a structured error response if the call fails.
+ Error *Error `json:"error,omitempty"`
+ // ID must be set and is the identifier of the Request this is a response to.
+ ID *ID `json:"id,omitempty"`
+}
+
+// Error represents a structured error in a Response.
+type Error struct {
+ // Code is an error code indicating the type of failure.
+ Code int64 `json:"code"`
+ // Message is a short description of the error.
+ Message string `json:"message"`
+ // Data is optional structured data containing additional information about the error.
+ Data *json.RawMessage `json:"data"`
+}
+
+// VersionTag is a special 0 sized struct that encodes as the jsonrpc version
+// tag.
+// It will fail during decode if it is not the correct version tag in the
+// stream.
+type VersionTag struct{}
+
+// ID is a Request identifier.
+// Only one of either the Name or Number members will be set, using the
+// number form if the Name is the empty string.
+type ID struct {
+ Name string
+ Number int64
+}
+
+func (err *Error) Error() string {
+ if err == nil {
+ return ""
+ }
+ return err.Message
+}
+
+func (VersionTag) MarshalJSON() ([]byte, error) {
+ return json.Marshal("2.0")
+}
+
+func (VersionTag) UnmarshalJSON(data []byte) error {
+ version := ""
+ if err := json.Unmarshal(data, &version); err != nil {
+ return err
+ }
+ if version != "2.0" {
+ return fmt.Errorf("Invalid RPC version %v", version)
+ }
+ return nil
+}
+
+// String returns a string representation of the ID.
+// The representation is non ambiguous, string forms are quoted, number forms
+// are preceded by a #
+func (id *ID) String() string {
+ if id == nil {
+ return ""
+ }
+ if id.Name != "" {
+ return strconv.Quote(id.Name)
+ }
+ return "#" + strconv.FormatInt(id.Number, 10)
+}
+
+func (id *ID) MarshalJSON() ([]byte, error) {
+ if id.Name != "" {
+ return json.Marshal(id.Name)
+ }
+ return json.Marshal(id.Number)
+}
+
+func (id *ID) UnmarshalJSON(data []byte) error {
+ *id = ID{}
+ if err := json.Unmarshal(data, &id.Number); err == nil {
+ return nil
+ }
+ return json.Unmarshal(data, &id.Name)
+}
diff --git a/utils/vscode/src/lsp/protocol/context.go b/utils/vscode/src/lsp/protocol/context.go
new file mode 100644
index 0000000..7833d40
--- /dev/null
+++ b/utils/vscode/src/lsp/protocol/context.go
@@ -0,0 +1,29 @@
+// Copyright 2018 The Go Authors.
+//
+// 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.
+
+package protocol
+
+import (
+ "context"
+)
+
+type contextKey int
+
+const (
+ clientKey = contextKey(iota)
+)
+
+func WithClient(ctx context.Context, client Client) context.Context {
+ return context.WithValue(ctx, clientKey, client)
+}
diff --git a/utils/vscode/src/lsp/protocol/doc.go b/utils/vscode/src/lsp/protocol/doc.go
new file mode 100644
index 0000000..3c9198d
--- /dev/null
+++ b/utils/vscode/src/lsp/protocol/doc.go
@@ -0,0 +1,26 @@
+// Copyright 2018 The Go Authors.
+//
+// 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.
+
+// Package protocol contains the structs that map directly to the wire format
+// of the "Language Server Protocol".
+//
+// It is a literal transcription, with unmodified comments, and only the changes
+// required to make it go code.
+// Names are uppercased to export them.
+// All fields have JSON tags added to correct the names.
+// Fields marked with a ? are also marked as "omitempty"
+// Fields that are "|| null" are made pointers
+// Fields that are string or number are left as string
+// Fields that are type "number" are made float64
+package protocol
diff --git a/utils/vscode/src/lsp/protocol/enums.go b/utils/vscode/src/lsp/protocol/enums.go
new file mode 100644
index 0000000..db76ca3
--- /dev/null
+++ b/utils/vscode/src/lsp/protocol/enums.go
@@ -0,0 +1,256 @@
+// Copyright 2018 The Go Authors.
+//
+// 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.
+
+package protocol
+
+import (
+ "fmt"
+)
+
+var (
+ namesTextDocumentSyncKind [int(Incremental) + 1]string
+ namesInitializeError [int(UnknownProtocolVersion) + 1]string
+ namesMessageType [int(Log) + 1]string
+ namesFileChangeType [int(Deleted) + 1]string
+ namesWatchKind [int(WatchDelete) + 1]string
+ namesCompletionTriggerKind [int(TriggerForIncompleteCompletions) + 1]string
+ namesDiagnosticSeverity [int(SeverityHint) + 1]string
+ namesDiagnosticTag [int(Unnecessary) + 1]string
+ namesCompletionItemKind [int(TypeParameterCompletion) + 1]string
+ namesInsertTextFormat [int(SnippetTextFormat) + 1]string
+ namesDocumentHighlightKind [int(Write) + 1]string
+ namesSymbolKind [int(TypeParameter) + 1]string
+ namesTextDocumentSaveReason [int(FocusOut) + 1]string
+)
+
+func init() {
+ namesTextDocumentSyncKind[int(None)] = "None"
+ namesTextDocumentSyncKind[int(Full)] = "Full"
+ namesTextDocumentSyncKind[int(Incremental)] = "Incremental"
+
+ namesInitializeError[int(UnknownProtocolVersion)] = "UnknownProtocolVersion"
+
+ namesMessageType[int(Error)] = "Error"
+ namesMessageType[int(Warning)] = "Warning"
+ namesMessageType[int(Info)] = "Info"
+ namesMessageType[int(Log)] = "Log"
+
+ namesFileChangeType[int(Created)] = "Created"
+ namesFileChangeType[int(Changed)] = "Changed"
+ namesFileChangeType[int(Deleted)] = "Deleted"
+
+ namesWatchKind[int(WatchCreate)] = "WatchCreate"
+ namesWatchKind[int(WatchChange)] = "WatchChange"
+ namesWatchKind[int(WatchDelete)] = "WatchDelete"
+
+ namesCompletionTriggerKind[int(Invoked)] = "Invoked"
+ namesCompletionTriggerKind[int(TriggerCharacter)] = "TriggerCharacter"
+ namesCompletionTriggerKind[int(TriggerForIncompleteCompletions)] = "TriggerForIncompleteCompletions"
+
+ namesDiagnosticSeverity[int(SeverityError)] = "Error"
+ namesDiagnosticSeverity[int(SeverityWarning)] = "Warning"
+ namesDiagnosticSeverity[int(SeverityInformation)] = "Information"
+ namesDiagnosticSeverity[int(SeverityHint)] = "Hint"
+
+ namesDiagnosticTag[int(Unnecessary)] = "Unnecessary"
+
+ namesCompletionItemKind[int(TextCompletion)] = "text"
+ namesCompletionItemKind[int(MethodCompletion)] = "method"
+ namesCompletionItemKind[int(FunctionCompletion)] = "func"
+ namesCompletionItemKind[int(ConstructorCompletion)] = "constructor"
+ namesCompletionItemKind[int(FieldCompletion)] = "field"
+ namesCompletionItemKind[int(VariableCompletion)] = "var"
+ namesCompletionItemKind[int(ClassCompletion)] = "type"
+ namesCompletionItemKind[int(InterfaceCompletion)] = "interface"
+ namesCompletionItemKind[int(ModuleCompletion)] = "package"
+ namesCompletionItemKind[int(PropertyCompletion)] = "property"
+ namesCompletionItemKind[int(UnitCompletion)] = "unit"
+ namesCompletionItemKind[int(ValueCompletion)] = "value"
+ namesCompletionItemKind[int(EnumCompletion)] = "enum"
+ namesCompletionItemKind[int(KeywordCompletion)] = "keyword"
+ namesCompletionItemKind[int(SnippetCompletion)] = "snippet"
+ namesCompletionItemKind[int(ColorCompletion)] = "color"
+ namesCompletionItemKind[int(FileCompletion)] = "file"
+ namesCompletionItemKind[int(ReferenceCompletion)] = "reference"
+ namesCompletionItemKind[int(FolderCompletion)] = "folder"
+ namesCompletionItemKind[int(EnumMemberCompletion)] = "enumMember"
+ namesCompletionItemKind[int(ConstantCompletion)] = "const"
+ namesCompletionItemKind[int(StructCompletion)] = "struct"
+ namesCompletionItemKind[int(EventCompletion)] = "event"
+ namesCompletionItemKind[int(OperatorCompletion)] = "operator"
+ namesCompletionItemKind[int(TypeParameterCompletion)] = "typeParam"
+
+ namesInsertTextFormat[int(PlainTextTextFormat)] = "PlainText"
+ namesInsertTextFormat[int(SnippetTextFormat)] = "Snippet"
+
+ namesDocumentHighlightKind[int(Text)] = "Text"
+ namesDocumentHighlightKind[int(Read)] = "Read"
+ namesDocumentHighlightKind[int(Write)] = "Write"
+
+ namesSymbolKind[int(File)] = "File"
+ namesSymbolKind[int(Module)] = "Module"
+ namesSymbolKind[int(Namespace)] = "Namespace"
+ namesSymbolKind[int(Package)] = "Package"
+ namesSymbolKind[int(Class)] = "Class"
+ namesSymbolKind[int(Method)] = "Method"
+ namesSymbolKind[int(Property)] = "Property"
+ namesSymbolKind[int(Field)] = "Field"
+ namesSymbolKind[int(Constructor)] = "Constructor"
+ namesSymbolKind[int(Enum)] = "Enum"
+ namesSymbolKind[int(Interface)] = "Interface"
+ namesSymbolKind[int(Function)] = "Function"
+ namesSymbolKind[int(Variable)] = "Variable"
+ namesSymbolKind[int(Constant)] = "Constant"
+ namesSymbolKind[int(String)] = "String"
+ namesSymbolKind[int(Number)] = "Number"
+ namesSymbolKind[int(Boolean)] = "Boolean"
+ namesSymbolKind[int(Array)] = "Array"
+ namesSymbolKind[int(Object)] = "Object"
+ namesSymbolKind[int(Key)] = "Key"
+ namesSymbolKind[int(Null)] = "Null"
+ namesSymbolKind[int(EnumMember)] = "EnumMember"
+ namesSymbolKind[int(Struct)] = "Struct"
+ namesSymbolKind[int(Event)] = "Event"
+ namesSymbolKind[int(Operator)] = "Operator"
+ namesSymbolKind[int(TypeParameter)] = "TypeParameter"
+
+ namesTextDocumentSaveReason[int(Manual)] = "Manual"
+ namesTextDocumentSaveReason[int(AfterDelay)] = "AfterDelay"
+ namesTextDocumentSaveReason[int(FocusOut)] = "FocusOut"
+}
+
+func formatEnum(f fmt.State, c rune, i int, names []string, unknown string) {
+ s := ""
+ if i >= 0 && i < len(names) {
+ s = names[i]
+ }
+ if s != "" {
+ fmt.Fprint(f, s)
+ } else {
+ fmt.Fprintf(f, "%s(%d)", unknown, i)
+ }
+}
+
+func parseEnum(s string, names []string) int {
+ for i, name := range names {
+ if s == name {
+ return i
+ }
+ }
+ return 0
+}
+
+func (e TextDocumentSyncKind) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesTextDocumentSyncKind[:], "TextDocumentSyncKind")
+}
+
+func ParseTextDocumentSyncKind(s string) TextDocumentSyncKind {
+ return TextDocumentSyncKind(parseEnum(s, namesTextDocumentSyncKind[:]))
+}
+
+func (e InitializeError) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesInitializeError[:], "InitializeError")
+}
+
+func ParseInitializeError(s string) InitializeError {
+ return InitializeError(parseEnum(s, namesInitializeError[:]))
+}
+
+func (e MessageType) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesMessageType[:], "MessageType")
+}
+
+func ParseMessageType(s string) MessageType {
+ return MessageType(parseEnum(s, namesMessageType[:]))
+}
+
+func (e FileChangeType) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesFileChangeType[:], "FileChangeType")
+}
+
+func ParseFileChangeType(s string) FileChangeType {
+ return FileChangeType(parseEnum(s, namesFileChangeType[:]))
+}
+
+func (e WatchKind) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesWatchKind[:], "WatchKind")
+}
+
+func ParseWatchKind(s string) WatchKind {
+ return WatchKind(parseEnum(s, namesWatchKind[:]))
+}
+
+func (e CompletionTriggerKind) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesCompletionTriggerKind[:], "CompletionTriggerKind")
+}
+
+func ParseCompletionTriggerKind(s string) CompletionTriggerKind {
+ return CompletionTriggerKind(parseEnum(s, namesCompletionTriggerKind[:]))
+}
+
+func (e DiagnosticSeverity) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesDiagnosticSeverity[:], "DiagnosticSeverity")
+}
+
+func ParseDiagnosticSeverity(s string) DiagnosticSeverity {
+ return DiagnosticSeverity(parseEnum(s, namesDiagnosticSeverity[:]))
+}
+
+func (e DiagnosticTag) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesDiagnosticTag[:], "DiagnosticTag")
+}
+
+func ParseDiagnosticTag(s string) DiagnosticTag {
+ return DiagnosticTag(parseEnum(s, namesDiagnosticTag[:]))
+}
+
+func (e CompletionItemKind) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesCompletionItemKind[:], "CompletionItemKind")
+}
+
+func ParseCompletionItemKind(s string) CompletionItemKind {
+ return CompletionItemKind(parseEnum(s, namesCompletionItemKind[:]))
+}
+
+func (e InsertTextFormat) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesInsertTextFormat[:], "InsertTextFormat")
+}
+
+func ParseInsertTextFormat(s string) InsertTextFormat {
+ return InsertTextFormat(parseEnum(s, namesInsertTextFormat[:]))
+}
+
+func (e DocumentHighlightKind) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesDocumentHighlightKind[:], "DocumentHighlightKind")
+}
+
+func ParseDocumentHighlightKind(s string) DocumentHighlightKind {
+ return DocumentHighlightKind(parseEnum(s, namesDocumentHighlightKind[:]))
+}
+
+func (e SymbolKind) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesSymbolKind[:], "SymbolKind")
+}
+
+func ParseSymbolKind(s string) SymbolKind {
+ return SymbolKind(parseEnum(s, namesSymbolKind[:]))
+}
+
+func (e TextDocumentSaveReason) Format(f fmt.State, c rune) {
+ formatEnum(f, c, int(e), namesTextDocumentSaveReason[:], "TextDocumentSaveReason")
+}
+
+func ParseTextDocumentSaveReason(s string) TextDocumentSaveReason {
+ return TextDocumentSaveReason(parseEnum(s, namesTextDocumentSaveReason[:]))
+}
diff --git a/utils/vscode/src/lsp/protocol/log.go b/utils/vscode/src/lsp/protocol/log.go
new file mode 100644
index 0000000..f245881
--- /dev/null
+++ b/utils/vscode/src/lsp/protocol/log.go
@@ -0,0 +1,258 @@
+// Copyright 2018 The Go Authors.
+//
+// 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.
+
+package protocol
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "strings"
+ "sync"
+ "time"
+
+ "../jsonrpc2"
+)
+
+type loggingStream struct {
+ stream jsonrpc2.Stream
+ log io.Writer
+}
+
+// LoggingStream returns a stream that does LSP protocol logging too
+func LoggingStream(str jsonrpc2.Stream, w io.Writer) jsonrpc2.Stream {
+ return &loggingStream{str, w}
+}
+
+func (s *loggingStream) Read(ctx context.Context) ([]byte, int64, error) {
+ data, count, err := s.stream.Read(ctx)
+ if err == nil {
+ logIn(s.log, data)
+ }
+ return data, count, err
+}
+
+func (s *loggingStream) Write(ctx context.Context, data []byte) (int64, error) {
+ logOut(s.log, data)
+ count, err := s.stream.Write(ctx, data)
+ return count, err
+}
+
+// Combined has all the fields of both Request and Response.
+// We can decode this and then work out which it is.
+type Combined struct {
+ VersionTag jsonrpc2.VersionTag `json:"jsonrpc"`
+ ID *jsonrpc2.ID `json:"id,omitempty"`
+ Method string `json:"method"`
+ Params *json.RawMessage `json:"params,omitempty"`
+ Result *json.RawMessage `json:"result,omitempty"`
+ Error *jsonrpc2.Error `json:"error,omitempty"`
+}
+
+type req struct {
+ method string
+ start time.Time
+}
+
+type mapped struct {
+ mu sync.Mutex
+ clientCalls map[string]req
+ serverCalls map[string]req
+}
+
+var maps = &mapped{
+ sync.Mutex{},
+ make(map[string]req),
+ make(map[string]req),
+}
+
+// these 4 methods are each used exactly once, but it seemed
+// better to have the encapsulation rather than ad hoc mutex
+// code in 4 places
+func (m *mapped) client(id string, del bool) req {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ v := m.clientCalls[id]
+ if del {
+ delete(m.clientCalls, id)
+ }
+ return v
+}
+
+func (m *mapped) server(id string, del bool) req {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ v := m.serverCalls[id]
+ if del {
+ delete(m.serverCalls, id)
+ }
+ return v
+}
+
+func (m *mapped) setClient(id string, r req) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.clientCalls[id] = r
+}
+
+func (m *mapped) setServer(id string, r req) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.serverCalls[id] = r
+}
+
+const eor = "\r\n\r\n\r\n"
+
+func strID(x *jsonrpc2.ID) string {
+ if x == nil {
+ // should never happen, but we need a number
+ return "999999999"
+ }
+ if x.Name != "" {
+ return x.Name
+ }
+ return fmt.Sprintf("%d", x.Number)
+}
+
+func logCommon(outfd io.Writer, data []byte) (*Combined, time.Time, string) {
+ if outfd == nil {
+ return nil, time.Time{}, ""
+ }
+ var v Combined
+ err := json.Unmarshal(data, &v)
+ if err != nil {
+ fmt.Fprintf(outfd, "Unmarshal %v\n", err)
+ panic(err) // do better
+ }
+ tm := time.Now()
+ tmfmt := tm.Format("15:04:05.000 PM")
+ return &v, tm, tmfmt
+}
+
+// logOut and logIn could be combined. "received"<->"Sending", serverCalls<->clientCalls
+// but it wouldn't be a lot shorter or clearer and "shutdown" is a special case
+
+// Writing a message to the client, log it
+func logOut(outfd io.Writer, data []byte) {
+ v, tm, tmfmt := logCommon(outfd, data)
+ if v == nil {
+ return
+ }
+ if v.Error != nil {
+ id := strID(v.ID)
+ fmt.Fprintf(outfd, "[Error - %s] Received #%s %s%s", tmfmt, id, v.Error, eor)
+ return
+ }
+ buf := strings.Builder{}
+ id := strID(v.ID)
+ fmt.Fprintf(&buf, "[Trace - %s] ", tmfmt) // common beginning
+ if v.ID != nil && v.Method != "" && v.Params != nil {
+ fmt.Fprintf(&buf, "Received request '%s - (%s)'.\n", v.Method, id)
+ fmt.Fprintf(&buf, "Params: %s%s", *v.Params, eor)
+ maps.setServer(id, req{method: v.Method, start: tm})
+ } else if v.ID != nil && v.Method == "" && v.Params == nil {
+ cc := maps.client(id, true)
+ elapsed := tm.Sub(cc.start)
+ fmt.Fprintf(&buf, "Received response '%s - (%s)' in %dms.\n",
+ cc.method, id, elapsed/time.Millisecond)
+ if v.Result == nil {
+ fmt.Fprintf(&buf, "Result: {}%s", eor)
+ } else {
+ fmt.Fprintf(&buf, "Result: %s%s", string(*v.Result), eor)
+ }
+ } else if v.ID == nil && v.Method != "" && v.Params != nil {
+ p := "null"
+ if v.Params != nil {
+ p = string(*v.Params)
+ }
+ fmt.Fprintf(&buf, "Received notification '%s'.\n", v.Method)
+ fmt.Fprintf(&buf, "Params: %s%s", p, eor)
+ } else { // for completeness, as it should never happen
+ buf = strings.Builder{} // undo common Trace
+ fmt.Fprintf(&buf, "[Error - %s] on write ID?%v method:%q Params:%v Result:%v Error:%v%s",
+ tmfmt, v.ID != nil, v.Method, v.Params != nil,
+ v.Result != nil, v.Error != nil, eor)
+ p := "null"
+ if v.Params != nil {
+ p = string(*v.Params)
+ }
+ r := "null"
+ if v.Result != nil {
+ r = string(*v.Result)
+ }
+ fmt.Fprintf(&buf, "%s\n%s\n%s%s", p, r, v.Error, eor)
+ }
+ outfd.Write([]byte(buf.String()))
+}
+
+// Got a message from the client, log it
+func logIn(outfd io.Writer, data []byte) {
+ v, tm, tmfmt := logCommon(outfd, data)
+ if v == nil {
+ return
+ }
+ // ID Method Params => Sending request
+ // ID !Method Result(might be null, but !Params) => Sending response (could we get an Error?)
+ // !ID Method Params => Sending notification
+ if v.Error != nil { // does this ever happen?
+ id := strID(v.ID)
+ fmt.Fprintf(outfd, "[Error - %s] Sent #%s %s%s", tmfmt, id, v.Error, eor)
+ return
+ }
+ buf := strings.Builder{}
+ id := strID(v.ID)
+ fmt.Fprintf(&buf, "[Trace - %s] ", tmfmt) // common beginning
+ if v.ID != nil && v.Method != "" && (v.Params != nil || v.Method == "shutdown") {
+ fmt.Fprintf(&buf, "Sending request '%s - (%s)'.\n", v.Method, id)
+ x := "{}"
+ if v.Params != nil {
+ x = string(*v.Params)
+ }
+ fmt.Fprintf(&buf, "Params: %s%s", x, eor)
+ maps.setClient(id, req{method: v.Method, start: tm})
+ } else if v.ID != nil && v.Method == "" && v.Params == nil {
+ sc := maps.server(id, true)
+ elapsed := tm.Sub(sc.start)
+ fmt.Fprintf(&buf, "Sending response '%s - (%s)' took %dms.\n",
+ sc.method, id, elapsed/time.Millisecond)
+ if v.Result == nil {
+ fmt.Fprintf(&buf, "Result: {}%s", eor)
+ } else {
+ fmt.Fprintf(&buf, "Result: %s%s", string(*v.Result), eor)
+ }
+ } else if v.ID == nil && v.Method != "" {
+ p := "null"
+ if v.Params != nil {
+ p = string(*v.Params)
+ }
+ fmt.Fprintf(&buf, "Sending notification '%s'.\n", v.Method)
+ fmt.Fprintf(&buf, "Params: %s%s", p, eor)
+ } else { // for completeness, as it should never happen
+ buf = strings.Builder{} // undo common Trace
+ fmt.Fprintf(&buf, "[Error - %s] on read ID?%v method:%q Params:%v Result:%v Error:%v%s",
+ tmfmt, v.ID != nil, v.Method, v.Params != nil,
+ v.Result != nil, v.Error != nil, eor)
+ p := "null"
+ if v.Params != nil {
+ p = string(*v.Params)
+ }
+ r := "null"
+ if v.Result != nil {
+ r = string(*v.Result)
+ }
+ fmt.Fprintf(&buf, "%s\n%s\n%s%s", p, r, v.Error, eor)
+ }
+ outfd.Write([]byte(buf.String()))
+}
diff --git a/utils/vscode/src/lsp/protocol/protocol.go b/utils/vscode/src/lsp/protocol/protocol.go
new file mode 100644
index 0000000..e396c83
--- /dev/null
+++ b/utils/vscode/src/lsp/protocol/protocol.go
@@ -0,0 +1,86 @@
+// Copyright 2018 The Go Authors.
+//
+// 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.
+
+package protocol
+
+import (
+ "context"
+ "encoding/json"
+ "log"
+
+ "../jsonrpc2"
+)
+
+const (
+ // RequestCancelledError should be used when a request is cancelled early.
+ RequestCancelledError = -32800
+)
+
+type DocumentUri = string
+
+type canceller struct{ jsonrpc2.EmptyHandler }
+
+type clientHandler struct {
+ canceller
+ client Client
+}
+
+type serverHandler struct {
+ canceller
+ server Server
+}
+
+func (canceller) Request(ctx context.Context, conn *jsonrpc2.Conn, direction jsonrpc2.Direction, r *jsonrpc2.WireRequest) context.Context {
+ if direction == jsonrpc2.Receive && r.Method == "$/cancelRequest" {
+ var params CancelParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ log.Printf("%v", err)
+ } else {
+ conn.Cancel(params.ID)
+ }
+ }
+ return ctx
+}
+
+func (canceller) Cancel(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID, cancelled bool) bool {
+ if cancelled {
+ return false
+ }
+ conn.Notify(ctx, "$/cancelRequest", &CancelParams{ID: id})
+ return true
+}
+
+func NewClient(ctx context.Context, stream jsonrpc2.Stream, client Client) (context.Context, *jsonrpc2.Conn, Server) {
+ ctx = WithClient(ctx, client)
+ conn := jsonrpc2.NewConn(stream)
+ conn.AddHandler(&clientHandler{client: client})
+ return ctx, conn, &serverDispatcher{Conn: conn}
+}
+
+func NewServer(ctx context.Context, stream jsonrpc2.Stream, server Server) (context.Context, *jsonrpc2.Conn, Client) {
+ conn := jsonrpc2.NewConn(stream)
+ client := &clientDispatcher{Conn: conn}
+ ctx = WithClient(ctx, client)
+ conn.AddHandler(&serverHandler{server: server})
+ return ctx, conn, client
+}
+
+func sendParseError(ctx context.Context, req *jsonrpc2.Request, err error) {
+ if _, ok := err.(*jsonrpc2.Error); !ok {
+ err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
+ }
+ if err := req.Reply(ctx, nil, err); err != nil {
+ log.Printf("%v", err)
+ }
+}
diff --git a/utils/vscode/src/lsp/protocol/span.go b/utils/vscode/src/lsp/protocol/span.go
new file mode 100644
index 0000000..33cc2a6
--- /dev/null
+++ b/utils/vscode/src/lsp/protocol/span.go
@@ -0,0 +1,137 @@
+// Copyright 2018 The Go Authors.
+//
+// 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.
+
+// this file contains protocol<->span converters
+
+package protocol
+
+import (
+ "fmt"
+
+ "../span"
+ errors "golang.org/x/xerrors"
+)
+
+type ColumnMapper struct {
+ URI span.URI
+ Converter *span.TokenConverter
+ Content []byte
+}
+
+func NewURI(uri span.URI) string {
+ return string(uri)
+}
+
+func (m *ColumnMapper) Location(s span.Span) (Location, error) {
+ rng, err := m.Range(s)
+ if err != nil {
+ return Location{}, err
+ }
+ return Location{URI: NewURI(s.URI()), Range: rng}, nil
+}
+
+func (m *ColumnMapper) Range(s span.Span) (Range, error) {
+ if span.CompareURI(m.URI, s.URI()) != 0 {
+ return Range{}, errors.Errorf("column mapper is for file %q instead of %q", m.URI, s.URI())
+ }
+ s, err := s.WithAll(m.Converter)
+ if err != nil {
+ return Range{}, err
+ }
+ start, err := m.Position(s.Start())
+ if err != nil {
+ return Range{}, err
+ }
+ end, err := m.Position(s.End())
+ if err != nil {
+ return Range{}, err
+ }
+ return Range{Start: start, End: end}, nil
+}
+
+func (m *ColumnMapper) Position(p span.Point) (Position, error) {
+ chr, err := span.ToUTF16Column(p, m.Content)
+ if err != nil {
+ return Position{}, err
+ }
+ return Position{
+ Line: float64(p.Line() - 1),
+ Character: float64(chr - 1),
+ }, nil
+}
+
+func (m *ColumnMapper) Span(l Location) (span.Span, error) {
+ return m.RangeSpan(l.Range)
+}
+
+func (m *ColumnMapper) RangeSpan(r Range) (span.Span, error) {
+ start, err := m.Point(r.Start)
+ if err != nil {
+ return span.Span{}, err
+ }
+ end, err := m.Point(r.End)
+ if err != nil {
+ return span.Span{}, err
+ }
+ return span.New(m.URI, start, end).WithAll(m.Converter)
+}
+
+func (m *ColumnMapper) PointSpan(p Position) (span.Span, error) {
+ start, err := m.Point(p)
+ if err != nil {
+ return span.Span{}, err
+ }
+ return span.New(m.URI, start, start).WithAll(m.Converter)
+}
+
+func (m *ColumnMapper) Point(p Position) (span.Point, error) {
+ line := int(p.Line) + 1
+ offset, err := m.Converter.ToOffset(line, 1)
+ if err != nil {
+ return span.Point{}, err
+ }
+ lineStart := span.NewPoint(line, 1, offset)
+ return span.FromUTF16Column(lineStart, int(p.Character)+1, m.Content)
+}
+
+func IsPoint(r Range) bool {
+ return r.Start.Line == r.End.Line && r.Start.Character == r.End.Character
+}
+
+func CompareRange(a, b Range) int {
+ if r := ComparePosition(a.Start, b.Start); r != 0 {
+ return r
+ }
+ return ComparePosition(a.End, b.End)
+}
+
+func ComparePosition(a, b Position) int {
+ if a.Line < b.Line {
+ return -1
+ }
+ if a.Line > b.Line {
+ return 1
+ }
+ if a.Character < b.Character {
+ return -1
+ }
+ if a.Character > b.Character {
+ return 1
+ }
+ return 0
+}
+
+func (r Range) Format(f fmt.State, _ rune) {
+ fmt.Fprintf(f, "%v:%v-%v:%v", r.Start.Line, r.Start.Character, r.End.Line, r.End.Character)
+}
diff --git a/utils/vscode/src/lsp/protocol/tsclient.go b/utils/vscode/src/lsp/protocol/tsclient.go
new file mode 100644
index 0000000..2f9beef
--- /dev/null
+++ b/utils/vscode/src/lsp/protocol/tsclient.go
@@ -0,0 +1,221 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+package protocol
+
+import (
+ "context"
+ "encoding/json"
+ "log"
+
+ "../jsonrpc2"
+)
+
+type Client interface {
+ ShowMessage(context.Context, *ShowMessageParams) error
+ LogMessage(context.Context, *LogMessageParams) error
+ Event(context.Context, *interface{}) error
+ PublishDiagnostics(context.Context, *PublishDiagnosticsParams) error
+ WorkspaceFolders(context.Context) ([]WorkspaceFolder, error)
+ Configuration(context.Context, *ParamConfig) ([]interface{}, error)
+ RegisterCapability(context.Context, *RegistrationParams) error
+ UnregisterCapability(context.Context, *UnregistrationParams) error
+ ShowMessageRequest(context.Context, *ShowMessageRequestParams) (*MessageActionItem, error)
+ ApplyEdit(context.Context, *ApplyWorkspaceEditParams) (*ApplyWorkspaceEditResponse, error)
+}
+
+func (h clientHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
+ if delivered {
+ return false
+ }
+ if ctx.Err() != nil {
+ r.Reply(ctx, nil, jsonrpc2.NewErrorf(RequestCancelledError, ""))
+ return true
+ }
+ switch r.Method {
+ case "window/showMessage": // notif
+ var params ShowMessageParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.client.ShowMessage(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "window/logMessage": // notif
+ var params LogMessageParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.client.LogMessage(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "telemetry/event": // notif
+ var params interface{}
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.client.Event(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/publishDiagnostics": // notif
+ var params PublishDiagnosticsParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.client.PublishDiagnostics(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "workspace/workspaceFolders": // req
+ if r.Params != nil {
+ r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
+ return true
+ }
+ resp, err := h.client.WorkspaceFolders(ctx)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "workspace/configuration": // req
+ var params ParamConfig
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.client.Configuration(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "client/registerCapability": // req
+ var params RegistrationParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ err := h.client.RegisterCapability(ctx, ¶ms)
+ if err := r.Reply(ctx, nil, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "client/unregisterCapability": // req
+ var params UnregistrationParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ err := h.client.UnregisterCapability(ctx, ¶ms)
+ if err := r.Reply(ctx, nil, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "window/showMessageRequest": // req
+ var params ShowMessageRequestParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.client.ShowMessageRequest(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "workspace/applyEdit": // req
+ var params ApplyWorkspaceEditParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.client.ApplyEdit(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+
+ default:
+ return false
+ }
+}
+
+type clientDispatcher struct {
+ *jsonrpc2.Conn
+}
+
+func (s *clientDispatcher) ShowMessage(ctx context.Context, params *ShowMessageParams) error {
+ return s.Conn.Notify(ctx, "window/showMessage", params)
+}
+
+func (s *clientDispatcher) LogMessage(ctx context.Context, params *LogMessageParams) error {
+ return s.Conn.Notify(ctx, "window/logMessage", params)
+}
+
+func (s *clientDispatcher) Event(ctx context.Context, params *interface{}) error {
+ return s.Conn.Notify(ctx, "telemetry/event", params)
+}
+
+func (s *clientDispatcher) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) error {
+ return s.Conn.Notify(ctx, "textDocument/publishDiagnostics", params)
+}
+func (s *clientDispatcher) WorkspaceFolders(ctx context.Context) ([]WorkspaceFolder, error) {
+ var result []WorkspaceFolder
+ if err := s.Conn.Call(ctx, "workspace/workspaceFolders", nil, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *clientDispatcher) Configuration(ctx context.Context, params *ParamConfig) ([]interface{}, error) {
+ var result []interface{}
+ if err := s.Conn.Call(ctx, "workspace/configuration", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *clientDispatcher) RegisterCapability(ctx context.Context, params *RegistrationParams) error {
+ return s.Conn.Call(ctx, "client/registerCapability", params, nil) // Call, not Notify
+}
+
+func (s *clientDispatcher) UnregisterCapability(ctx context.Context, params *UnregistrationParams) error {
+ return s.Conn.Call(ctx, "client/unregisterCapability", params, nil) // Call, not Notify
+}
+
+func (s *clientDispatcher) ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (*MessageActionItem, error) {
+ var result MessageActionItem
+ if err := s.Conn.Call(ctx, "window/showMessageRequest", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *clientDispatcher) ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (*ApplyWorkspaceEditResponse, error) {
+ var result ApplyWorkspaceEditResponse
+ if err := s.Conn.Call(ctx, "workspace/applyEdit", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+// Types constructed to avoid structs as formal argument types
+type ParamConfig struct {
+ ConfigurationParams
+ PartialResultParams
+}
diff --git a/utils/vscode/src/lsp/protocol/tsprotocol.go b/utils/vscode/src/lsp/protocol/tsprotocol.go
new file mode 100644
index 0000000..50543fc
--- /dev/null
+++ b/utils/vscode/src/lsp/protocol/tsprotocol.go
@@ -0,0 +1,4630 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+// Package protocol contains data types and code for LSP jsonrpcs
+// generated automatically from vscode-languageserver-node
+// commit: 36ac51f057215e6e2e0408384e07ecf564a938da
+// last fetched Tue Sep 24 2019 17:44:28 GMT-0400 (Eastern Daylight Time)
+package protocol
+
+// Code generated (see typescript/README.md) DO NOT EDIT.
+
+/*ImplementationClientCapabilities defined:
+ * Since 3.6.0
+ */
+type ImplementationClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether implementation supports dynamic registration. If this is set to `true`
+ * the client supports the new `ImplementationRegistrationOptions` return value
+ * for the corresponding server capability as well.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*LinkSupport defined:
+ * The client supports additional metadata in the form of definition links.
+ *
+ * Since 3.14.0
+ */
+ LinkSupport bool `json:"linkSupport,omitempty"`
+}
+
+// ImplementationOptions is
+type ImplementationOptions struct {
+ WorkDoneProgressOptions
+}
+
+// ImplementationRegistrationOptions is
+type ImplementationRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ ImplementationOptions
+ StaticRegistrationOptions
+}
+
+// ImplementationParams is
+type ImplementationParams struct {
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*TypeDefinitionClientCapabilities defined:
+ * Since 3.6.0
+ */
+type TypeDefinitionClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether implementation supports dynamic registration. If this is set to `true`
+ * the client supports the new `TypeDefinitionRegistrationOptions` return value
+ * for the corresponding server capability as well.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*LinkSupport defined:
+ * The client supports additional metadata in the form of definition links.
+ *
+ * Since 3.14.0
+ */
+ LinkSupport bool `json:"linkSupport,omitempty"`
+}
+
+// TypeDefinitionOptions is
+type TypeDefinitionOptions struct {
+ WorkDoneProgressOptions
+}
+
+// TypeDefinitionRegistrationOptions is
+type TypeDefinitionRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ TypeDefinitionOptions
+ StaticRegistrationOptions
+}
+
+// TypeDefinitionParams is
+type TypeDefinitionParams struct {
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+// WorkspaceFoldersInitializeParams is
+type WorkspaceFoldersInitializeParams struct {
+
+ /*WorkspaceFolders defined:
+ * The actual configured workspace folders.
+ */
+ WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders"`
+}
+
+// WorkspaceFoldersClientCapabilities is
+type WorkspaceFoldersClientCapabilities struct {
+
+ /*Workspace defined:
+ * The workspace client capabilities
+ */
+ Workspace *struct {
+
+ /*WorkspaceFolders defined:
+ * The client has support for workspace folders
+ */
+ WorkspaceFolders bool `json:"workspaceFolders,omitempty"`
+ } `json:"workspace,omitempty"`
+}
+
+// WorkspaceFoldersServerCapabilities is
+type WorkspaceFoldersServerCapabilities struct {
+
+ /*Workspace defined:
+ * The workspace server capabilities
+ */
+ Workspace *struct {
+
+ // WorkspaceFolders is
+ WorkspaceFolders *struct {
+
+ /*Supported defined:
+ * The Server has support for workspace folders
+ */
+ Supported bool `json:"supported,omitempty"`
+
+ /*ChangeNotifications defined:
+ * Whether the server wants to receive workspace folder
+ * change notifications.
+ *
+ * If a strings is provided the string is treated as a ID
+ * under which the notification is registed on the client
+ * side. The ID can be used to unregister for these events
+ * using the `client/unregisterCapability` request.
+ */
+ ChangeNotifications string `json:"changeNotifications,omitempty"` // string | boolean
+ } `json:"workspaceFolders,omitempty"`
+ } `json:"workspace,omitempty"`
+}
+
+// WorkspaceFolder is
+type WorkspaceFolder struct {
+
+ /*URI defined:
+ * The associated URI for this workspace folder.
+ */
+ URI string `json:"uri"`
+
+ /*Name defined:
+ * The name of the workspace folder. Used to refer to this
+ * workspace folder in thge user interface.
+ */
+ Name string `json:"name"`
+}
+
+/*DidChangeWorkspaceFoldersParams defined:
+ * The parameters of a `workspace/didChangeWorkspaceFolders` notification.
+ */
+type DidChangeWorkspaceFoldersParams struct {
+
+ /*Event defined:
+ * The actual workspace folder change event.
+ */
+ Event WorkspaceFoldersChangeEvent `json:"event"`
+}
+
+/*WorkspaceFoldersChangeEvent defined:
+ * The workspace folder change event.
+ */
+type WorkspaceFoldersChangeEvent struct {
+
+ /*Added defined:
+ * The array of added workspace folders
+ */
+ Added []WorkspaceFolder `json:"added"`
+
+ /*Removed defined:
+ * The array of the removed workspace folders
+ */
+ Removed []WorkspaceFolder `json:"removed"`
+}
+
+// ConfigurationClientCapabilities is
+type ConfigurationClientCapabilities struct {
+
+ /*Workspace defined:
+ * The workspace client capabilities
+ */
+ Workspace *struct {
+
+ /*Configuration defined:
+ * The client supports `workspace/configuration` requests.
+ */
+ Configuration bool `json:"configuration,omitempty"`
+ } `json:"workspace,omitempty"`
+}
+
+// ConfigurationItem is
+type ConfigurationItem struct {
+
+ /*ScopeURI defined:
+ * The scope to get the configuration section for.
+ */
+ ScopeURI string `json:"scopeUri,omitempty"`
+
+ /*Section defined:
+ * The configuration section asked for.
+ */
+ Section string `json:"section,omitempty"`
+}
+
+/*ConfigurationParams defined:
+ * The parameters of a configuration request.
+ */
+type ConfigurationParams struct {
+
+ // Items is
+ Items []ConfigurationItem `json:"items"`
+}
+
+// DocumentColorClientCapabilities is
+type DocumentColorClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether implementation supports dynamic registration. If this is set to `true`
+ * the client supports the new `DocumentColorRegistrationOptions` return value
+ * for the corresponding server capability as well.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+// DocumentColorOptions is
+type DocumentColorOptions struct {
+
+ /*ResolveProvider defined:
+ * Code lens has a resolve provider as well.
+ */
+ ResolveProvider bool `json:"resolveProvider,omitempty"`
+ WorkDoneProgressOptions
+}
+
+// DocumentColorRegistrationOptions is
+type DocumentColorRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ StaticRegistrationOptions
+ DocumentColorOptions
+}
+
+/*DocumentColorParams defined:
+ * Parameters for a [DocumentColorRequest](#DocumentColorRequest).
+ */
+type DocumentColorParams struct {
+
+ /*TextDocument defined:
+ * The text document.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*ColorPresentationParams defined:
+ * Parameters for a [ColorPresentationRequest](#ColorPresentationRequest).
+ */
+type ColorPresentationParams struct {
+
+ /*TextDocument defined:
+ * The text document.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+
+ /*Color defined:
+ * The color to request presentations for.
+ */
+ Color Color `json:"color"`
+
+ /*Range defined:
+ * The range where the color would be inserted. Serves as a context.
+ */
+ Range Range `json:"range"`
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+// FoldingRangeClientCapabilities is
+type FoldingRangeClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether implementation supports dynamic registration for folding range providers. If this is set to `true`
+ * the client supports the new `FoldingRangeRegistrationOptions` return value for the corresponding server
+ * capability as well.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*RangeLimit defined:
+ * The maximum number of folding ranges that the client prefers to receive per document. The value serves as a
+ * hint, servers are free to follow the limit.
+ */
+ RangeLimit float64 `json:"rangeLimit,omitempty"`
+
+ /*LineFoldingOnly defined:
+ * If set, the client signals that it only supports folding complete lines. If set, client will
+ * ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange.
+ */
+ LineFoldingOnly bool `json:"lineFoldingOnly,omitempty"`
+}
+
+// FoldingRangeOptions is
+type FoldingRangeOptions struct {
+ WorkDoneProgressOptions
+}
+
+// FoldingRangeRegistrationOptions is
+type FoldingRangeRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ FoldingRangeOptions
+ StaticRegistrationOptions
+}
+
+/*FoldingRange defined:
+ * Represents a folding range.
+ */
+type FoldingRange struct {
+
+ /*StartLine defined:
+ * The zero-based line number from where the folded range starts.
+ */
+ StartLine float64 `json:"startLine"`
+
+ /*StartCharacter defined:
+ * The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line.
+ */
+ StartCharacter float64 `json:"startCharacter,omitempty"`
+
+ /*EndLine defined:
+ * The zero-based line number where the folded range ends.
+ */
+ EndLine float64 `json:"endLine"`
+
+ /*EndCharacter defined:
+ * The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line.
+ */
+ EndCharacter float64 `json:"endCharacter,omitempty"`
+
+ /*Kind defined:
+ * Describes the kind of the folding range such as `comment' or 'region'. The kind
+ * is used to categorize folding ranges and used by commands like 'Fold all comments'. See
+ * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds.
+ */
+ Kind string `json:"kind,omitempty"`
+}
+
+/*FoldingRangeParams defined:
+ * Parameters for a [FoldingRangeRequest](#FoldingRangeRequest).
+ */
+type FoldingRangeParams struct {
+
+ /*TextDocument defined:
+ * The text document.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*DeclarationClientCapabilities defined:
+ * Since 3.14.0
+ */
+type DeclarationClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether declaration supports dynamic registration. If this is set to `true`
+ * the client supports the new `DeclarationRegistrationOptions` return value
+ * for the corresponding server capability as well.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*LinkSupport defined:
+ * The client supports additional metadata in the form of declaration links.
+ */
+ LinkSupport bool `json:"linkSupport,omitempty"`
+}
+
+// DeclarationOptions is
+type DeclarationOptions struct {
+ WorkDoneProgressOptions
+}
+
+// DeclarationRegistrationOptions is
+type DeclarationRegistrationOptions struct {
+ DeclarationOptions
+ TextDocumentRegistrationOptions
+ StaticRegistrationOptions
+}
+
+// DeclarationParams is
+type DeclarationParams struct {
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+// SelectionRangeClientCapabilities is
+type SelectionRangeClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether implementation supports dynamic registration for selection range providers. If this is set to `true`
+ * the client supports the new `SelectionRangeRegistrationOptions` return value for the corresponding server
+ * capability as well.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+// SelectionRangeOptions is
+type SelectionRangeOptions struct {
+ WorkDoneProgressOptions
+}
+
+// SelectionRangeRegistrationOptions is
+type SelectionRangeRegistrationOptions struct {
+ SelectionRangeOptions
+ TextDocumentRegistrationOptions
+ StaticRegistrationOptions
+}
+
+/*SelectionRangeParams defined:
+ * A parameter literal used in selection range requests.
+ */
+type SelectionRangeParams struct {
+
+ /*TextDocument defined:
+ * The text document.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+
+ /*Positions defined:
+ * The positions inside the text document.
+ */
+ Positions []Position `json:"positions"`
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*Registration defined:
+ * General parameters to to register for an notification or to register a provider.
+ */
+type Registration struct {
+
+ /*ID defined:
+ * The id used to register the request. The id can be used to deregister
+ * the request again.
+ */
+ ID string `json:"id"`
+
+ /*Method defined:
+ * The method to register for.
+ */
+ Method string `json:"method"`
+
+ /*RegisterOptions defined:
+ * Options necessary for the registration.
+ */
+ RegisterOptions interface{} `json:"registerOptions,omitempty"`
+}
+
+// RegistrationParams is
+type RegistrationParams struct {
+
+ // Registrations is
+ Registrations []Registration `json:"registrations"`
+}
+
+/*Unregistration defined:
+ * General parameters to unregister a request or notification.
+ */
+type Unregistration struct {
+
+ /*ID defined:
+ * The id used to unregister the request or notification. Usually an id
+ * provided during the register request.
+ */
+ ID string `json:"id"`
+
+ /*Method defined:
+ * The method to unregister for.
+ */
+ Method string `json:"method"`
+}
+
+// UnregistrationParams is
+type UnregistrationParams struct {
+
+ // Unregisterations is
+ Unregisterations []Unregistration `json:"unregisterations"`
+}
+
+// WorkDoneProgressParams is
+type WorkDoneProgressParams struct {
+
+ /*WorkDoneToken defined:
+ * An optional token that a server can use to report work done progress.
+ */
+ WorkDoneToken *ProgressToken `json:"workDoneToken,omitempty"`
+}
+
+// PartialResultParams is
+type PartialResultParams struct {
+
+ /*PartialResultToken defined:
+ * An optional token that a server can use to report partial results (e.g. streaming) to
+ * the client.
+ */
+ PartialResultToken *ProgressToken `json:"partialResultToken,omitempty"`
+}
+
+/*TextDocumentPositionParams defined:
+ * A parameter literal used in requests to pass a text document and a position inside that
+ * document.
+ */
+type TextDocumentPositionParams struct {
+
+ /*TextDocument defined:
+ * The text document.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+
+ /*Position defined:
+ * The position inside the text document.
+ */
+ Position Position `json:"position"`
+}
+
+/*WorkspaceClientCapabilities defined:
+ * Workspace specific client capabilities.
+ */
+type WorkspaceClientCapabilities struct {
+
+ /*ApplyEdit defined:
+ * The client supports applying batch edits
+ * to the workspace by supporting the request
+ * 'workspace/applyEdit'
+ */
+ ApplyEdit bool `json:"applyEdit,omitempty"`
+
+ /*WorkspaceEdit defined:
+ * Capabilities specific to `WorkspaceEdit`s
+ */
+ WorkspaceEdit *WorkspaceEditClientCapabilities `json:"workspaceEdit,omitempty"`
+
+ /*DidChangeConfiguration defined:
+ * Capabilities specific to the `workspace/didChangeConfiguration` notification.
+ */
+ DidChangeConfiguration *DidChangeConfigurationClientCapabilities `json:"didChangeConfiguration,omitempty"`
+
+ /*DidChangeWatchedFiles defined:
+ * Capabilities specific to the `workspace/didChangeWatchedFiles` notification.
+ */
+ DidChangeWatchedFiles *DidChangeWatchedFilesClientCapabilities `json:"didChangeWatchedFiles,omitempty"`
+
+ /*Symbol defined:
+ * Capabilities specific to the `workspace/symbol` request.
+ */
+ Symbol *WorkspaceSymbolClientCapabilities `json:"symbol,omitempty"`
+
+ /*ExecuteCommand defined:
+ * Capabilities specific to the `workspace/executeCommand` request.
+ */
+ ExecuteCommand *ExecuteCommandClientCapabilities `json:"executeCommand,omitempty"`
+}
+
+/*TextDocumentClientCapabilities defined:
+ * Text document specific client capabilities.
+ */
+type TextDocumentClientCapabilities struct {
+
+ /*Synchronization defined:
+ * Defines which synchronization capabilities the client supports.
+ */
+ Synchronization *TextDocumentSyncClientCapabilities `json:"synchronization,omitempty"`
+
+ /*Completion defined:
+ * Capabilities specific to the `textDocument/completion`
+ */
+ Completion *CompletionClientCapabilities `json:"completion,omitempty"`
+
+ /*Hover defined:
+ * Capabilities specific to the `textDocument/hover`
+ */
+ Hover *HoverClientCapabilities `json:"hover,omitempty"`
+
+ /*SignatureHelp defined:
+ * Capabilities specific to the `textDocument/signatureHelp`
+ */
+ SignatureHelp *SignatureHelpClientCapabilities `json:"signatureHelp,omitempty"`
+
+ /*Declaration defined:
+ * Capabilities specific to the `textDocument/declaration`
+ *
+ * @since 3.14.0
+ */
+ Declaration *DeclarationClientCapabilities `json:"declaration,omitempty"`
+
+ /*Definition defined:
+ * Capabilities specific to the `textDocument/definition`
+ */
+ Definition *DefinitionClientCapabilities `json:"definition,omitempty"`
+
+ /*TypeDefinition defined:
+ * Capabilities specific to the `textDocument/typeDefinition`
+ *
+ * @since 3.6.0
+ */
+ TypeDefinition *TypeDefinitionClientCapabilities `json:"typeDefinition,omitempty"`
+
+ /*Implementation defined:
+ * Capabilities specific to the `textDocument/implementation`
+ *
+ * @since 3.6.0
+ */
+ Implementation *ImplementationClientCapabilities `json:"implementation,omitempty"`
+
+ /*References defined:
+ * Capabilities specific to the `textDocument/references`
+ */
+ References *ReferenceClientCapabilities `json:"references,omitempty"`
+
+ /*DocumentHighlight defined:
+ * Capabilities specific to the `textDocument/documentHighlight`
+ */
+ DocumentHighlight *DocumentHighlightClientCapabilities `json:"documentHighlight,omitempty"`
+
+ /*DocumentSymbol defined:
+ * Capabilities specific to the `textDocument/documentSymbol`
+ */
+ DocumentSymbol *DocumentSymbolClientCapabilities `json:"documentSymbol,omitempty"`
+
+ /*CodeAction defined:
+ * Capabilities specific to the `textDocument/codeAction`
+ */
+ CodeAction *CodeActionClientCapabilities `json:"codeAction,omitempty"`
+
+ /*CodeLens defined:
+ * Capabilities specific to the `textDocument/codeLens`
+ */
+ CodeLens *CodeLensClientCapabilities `json:"codeLens,omitempty"`
+
+ /*DocumentLink defined:
+ * Capabilities specific to the `textDocument/documentLink`
+ */
+ DocumentLink *DocumentLinkClientCapabilities `json:"documentLink,omitempty"`
+
+ /*ColorProvider defined:
+ * Capabilities specific to the `textDocument/documentColor`
+ */
+ ColorProvider *DocumentColorClientCapabilities `json:"colorProvider,omitempty"`
+
+ /*Formatting defined:
+ * Capabilities specific to the `textDocument/formatting`
+ */
+ Formatting *DocumentFormattingClientCapabilities `json:"formatting,omitempty"`
+
+ /*RangeFormatting defined:
+ * Capabilities specific to the `textDocument/rangeFormatting`
+ */
+ RangeFormatting *DocumentRangeFormattingClientCapabilities `json:"rangeFormatting,omitempty"`
+
+ /*OnTypeFormatting defined:
+ * Capabilities specific to the `textDocument/onTypeFormatting`
+ */
+ OnTypeFormatting *DocumentOnTypeFormattingClientCapabilities `json:"onTypeFormatting,omitempty"`
+
+ /*Rename defined:
+ * Capabilities specific to the `textDocument/rename`
+ */
+ Rename *RenameClientCapabilities `json:"rename,omitempty"`
+
+ /*FoldingRange defined:
+ * Capabilities specific to `textDocument/foldingRange` requests.
+ *
+ * @since 3.10.0
+ */
+ FoldingRange *FoldingRangeClientCapabilities `json:"foldingRange,omitempty"`
+
+ /*SelectionRange defined:
+ * Capabilities specific to `textDocument/selectionRange` requests
+ *
+ * @since 3.15.0
+ */
+ SelectionRange *SelectionRangeClientCapabilities `json:"selectionRange,omitempty"`
+
+ /*PublishDiagnostics defined:
+ * Capabilities specific to `textDocument/publishDiagnostics`.
+ */
+ PublishDiagnostics *PublishDiagnosticsClientCapabilities `json:"publishDiagnostics,omitempty"`
+}
+
+/*InnerClientCapabilities defined:
+ * Defines the capabilities provided by the client.
+ */
+type InnerClientCapabilities struct {
+
+ /*Workspace defined:
+ * Workspace specific client capabilities.
+ */
+ Workspace *WorkspaceClientCapabilities `json:"workspace,omitempty"`
+
+ /*TextDocument defined:
+ * Text document specific client capabilities.
+ */
+ TextDocument *TextDocumentClientCapabilities `json:"textDocument,omitempty"`
+
+ /*Window defined:
+ * Window specific client capabilities.
+ */
+ Window interface{} `json:"window,omitempty"`
+
+ /*Experimental defined:
+ * Experimental client capabilities.
+ */
+ Experimental interface{} `json:"experimental,omitempty"`
+}
+
+// ClientCapabilities is
+type ClientCapabilities struct {
+
+ /*Workspace defined:
+ * Workspace specific client capabilities.
+ */
+ Workspace struct {
+
+ /*ApplyEdit defined:
+ * The client supports applying batch edits
+ * to the workspace by supporting the request
+ * 'workspace/applyEdit'
+ */
+ ApplyEdit bool `json:"applyEdit,omitempty"`
+
+ /*WorkspaceEdit defined:
+ * Capabilities specific to `WorkspaceEdit`s
+ */
+ WorkspaceEdit WorkspaceEditClientCapabilities `json:"workspaceEdit,omitempty"`
+
+ /*DidChangeConfiguration defined:
+ * Capabilities specific to the `workspace/didChangeConfiguration` notification.
+ */
+ DidChangeConfiguration DidChangeConfigurationClientCapabilities `json:"didChangeConfiguration,omitempty"`
+
+ /*DidChangeWatchedFiles defined:
+ * Capabilities specific to the `workspace/didChangeWatchedFiles` notification.
+ */
+ DidChangeWatchedFiles DidChangeWatchedFilesClientCapabilities `json:"didChangeWatchedFiles,omitempty"`
+
+ /*Symbol defined:
+ * Capabilities specific to the `workspace/symbol` request.
+ */
+ Symbol WorkspaceSymbolClientCapabilities `json:"symbol,omitempty"`
+
+ /*ExecuteCommand defined:
+ * Capabilities specific to the `workspace/executeCommand` request.
+ */
+ ExecuteCommand ExecuteCommandClientCapabilities `json:"executeCommand,omitempty"`
+
+ /*WorkspaceFolders defined:
+ * The client has support for workspace folders
+ */
+ WorkspaceFolders bool `json:"workspaceFolders,omitempty"`
+
+ /*Configuration defined:
+ * The client supports `workspace/configuration` requests.
+ */
+ Configuration bool `json:"configuration,omitempty"`
+ } `json:"workspace,omitempty"`
+
+ /*TextDocument defined:
+ * Text document specific client capabilities.
+ */
+ TextDocument TextDocumentClientCapabilities `json:"textDocument,omitempty"`
+
+ /*Window defined:
+ * Window specific client capabilities.
+ */
+ Window interface{} `json:"window,omitempty"`
+
+ /*Experimental defined:
+ * Experimental client capabilities.
+ */
+ Experimental interface{} `json:"experimental,omitempty"`
+
+ /*DynamicRegistration defined:
+ * Whether implementation supports dynamic registration for selection range providers. If this is set to `true`
+ * the client supports the new `SelectionRangeRegistrationOptions` return value for the corresponding server
+ * capability as well.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+/*StaticRegistrationOptions defined:
+ * Static registration options to be returned in the initialize
+ * request.
+ */
+type StaticRegistrationOptions struct {
+
+ /*ID defined:
+ * The id used to register the request. The id can be used to deregister
+ * the request again. See also Registration#id.
+ */
+ ID string `json:"id,omitempty"`
+}
+
+/*TextDocumentRegistrationOptions defined:
+ * General text document registration options.
+ */
+type TextDocumentRegistrationOptions struct {
+
+ /*DocumentSelector defined:
+ * A document selector to identify the scope of the registration. If set to null
+ * the document selector provided on the client side will be used.
+ */
+ DocumentSelector DocumentSelector `json:"documentSelector"`
+}
+
+/*SaveOptions defined:
+ * Save options.
+ */
+type SaveOptions struct {
+
+ /*IncludeText defined:
+ * The client is supposed to include the content on save.
+ */
+ IncludeText bool `json:"includeText,omitempty"`
+}
+
+// WorkDoneProgressOptions is
+type WorkDoneProgressOptions struct {
+
+ // WorkDoneProgress is
+ WorkDoneProgress bool `json:"workDoneProgress,omitempty"`
+}
+
+/*InnerServerCapabilities defined:
+ * Defines the capabilities provided by a language
+ * server.
+ */
+type InnerServerCapabilities struct {
+
+ /*TextDocumentSync defined:
+ * Defines how text documents are synced. Is either a detailed structure defining each notification or
+ * for backwards compatibility the TextDocumentSyncKind number.
+ */
+ TextDocumentSync interface{} `json:"textDocumentSync,omitempty"` // TextDocumentSyncOptions | TextDocumentSyncKind
+
+ /*CompletionProvider defined:
+ * The server provides completion support.
+ */
+ CompletionProvider *CompletionOptions `json:"completionProvider,omitempty"`
+
+ /*HoverProvider defined:
+ * The server provides hover support.
+ */
+ HoverProvider bool `json:"hoverProvider,omitempty"` // boolean | HoverOptions
+
+ /*SignatureHelpProvider defined:
+ * The server provides signature help support.
+ */
+ SignatureHelpProvider *SignatureHelpOptions `json:"signatureHelpProvider,omitempty"`
+
+ /*DeclarationProvider defined:
+ * The server provides Goto Declaration support.
+ */
+ DeclarationProvider bool `json:"declarationProvider,omitempty"` // boolean | DeclarationOptions | DeclarationRegistrationOptions
+
+ /*DefinitionProvider defined:
+ * The server provides goto definition support.
+ */
+ DefinitionProvider bool `json:"definitionProvider,omitempty"` // boolean | DefinitionOptions
+
+ /*TypeDefinitionProvider defined:
+ * The server provides Goto Type Definition support.
+ */
+ TypeDefinitionProvider bool `json:"typeDefinitionProvider,omitempty"` // boolean | TypeDefinitionOptions | TypeDefinitionRegistrationOptions
+
+ /*ImplementationProvider defined:
+ * The server provides Goto Implementation support.
+ */
+ ImplementationProvider bool `json:"implementationProvider,omitempty"` // boolean | ImplementationOptions | ImplementationRegistrationOptions
+
+ /*ReferencesProvider defined:
+ * The server provides find references support.
+ */
+ ReferencesProvider bool `json:"referencesProvider,omitempty"` // boolean | ReferenceOptions
+
+ /*DocumentHighlightProvider defined:
+ * The server provides document highlight support.
+ */
+ DocumentHighlightProvider bool `json:"documentHighlightProvider,omitempty"` // boolean | DocumentHighlightOptions
+
+ /*DocumentSymbolProvider defined:
+ * The server provides document symbol support.
+ */
+ DocumentSymbolProvider bool `json:"documentSymbolProvider,omitempty"` // boolean | DocumentSymbolOptions
+
+ /*CodeActionProvider defined:
+ * The server provides code actions. CodeActionOptions may only be
+ * specified if the client states that it supports
+ * `codeActionLiteralSupport` in its initial `initialize` request.
+ */
+ CodeActionProvider interface{} `json:"codeActionProvider,omitempty"` // boolean | CodeActionOptions
+
+ /*CodeLensProvider defined:
+ * The server provides code lens.
+ */
+ CodeLensProvider *CodeLensOptions `json:"codeLensProvider,omitempty"`
+
+ /*DocumentLinkProvider defined:
+ * The server provides document link support.
+ */
+ DocumentLinkProvider *DocumentLinkOptions `json:"documentLinkProvider,omitempty"`
+
+ /*ColorProvider defined:
+ * The server provides color provider support.
+ */
+ ColorProvider bool `json:"colorProvider,omitempty"` // boolean | DocumentColorOptions | DocumentColorRegistrationOptions
+
+ /*WorkspaceSymbolProvider defined:
+ * The server provides workspace symbol support.
+ */
+ WorkspaceSymbolProvider bool `json:"workspaceSymbolProvider,omitempty"` // boolean | WorkspaceSymbolOptions
+
+ /*DocumentFormattingProvider defined:
+ * The server provides document formatting.
+ */
+ DocumentFormattingProvider bool `json:"documentFormattingProvider,omitempty"` // boolean | DocumentFormattingOptions
+
+ /*DocumentRangeFormattingProvider defined:
+ * The server provides document range formatting.
+ */
+ DocumentRangeFormattingProvider bool `json:"documentRangeFormattingProvider,omitempty"` // boolean | DocumentRangeFormattingOptions
+
+ /*DocumentOnTypeFormattingProvider defined:
+ * The server provides document formatting on typing.
+ */
+ DocumentOnTypeFormattingProvider *DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"`
+
+ /*RenameProvider defined:
+ * The server provides rename support. RenameOptions may only be
+ * specified if the client states that it supports
+ * `prepareSupport` in its initial `initialize` request.
+ */
+ RenameProvider interface{} `json:"renameProvider,omitempty"` // boolean | RenameOptions
+
+ /*FoldingRangeProvider defined:
+ * The server provides folding provider support.
+ */
+ FoldingRangeProvider bool `json:"foldingRangeProvider,omitempty"` // boolean | FoldingRangeOptions | FoldingRangeRegistrationOptions
+
+ /*SelectionRangeProvider defined:
+ * The server provides selection range support.
+ */
+ SelectionRangeProvider bool `json:"selectionRangeProvider,omitempty"` // boolean | SelectionRangeOptions | SelectionRangeRegistrationOptions
+
+ /*ExecuteCommandProvider defined:
+ * The server provides execute command support.
+ */
+ ExecuteCommandProvider *ExecuteCommandOptions `json:"executeCommandProvider,omitempty"`
+
+ /*Experimental defined:
+ * Experimental server capabilities.
+ */
+ Experimental interface{} `json:"experimental,omitempty"`
+}
+
+// ServerCapabilities is
+type ServerCapabilities struct {
+
+ /*TextDocumentSync defined:
+ * Defines how text documents are synced. Is either a detailed structure defining each notification or
+ * for backwards compatibility the TextDocumentSyncKind number.
+ */
+ TextDocumentSync interface{} `json:"textDocumentSync,omitempty"` // TextDocumentSyncOptions | TextDocumentSyncKind
+
+ /*CompletionProvider defined:
+ * The server provides completion support.
+ */
+ CompletionProvider *CompletionOptions `json:"completionProvider,omitempty"`
+
+ /*HoverProvider defined:
+ * The server provides hover support.
+ */
+ HoverProvider bool `json:"hoverProvider,omitempty"` // boolean | HoverOptions
+
+ /*SignatureHelpProvider defined:
+ * The server provides signature help support.
+ */
+ SignatureHelpProvider *SignatureHelpOptions `json:"signatureHelpProvider,omitempty"`
+
+ /*DeclarationProvider defined:
+ * The server provides Goto Declaration support.
+ */
+ DeclarationProvider bool `json:"declarationProvider,omitempty"` // boolean | DeclarationOptions | DeclarationRegistrationOptions
+
+ /*DefinitionProvider defined:
+ * The server provides goto definition support.
+ */
+ DefinitionProvider bool `json:"definitionProvider,omitempty"` // boolean | DefinitionOptions
+
+ /*TypeDefinitionProvider defined:
+ * The server provides Goto Type Definition support.
+ */
+ TypeDefinitionProvider bool `json:"typeDefinitionProvider,omitempty"` // boolean | TypeDefinitionOptions | TypeDefinitionRegistrationOptions
+
+ /*ImplementationProvider defined:
+ * The server provides Goto Implementation support.
+ */
+ ImplementationProvider bool `json:"implementationProvider,omitempty"` // boolean | ImplementationOptions | ImplementationRegistrationOptions
+
+ /*ReferencesProvider defined:
+ * The server provides find references support.
+ */
+ ReferencesProvider bool `json:"referencesProvider,omitempty"` // boolean | ReferenceOptions
+
+ /*DocumentHighlightProvider defined:
+ * The server provides document highlight support.
+ */
+ DocumentHighlightProvider bool `json:"documentHighlightProvider,omitempty"` // boolean | DocumentHighlightOptions
+
+ /*DocumentSymbolProvider defined:
+ * The server provides document symbol support.
+ */
+ DocumentSymbolProvider bool `json:"documentSymbolProvider,omitempty"` // boolean | DocumentSymbolOptions
+
+ /*CodeActionProvider defined:
+ * The server provides code actions. CodeActionOptions may only be
+ * specified if the client states that it supports
+ * `codeActionLiteralSupport` in its initial `initialize` request.
+ */
+ CodeActionProvider interface{} `json:"codeActionProvider,omitempty"` // boolean | CodeActionOptions
+
+ /*CodeLensProvider defined:
+ * The server provides code lens.
+ */
+ CodeLensProvider *CodeLensOptions `json:"codeLensProvider,omitempty"`
+
+ /*DocumentLinkProvider defined:
+ * The server provides document link support.
+ */
+ DocumentLinkProvider *DocumentLinkOptions `json:"documentLinkProvider,omitempty"`
+
+ /*ColorProvider defined:
+ * The server provides color provider support.
+ */
+ ColorProvider bool `json:"colorProvider,omitempty"` // boolean | DocumentColorOptions | DocumentColorRegistrationOptions
+
+ /*WorkspaceSymbolProvider defined:
+ * The server provides workspace symbol support.
+ */
+ WorkspaceSymbolProvider bool `json:"workspaceSymbolProvider,omitempty"` // boolean | WorkspaceSymbolOptions
+
+ /*DocumentFormattingProvider defined:
+ * The server provides document formatting.
+ */
+ DocumentFormattingProvider bool `json:"documentFormattingProvider,omitempty"` // boolean | DocumentFormattingOptions
+
+ /*DocumentRangeFormattingProvider defined:
+ * The server provides document range formatting.
+ */
+ DocumentRangeFormattingProvider bool `json:"documentRangeFormattingProvider,omitempty"` // boolean | DocumentRangeFormattingOptions
+
+ /*DocumentOnTypeFormattingProvider defined:
+ * The server provides document formatting on typing.
+ */
+ DocumentOnTypeFormattingProvider *DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"`
+
+ /*RenameProvider defined:
+ * The server provides rename support. RenameOptions may only be
+ * specified if the client states that it supports
+ * `prepareSupport` in its initial `initialize` request.
+ */
+ RenameProvider interface{} `json:"renameProvider,omitempty"` // boolean | RenameOptions
+
+ /*FoldingRangeProvider defined:
+ * The server provides folding provider support.
+ */
+ FoldingRangeProvider bool `json:"foldingRangeProvider,omitempty"` // boolean | FoldingRangeOptions | FoldingRangeRegistrationOptions
+
+ /*SelectionRangeProvider defined:
+ * The server provides selection range support.
+ */
+ SelectionRangeProvider bool `json:"selectionRangeProvider,omitempty"` // boolean | SelectionRangeOptions | SelectionRangeRegistrationOptions
+
+ /*ExecuteCommandProvider defined:
+ * The server provides execute command support.
+ */
+ ExecuteCommandProvider *ExecuteCommandOptions `json:"executeCommandProvider,omitempty"`
+
+ /*Experimental defined:
+ * Experimental server capabilities.
+ */
+ Experimental interface{} `json:"experimental,omitempty"`
+
+ /*Workspace defined:
+ * The workspace server capabilities
+ */
+ Workspace *struct {
+
+ // WorkspaceFolders is
+ WorkspaceFolders *struct {
+
+ /*Supported defined:
+ * The Server has support for workspace folders
+ */
+ Supported bool `json:"supported,omitempty"`
+
+ /*ChangeNotifications defined:
+ * Whether the server wants to receive workspace folder
+ * change notifications.
+ *
+ * If a strings is provided the string is treated as a ID
+ * under which the notification is registed on the client
+ * side. The ID can be used to unregister for these events
+ * using the `client/unregisterCapability` request.
+ */
+ ChangeNotifications string `json:"changeNotifications,omitempty"` // string | boolean
+ } `json:"workspaceFolders,omitempty"`
+ } `json:"workspace,omitempty"`
+}
+
+/*InnerInitializeParams defined:
+ * The initialize parameters
+ */
+type InnerInitializeParams struct {
+
+ /*ProcessID defined:
+ * The process Id of the parent process that started
+ * the server.
+ */
+ ProcessID float64 `json:"processId"`
+
+ /*ClientInfo defined:
+ * Information about the client
+ *
+ * @since 3.15.0
+ */
+ ClientInfo *struct {
+
+ /*Name defined:
+ * The name of the client as defined by the client.
+ */
+ Name string `json:"name"`
+
+ /*Version defined:
+ * The client's version as defined by the client.
+ */
+ Version string `json:"version,omitempty"`
+ } `json:"clientInfo,omitempty"`
+
+ /*RootPath defined:
+ * The rootPath of the workspace. Is null
+ * if no folder is open.
+ *
+ * @deprecated in favour of rootUri.
+ */
+ RootPath string `json:"rootPath,omitempty"`
+
+ /*RootURI defined:
+ * The rootUri of the workspace. Is null if no
+ * folder is open. If both `rootPath` and `rootUri` are set
+ * `rootUri` wins.
+ *
+ * @deprecated in favour of workspaceFolders.
+ */
+ RootURI DocumentURI `json:"rootUri"`
+
+ /*Capabilities defined:
+ * The capabilities provided by the client (editor or tool)
+ */
+ Capabilities ClientCapabilities `json:"capabilities"`
+
+ /*InitializationOptions defined:
+ * User provided initialization options.
+ */
+ InitializationOptions interface{} `json:"initializationOptions,omitempty"`
+
+ /*Trace defined:
+ * The initial trace setting. If omitted trace is disabled ('off').
+ */
+ Trace string `json:"trace,omitempty"` // 'off' | 'messages' | 'verbose'
+ WorkDoneProgressParams
+}
+
+// InitializeParams is
+type InitializeParams struct {
+
+ /*ProcessID defined:
+ * The process Id of the parent process that started
+ * the server.
+ */
+ ProcessID float64 `json:"processId"`
+
+ /*ClientInfo defined:
+ * Information about the client
+ *
+ * @since 3.15.0
+ */
+ ClientInfo *struct {
+
+ /*Name defined:
+ * The name of the client as defined by the client.
+ */
+ Name string `json:"name"`
+
+ /*Version defined:
+ * The client's version as defined by the client.
+ */
+ Version string `json:"version,omitempty"`
+ } `json:"clientInfo,omitempty"`
+
+ /*RootPath defined:
+ * The rootPath of the workspace. Is null
+ * if no folder is open.
+ *
+ * @deprecated in favour of rootUri.
+ */
+ RootPath string `json:"rootPath,omitempty"`
+
+ /*RootURI defined:
+ * The rootUri of the workspace. Is null if no
+ * folder is open. If both `rootPath` and `rootUri` are set
+ * `rootUri` wins.
+ *
+ * @deprecated in favour of workspaceFolders.
+ */
+ RootURI DocumentURI `json:"rootUri"`
+
+ /*Capabilities defined:
+ * The capabilities provided by the client (editor or tool)
+ */
+ Capabilities ClientCapabilities `json:"capabilities"`
+
+ /*InitializationOptions defined:
+ * User provided initialization options.
+ */
+ InitializationOptions interface{} `json:"initializationOptions,omitempty"`
+
+ /*Trace defined:
+ * The initial trace setting. If omitted trace is disabled ('off').
+ */
+ Trace string `json:"trace,omitempty"` // 'off' | 'messages' | 'verbose'
+
+ /*WorkspaceFolders defined:
+ * The actual configured workspace folders.
+ */
+ WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders"`
+}
+
+/*InitializeResult defined:
+ * The result returned from an initialize request.
+ */
+type InitializeResult struct {
+
+ /*Capabilities defined:
+ * The capabilities the language server provides.
+ */
+ Capabilities ServerCapabilities `json:"capabilities"`
+
+ /*ServerInfo defined:
+ * Information about the server.
+ *
+ * @since 3.15.0
+ */
+ ServerInfo *struct {
+
+ /*Name defined:
+ * The name of the server as defined by the server.
+ */
+ Name string `json:"name"`
+
+ /*Version defined:
+ * The servers's version as defined by the server.
+ */
+ Version string `json:"version,omitempty"`
+ } `json:"serverInfo,omitempty"`
+
+ /*Custom defined:
+ * Custom initialization results.
+ */
+ Custom map[string]interface{} `json:"custom"` // [custom: string]: any;
+}
+
+// InitializedParams is
+type InitializedParams struct {
+}
+
+// DidChangeConfigurationClientCapabilities is
+type DidChangeConfigurationClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Did change configuration notification supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+// DidChangeConfigurationRegistrationOptions is
+type DidChangeConfigurationRegistrationOptions struct {
+
+ // Section is
+ Section string `json:"section,omitempty"` // string | string[]
+}
+
+/*DidChangeConfigurationParams defined:
+ * The parameters of a change configuration notification.
+ */
+type DidChangeConfigurationParams struct {
+
+ /*Settings defined:
+ * The actual changed settings
+ */
+ Settings interface{} `json:"settings"`
+}
+
+/*ShowMessageParams defined:
+ * The parameters of a notification message.
+ */
+type ShowMessageParams struct {
+
+ /*Type defined:
+ * The message type. See {@link MessageType}
+ */
+ Type MessageType `json:"type"`
+
+ /*Message defined:
+ * The actual message
+ */
+ Message string `json:"message"`
+}
+
+// MessageActionItem is
+type MessageActionItem struct {
+
+ /*Title defined:
+ * A short title like 'Retry', 'Open Log' etc.
+ */
+ Title string `json:"title"`
+}
+
+// ShowMessageRequestParams is
+type ShowMessageRequestParams struct {
+
+ /*Type defined:
+ * The message type. See {@link MessageType}
+ */
+ Type MessageType `json:"type"`
+
+ /*Message defined:
+ * The actual message
+ */
+ Message string `json:"message"`
+
+ /*Actions defined:
+ * The message action items to present.
+ */
+ Actions []MessageActionItem `json:"actions,omitempty"`
+}
+
+/*LogMessageParams defined:
+ * The log message parameters.
+ */
+type LogMessageParams struct {
+
+ /*Type defined:
+ * The message type. See {@link MessageType}
+ */
+ Type MessageType `json:"type"`
+
+ /*Message defined:
+ * The actual message
+ */
+ Message string `json:"message"`
+}
+
+// TextDocumentSyncClientCapabilities is
+type TextDocumentSyncClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether text document synchronization supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*WillSave defined:
+ * The client supports sending will save notifications.
+ */
+ WillSave bool `json:"willSave,omitempty"`
+
+ /*WillSaveWaitUntil defined:
+ * The client supports sending a will save request and
+ * waits for a response providing text edits which will
+ * be applied to the document before it is saved.
+ */
+ WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"`
+
+ /*DidSave defined:
+ * The client supports did save notifications.
+ */
+ DidSave bool `json:"didSave,omitempty"`
+}
+
+// TextDocumentSyncOptions is
+type TextDocumentSyncOptions struct {
+
+ /*OpenClose defined:
+ * Open and close notifications are sent to the server. If omitted open close notification should not
+ * be sent.
+ */
+ OpenClose bool `json:"openClose,omitempty"`
+
+ /*Change defined:
+ * Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full
+ * and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None.
+ */
+ Change TextDocumentSyncKind `json:"change,omitempty"`
+
+ /*WillSave defined:
+ * If present will save notifications are sent to the server. If omitted the notification should not be
+ * sent.
+ */
+ WillSave bool `json:"willSave,omitempty"`
+
+ /*WillSaveWaitUntil defined:
+ * If present will save wait until requests are sent to the server. If omitted the request should not be
+ * sent.
+ */
+ WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"`
+
+ /*Save defined:
+ * If present save notifications are sent to the server. If omitted the notification should not be
+ * sent.
+ */
+ Save *SaveOptions `json:"save,omitempty"`
+}
+
+/*DidOpenTextDocumentParams defined:
+ * The parameters send in a open text document notification
+ */
+type DidOpenTextDocumentParams struct {
+
+ /*TextDocument defined:
+ * The document that was opened.
+ */
+ TextDocument TextDocumentItem `json:"textDocument"`
+}
+
+/*DidChangeTextDocumentParams defined:
+ * The change text document notification's parameters.
+ */
+type DidChangeTextDocumentParams struct {
+
+ /*TextDocument defined:
+ * The document that did change. The version number points
+ * to the version after all provided content changes have
+ * been applied.
+ */
+ TextDocument VersionedTextDocumentIdentifier `json:"textDocument"`
+
+ /*ContentChanges defined:
+ * The actual content changes. The content changes describe single state changes
+ * to the document. So if there are two content changes c1 and c2 for a document
+ * in state S then c1 move the document to S' and c2 to S''.
+ */
+ ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"`
+}
+
+/*TextDocumentChangeRegistrationOptions defined:
+ * Describe options to be used when registered for text document change events.
+ */
+type TextDocumentChangeRegistrationOptions struct {
+
+ /*SyncKind defined:
+ * How documents are synced to the server.
+ */
+ SyncKind TextDocumentSyncKind `json:"syncKind"`
+ TextDocumentRegistrationOptions
+}
+
+/*DidCloseTextDocumentParams defined:
+ * The parameters send in a close text document notification
+ */
+type DidCloseTextDocumentParams struct {
+
+ /*TextDocument defined:
+ * The document that was closed.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+}
+
+/*DidSaveTextDocumentParams defined:
+ * The parameters send in a save text document notification
+ */
+type DidSaveTextDocumentParams struct {
+
+ /*TextDocument defined:
+ * The document that was closed.
+ */
+ TextDocument VersionedTextDocumentIdentifier `json:"textDocument"`
+
+ /*Text defined:
+ * Optional the content when saved. Depends on the includeText value
+ * when the save notification was requested.
+ */
+ Text string `json:"text,omitempty"`
+}
+
+/*TextDocumentSaveRegistrationOptions defined:
+ * Save registration options.
+ */
+type TextDocumentSaveRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ SaveOptions
+}
+
+/*WillSaveTextDocumentParams defined:
+ * The parameters send in a will save text document notification.
+ */
+type WillSaveTextDocumentParams struct {
+
+ /*TextDocument defined:
+ * The document that will be saved.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+
+ /*Reason defined:
+ * The 'TextDocumentSaveReason'.
+ */
+ Reason TextDocumentSaveReason `json:"reason"`
+}
+
+// DidChangeWatchedFilesClientCapabilities is
+type DidChangeWatchedFilesClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Did change watched files notification supports dynamic registration. Please note
+ * that the current protocol doesn't support static configuration for file changes
+ * from the server side.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+/*DidChangeWatchedFilesParams defined:
+ * The watched files change notification's parameters.
+ */
+type DidChangeWatchedFilesParams struct {
+
+ /*Changes defined:
+ * The actual file events.
+ */
+ Changes []FileEvent `json:"changes"`
+}
+
+/*FileEvent defined:
+ * An event describing a file change.
+ */
+type FileEvent struct {
+
+ /*URI defined:
+ * The file's uri.
+ */
+ URI DocumentURI `json:"uri"`
+
+ /*Type defined:
+ * The change type.
+ */
+ Type FileChangeType `json:"type"`
+}
+
+/*DidChangeWatchedFilesRegistrationOptions defined:
+ * Describe options to be used when registered for text document change events.
+ */
+type DidChangeWatchedFilesRegistrationOptions struct {
+
+ /*Watchers defined:
+ * The watchers to register.
+ */
+ Watchers []FileSystemWatcher `json:"watchers"`
+}
+
+// FileSystemWatcher is
+type FileSystemWatcher struct {
+
+ /*GlobPattern defined:
+ * The glob pattern to watch. Glob patterns can have the following syntax:
+ * - `*` to match one or more characters in a path segment
+ * - `?` to match on one character in a path segment
+ * - `**` to match any number of path segments, including none
+ * - `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files)
+ * - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
+ * - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)
+ */
+ GlobPattern string `json:"globPattern"`
+
+ /*Kind defined:
+ * The kind of events of interest. If omitted it defaults
+ * to WatchKind.Create | WatchKind.Change | WatchKind.Delete
+ * which is 7.
+ */
+ Kind float64 `json:"kind,omitempty"`
+}
+
+/*PublishDiagnosticsClientCapabilities defined:
+ * The publish diagnostic client capabilities.
+ */
+type PublishDiagnosticsClientCapabilities struct {
+
+ /*RelatedInformation defined:
+ * Whether the clients accepts diagnostics with related information.
+ */
+ RelatedInformation bool `json:"relatedInformation,omitempty"`
+
+ /*TagSupport defined:
+ * Client supports the tag property to provide meta data about a diagnostic.
+ * Clients supporting tags have to handle unknown tags gracefully.
+ *
+ * @since 3.15.0
+ */
+ TagSupport *struct {
+
+ /*ValueSet defined:
+ * The tags supported by the client.
+ */
+ ValueSet []DiagnosticTag `json:"valueSet"`
+ } `json:"tagSupport,omitempty"`
+}
+
+/*PublishDiagnosticsParams defined:
+ * The publish diagnostic notification's parameters.
+ */
+type PublishDiagnosticsParams struct {
+
+ /*URI defined:
+ * The URI for which diagnostic information is reported.
+ */
+ URI DocumentURI `json:"uri"`
+
+ /*Version defined:
+ * Optional the version number of the document the diagnostics are published for.
+ *
+ * @since 3.15.0
+ */
+ Version float64 `json:"version,omitempty"`
+
+ /*Diagnostics defined:
+ * An array of diagnostic information items.
+ */
+ Diagnostics []Diagnostic `json:"diagnostics"`
+}
+
+/*CompletionClientCapabilities defined:
+ * Completion client capabilities
+ */
+type CompletionClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether completion supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*CompletionItem defined:
+ * The client supports the following `CompletionItem` specific
+ * capabilities.
+ */
+ CompletionItem *struct {
+
+ /*SnippetSupport defined:
+ * Client supports snippets as insert text.
+ *
+ * A snippet can define tab stops and placeholders with `$1`, `$2`
+ * and `${3:foo}`. `$0` defines the final tab stop, it defaults to
+ * the end of the snippet. Placeholders with equal identifiers are linked,
+ * that is typing in one will update others too.
+ */
+ SnippetSupport bool `json:"snippetSupport,omitempty"`
+
+ /*CommitCharactersSupport defined:
+ * Client supports commit characters on a completion item.
+ */
+ CommitCharactersSupport bool `json:"commitCharactersSupport,omitempty"`
+
+ /*DocumentationFormat defined:
+ * Client supports the follow content formats for the documentation
+ * property. The order describes the preferred format of the client.
+ */
+ DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"`
+
+ /*DeprecatedSupport defined:
+ * Client supports the deprecated property on a completion item.
+ */
+ DeprecatedSupport bool `json:"deprecatedSupport,omitempty"`
+
+ /*PreselectSupport defined:
+ * Client supports the preselect property on a completion item.
+ */
+ PreselectSupport bool `json:"preselectSupport,omitempty"`
+
+ /*TagSupport defined:
+ * Client supports the tag property on a completion item. Clients supporting
+ * tags have to handle unknown tags gracefully. Clients especially need to
+ * preserve unknown tags when sending a completion item back to the server in
+ * a resolve call.
+ *
+ * @since 3.15.0
+ */
+ TagSupport *struct {
+
+ /*ValueSet defined:
+ * The tags supported by the client.
+ */
+ ValueSet []CompletionItemTag `json:"valueSet"`
+ } `json:"tagSupport,omitempty"`
+ } `json:"completionItem,omitempty"`
+
+ // CompletionItemKind is
+ CompletionItemKind *struct {
+
+ /*ValueSet defined:
+ * The completion item kind values the client supports. When this
+ * property exists the client also guarantees that it will
+ * handle values outside its set gracefully and falls back
+ * to a default value when unknown.
+ *
+ * If this property is not present the client only supports
+ * the completion items kinds from `Text` to `Reference` as defined in
+ * the initial version of the protocol.
+ */
+ ValueSet []CompletionItemKind `json:"valueSet,omitempty"`
+ } `json:"completionItemKind,omitempty"`
+
+ /*ContextSupport defined:
+ * The client supports to send additional context information for a
+ * `textDocument/completion` requestion.
+ */
+ ContextSupport bool `json:"contextSupport,omitempty"`
+}
+
+/*CompletionContext defined:
+ * Contains additional information about the context in which a completion request is triggered.
+ */
+type CompletionContext struct {
+
+ /*TriggerKind defined:
+ * How the completion was triggered.
+ */
+ TriggerKind CompletionTriggerKind `json:"triggerKind"`
+
+ /*TriggerCharacter defined:
+ * The trigger character (a single character) that has trigger code complete.
+ * Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
+ */
+ TriggerCharacter string `json:"triggerCharacter,omitempty"`
+}
+
+/*CompletionParams defined:
+ * Completion parameters
+ */
+type CompletionParams struct {
+
+ /*Context defined:
+ * The completion context. This is only available it the client specifies
+ * to send this using the client capability `textDocument.completion.contextSupport === true`
+ */
+ Context *CompletionContext `json:"context,omitempty"`
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*CompletionOptions defined:
+ * Completion options.
+ */
+type CompletionOptions struct {
+
+ /*TriggerCharacters defined:
+ * Most tools trigger completion request automatically without explicitly requesting
+ * it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user
+ * starts to type an identifier. For example if the user types `c` in a JavaScript file
+ * code complete will automatically pop up present `console` besides others as a
+ * completion item. Characters that make up identifiers don't need to be listed here.
+ *
+ * If code complete should automatically be trigger on characters not being valid inside
+ * an identifier (for example `.` in JavaScript) list them in `triggerCharacters`.
+ */
+ TriggerCharacters []string `json:"triggerCharacters,omitempty"`
+
+ /*AllCommitCharacters defined:
+ * The list of all possible characters that commit a completion. This field can be used
+ * if clients don't support individual commmit characters per completion item. See
+ * `ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport`
+ *
+ * @since 3.2.0
+ */
+ AllCommitCharacters []string `json:"allCommitCharacters,omitempty"`
+
+ /*ResolveProvider defined:
+ * The server provides support to resolve additional
+ * information for a completion item.
+ */
+ ResolveProvider bool `json:"resolveProvider,omitempty"`
+ WorkDoneProgressOptions
+}
+
+/*CompletionRegistrationOptions defined:
+ * Registration options for a [CompletionRequest](#CompletionRequest).
+ */
+type CompletionRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ CompletionOptions
+}
+
+// HoverClientCapabilities is
+type HoverClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether hover supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*ContentFormat defined:
+ * Client supports the follow content formats for the content
+ * property. The order describes the preferred format of the client.
+ */
+ ContentFormat []MarkupKind `json:"contentFormat,omitempty"`
+}
+
+/*HoverOptions defined:
+ * Hover options.
+ */
+type HoverOptions struct {
+ WorkDoneProgressOptions
+}
+
+/*HoverParams defined:
+ * Parameters for a [HoverRequest](#HoverRequest).
+ */
+type HoverParams struct {
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+}
+
+/*HoverRegistrationOptions defined:
+ * Registration options for a [HoverRequest](#HoverRequest).
+ */
+type HoverRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ HoverOptions
+}
+
+/*SignatureHelpClientCapabilities defined:
+ * Client Capabilities for a [SignatureHelpRequest](#SignatureHelpRequest).
+ */
+type SignatureHelpClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether signature help supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*SignatureInformation defined:
+ * The client supports the following `SignatureInformation`
+ * specific properties.
+ */
+ SignatureInformation *struct {
+
+ /*DocumentationFormat defined:
+ * Client supports the follow content formats for the documentation
+ * property. The order describes the preferred format of the client.
+ */
+ DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"`
+
+ /*ParameterInformation defined:
+ * Client capabilities specific to parameter information.
+ */
+ ParameterInformation *struct {
+
+ /*LabelOffsetSupport defined:
+ * The client supports processing label offsets instead of a
+ * simple label string.
+ *
+ * @since 3.14.0
+ */
+ LabelOffsetSupport bool `json:"labelOffsetSupport,omitempty"`
+ } `json:"parameterInformation,omitempty"`
+ } `json:"signatureInformation,omitempty"`
+
+ /*ContextSupport defined:
+ * The client supports to send additional context information for a
+ * `textDocument/signatureHelp` request. A client that opts into
+ * contextSupport will also support the `retriggerCharacters` on
+ * `SignatureHelpOptions`.
+ *
+ * @since 3.15.0
+ */
+ ContextSupport bool `json:"contextSupport,omitempty"`
+}
+
+/*SignatureHelpOptions defined:
+ * Server Capabilities for a [SignatureHelpRequest](#SignatureHelpRequest).
+ */
+type SignatureHelpOptions struct {
+
+ /*TriggerCharacters defined:
+ * List of characters that trigger signature help.
+ */
+ TriggerCharacters []string `json:"triggerCharacters,omitempty"`
+
+ /*RetriggerCharacters defined:
+ * List of characters that re-trigger signature help.
+ *
+ * These trigger characters are only active when signature help is already showing. All trigger characters
+ * are also counted as re-trigger characters.
+ *
+ * @since 3.15.0
+ */
+ RetriggerCharacters []string `json:"retriggerCharacters,omitempty"`
+ WorkDoneProgressOptions
+}
+
+/*SignatureHelpContext defined:
+ * Additional information about the context in which a signature help request was triggered.
+ *
+ * @since 3.15.0
+ */
+type SignatureHelpContext struct {
+
+ /*TriggerKind defined:
+ * Action that caused signature help to be triggered.
+ */
+ TriggerKind SignatureHelpTriggerKind `json:"triggerKind"`
+
+ /*TriggerCharacter defined:
+ * Character that caused signature help to be triggered.
+ *
+ * This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter`
+ */
+ TriggerCharacter string `json:"triggerCharacter,omitempty"`
+
+ /*IsRetrigger defined:
+ * `true` if signature help was already showing when it was triggered.
+ *
+ * Retriggers occur when the signature help is already active and can be caused by actions such as
+ * typing a trigger character, a cursor move, or document content changes.
+ */
+ IsRetrigger bool `json:"isRetrigger"`
+
+ /*ActiveSignatureHelp defined:
+ * The currently active `SignatureHelp`.
+ *
+ * The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on
+ * the user navigating through available signatures.
+ */
+ ActiveSignatureHelp *SignatureHelp `json:"activeSignatureHelp,omitempty"`
+}
+
+/*SignatureHelpParams defined:
+ * Parameters for a [SignatureHelpRequest](#SignatureHelpRequest).
+ */
+type SignatureHelpParams struct {
+
+ /*Context defined:
+ * The signature help context. This is only available if the client specifies
+ * to send this using the client capability `textDocument.signatureHelp.contextSupport === true`
+ *
+ * @since 3.15.0
+ */
+ Context *SignatureHelpContext `json:"context,omitempty"`
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+}
+
+/*SignatureHelpRegistrationOptions defined:
+ * Registration options for a [SignatureHelpRequest](#SignatureHelpRequest).
+ */
+type SignatureHelpRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ SignatureHelpOptions
+}
+
+/*DefinitionClientCapabilities defined:
+ * Client Capabilities for a [DefinitionRequest](#DefinitionRequest).
+ */
+type DefinitionClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether definition supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*LinkSupport defined:
+ * The client supports additional metadata in the form of definition links.
+ *
+ * @since 3.14.0
+ */
+ LinkSupport bool `json:"linkSupport,omitempty"`
+}
+
+/*DefinitionOptions defined:
+ * Server Capabilities for a [DefinitionRequest](#DefinitionRequest).
+ */
+type DefinitionOptions struct {
+ WorkDoneProgressOptions
+}
+
+/*DefinitionParams defined:
+ * Parameters for a [DefinitionRequest](#DefinitionRequest).
+ */
+type DefinitionParams struct {
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*DefinitionRegistrationOptions defined:
+ * Registration options for a [DefinitionRequest](#DefinitionRequest).
+ */
+type DefinitionRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ DefinitionOptions
+}
+
+/*ReferenceClientCapabilities defined:
+ * Client Capabilities for a [ReferencesRequest](#ReferencesRequest).
+ */
+type ReferenceClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether references supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+/*ReferenceParams defined:
+ * Parameters for a [ReferencesRequest](#ReferencesRequest).
+ */
+type ReferenceParams struct {
+
+ // Context is
+ Context ReferenceContext `json:"context"`
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*ReferenceOptions defined:
+ * Reference options.
+ */
+type ReferenceOptions struct {
+ WorkDoneProgressOptions
+}
+
+/*ReferenceRegistrationOptions defined:
+ * Registration options for a [ReferencesRequest](#ReferencesRequest).
+ */
+type ReferenceRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ ReferenceOptions
+}
+
+/*DocumentHighlightClientCapabilities defined:
+ * Client Capabilities for a [DocumentHighlightRequest](#DocumentHighlightRequest).
+ */
+type DocumentHighlightClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether document highlight supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+/*DocumentHighlightParams defined:
+ * Parameters for a [DocumentHighlightRequest](#DocumentHighlightRequest).
+ */
+type DocumentHighlightParams struct {
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*DocumentHighlightOptions defined:
+ * Provider options for a [DocumentHighlightRequest](#DocumentHighlightRequest).
+ */
+type DocumentHighlightOptions struct {
+ WorkDoneProgressOptions
+}
+
+/*DocumentHighlightRegistrationOptions defined:
+ * Registration options for a [DocumentHighlightRequest](#DocumentHighlightRequest).
+ */
+type DocumentHighlightRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ DocumentHighlightOptions
+}
+
+/*DocumentSymbolClientCapabilities defined:
+ * Client Capabilities for a [DocumentSymbolRequest](#DocumentSymbolRequest).
+ */
+type DocumentSymbolClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether document symbol supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*SymbolKind defined:
+ * Specific capabilities for the `SymbolKind`.
+ */
+ SymbolKind *struct {
+
+ /*ValueSet defined:
+ * The symbol kind values the client supports. When this
+ * property exists the client also guarantees that it will
+ * handle values outside its set gracefully and falls back
+ * to a default value when unknown.
+ *
+ * If this property is not present the client only supports
+ * the symbol kinds from `File` to `Array` as defined in
+ * the initial version of the protocol.
+ */
+ ValueSet []SymbolKind `json:"valueSet,omitempty"`
+ } `json:"symbolKind,omitempty"`
+
+ /*HierarchicalDocumentSymbolSupport defined:
+ * The client support hierarchical document symbols.
+ */
+ HierarchicalDocumentSymbolSupport bool `json:"hierarchicalDocumentSymbolSupport,omitempty"`
+}
+
+/*DocumentSymbolParams defined:
+ * Parameters for a [DocumentSymbolRequest](#DocumentSymbolRequest).
+ */
+type DocumentSymbolParams struct {
+
+ /*TextDocument defined:
+ * The text document.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*DocumentSymbolOptions defined:
+ * Provider options for a [DocumentSymbolRequest](#DocumentSymbolRequest).
+ */
+type DocumentSymbolOptions struct {
+ WorkDoneProgressOptions
+}
+
+/*DocumentSymbolRegistrationOptions defined:
+ * Registration options for a [DocumentSymbolRequest](#DocumentSymbolRequest).
+ */
+type DocumentSymbolRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ DocumentSymbolOptions
+}
+
+/*CodeActionClientCapabilities defined:
+ * The Client Capabilities of a [CodeActionRequest](#CodeActionRequest).
+ */
+type CodeActionClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether code action supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*CodeActionLiteralSupport defined:
+ * The client support code action literals as a valid
+ * response of the `textDocument/codeAction` request.
+ *
+ * @since 3.8.0
+ */
+ CodeActionLiteralSupport *struct {
+
+ /*CodeActionKind defined:
+ * The code action kind is support with the following value
+ * set.
+ */
+ CodeActionKind struct {
+
+ /*ValueSet defined:
+ * The code action kind values the client supports. When this
+ * property exists the client also guarantees that it will
+ * handle values outside its set gracefully and falls back
+ * to a default value when unknown.
+ */
+ ValueSet []CodeActionKind `json:"valueSet"`
+ } `json:"codeActionKind"`
+ } `json:"codeActionLiteralSupport,omitempty"`
+
+ /*IsPreferredSupport defined:
+ * Whether code action supports the `isPreferred` property.
+ * @since 3.15.0
+ */
+ IsPreferredSupport bool `json:"isPreferredSupport,omitempty"`
+}
+
+/*CodeActionParams defined:
+ * The parameters of a [CodeActionRequest](#CodeActionRequest).
+ */
+type CodeActionParams struct {
+
+ /*TextDocument defined:
+ * The document in which the command was invoked.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+
+ /*Range defined:
+ * The range for which the command was invoked.
+ */
+ Range Range `json:"range"`
+
+ /*Context defined:
+ * Context carrying additional information.
+ */
+ Context CodeActionContext `json:"context"`
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*CodeActionOptions defined:
+ * Provider options for a [CodeActionRequest](#CodeActionRequest).
+ */
+type CodeActionOptions struct {
+
+ /*CodeActionKinds defined:
+ * CodeActionKinds that this server may return.
+ *
+ * The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server
+ * may list out every specific kind they provide.
+ */
+ CodeActionKinds []CodeActionKind `json:"codeActionKinds,omitempty"`
+ WorkDoneProgressOptions
+}
+
+/*CodeActionRegistrationOptions defined:
+ * Registration options for a [CodeActionRequest](#CodeActionRequest).
+ */
+type CodeActionRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ CodeActionOptions
+}
+
+/*WorkspaceSymbolClientCapabilities defined:
+ * Client capabilities for a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest).
+ */
+type WorkspaceSymbolClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Symbol request supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*SymbolKind defined:
+ * Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
+ */
+ SymbolKind *struct {
+
+ /*ValueSet defined:
+ * The symbol kind values the client supports. When this
+ * property exists the client also guarantees that it will
+ * handle values outside its set gracefully and falls back
+ * to a default value when unknown.
+ *
+ * If this property is not present the client only supports
+ * the symbol kinds from `File` to `Array` as defined in
+ * the initial version of the protocol.
+ */
+ ValueSet []SymbolKind `json:"valueSet,omitempty"`
+ } `json:"symbolKind,omitempty"`
+}
+
+/*WorkspaceSymbolParams defined:
+ * The parameters of a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest).
+ */
+type WorkspaceSymbolParams struct {
+
+ /*Query defined:
+ * A query string to filter symbols by. Clients may send an empty
+ * string here to request all symbols.
+ */
+ Query string `json:"query"`
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*WorkspaceSymbolOptions defined:
+ * Server capabilities for a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest).
+ */
+type WorkspaceSymbolOptions struct {
+ WorkDoneProgressOptions
+}
+
+/*WorkspaceSymbolRegistrationOptions defined:
+ * Registration options for a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest).
+ */
+type WorkspaceSymbolRegistrationOptions struct {
+ WorkspaceSymbolOptions
+}
+
+/*CodeLensClientCapabilities defined:
+ * The client capabilities of a [CodeLensRequest](#CodeLensRequest).
+ */
+type CodeLensClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether code lens supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+/*CodeLensParams defined:
+ * The parameters of a [CodeLensRequest](#CodeLensRequest).
+ */
+type CodeLensParams struct {
+
+ /*TextDocument defined:
+ * The document to request code lens for.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*CodeLensOptions defined:
+ * Code Lens provider options of a [CodeLensRequest](#CodeLensRequest).
+ */
+type CodeLensOptions struct {
+
+ /*ResolveProvider defined:
+ * Code lens has a resolve provider as well.
+ */
+ ResolveProvider bool `json:"resolveProvider,omitempty"`
+ WorkDoneProgressOptions
+}
+
+/*CodeLensRegistrationOptions defined:
+ * Registration options for a [CodeLensRequest](#CodeLensRequest).
+ */
+type CodeLensRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ CodeLensOptions
+}
+
+/*DocumentLinkClientCapabilities defined:
+ * The client capabilities of a [DocumentLinkRequest](#DocumentLinkRequest).
+ */
+type DocumentLinkClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether document link supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*TooltipSupport defined:
+ * Whether the client support the `tooltip` property on `DocumentLink`.
+ *
+ * @since 3.15.0
+ */
+ TooltipSupport bool `json:"tooltipSupport,omitempty"`
+}
+
+/*DocumentLinkParams defined:
+ * The parameters of a [DocumentLinkRequest](#DocumentLinkRequest).
+ */
+type DocumentLinkParams struct {
+
+ /*TextDocument defined:
+ * The document to provide document links for.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+ WorkDoneProgressParams
+ PartialResultParams
+}
+
+/*DocumentLinkOptions defined:
+ * Provider options for a [DocumentLinkRequest](#DocumentLinkRequest).
+ */
+type DocumentLinkOptions struct {
+
+ /*ResolveProvider defined:
+ * Document links have a resolve provider as well.
+ */
+ ResolveProvider bool `json:"resolveProvider,omitempty"`
+ WorkDoneProgressOptions
+}
+
+/*DocumentLinkRegistrationOptions defined:
+ * Registration options for a [DocumentLinkRequest](#DocumentLinkRequest).
+ */
+type DocumentLinkRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ DocumentLinkOptions
+}
+
+/*DocumentFormattingClientCapabilities defined:
+ * Client capabilities of a [DocumentFormattingRequest](#DocumentFormattingRequest).
+ */
+type DocumentFormattingClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether formatting supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+/*DocumentFormattingParams defined:
+ * The parameters of a [DocumentFormattingRequest](#DocumentFormattingRequest).
+ */
+type DocumentFormattingParams struct {
+
+ /*TextDocument defined:
+ * The document to format.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+
+ /*Options defined:
+ * The format options
+ */
+ Options FormattingOptions `json:"options"`
+ WorkDoneProgressParams
+}
+
+/*DocumentFormattingOptions defined:
+ * Provider options for a [DocumentFormattingRequest](#DocumentFormattingRequest).
+ */
+type DocumentFormattingOptions struct {
+ WorkDoneProgressOptions
+}
+
+/*DocumentFormattingRegistrationOptions defined:
+ * Registration options for a [DocumentFormattingRequest](#DocumentFormattingRequest).
+ */
+type DocumentFormattingRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ DocumentFormattingOptions
+}
+
+/*DocumentRangeFormattingClientCapabilities defined:
+ * Client capabilities of a [DocumentRangeFormattingRequest](#DocumentRangeFormattingRequest).
+ */
+type DocumentRangeFormattingClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether range formatting supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+/*DocumentRangeFormattingParams defined:
+ * The parameters of a [DocumentRangeFormattingRequest](#DocumentRangeFormattingRequest).
+ */
+type DocumentRangeFormattingParams struct {
+
+ /*TextDocument defined:
+ * The document to format.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+
+ /*Range defined:
+ * The range to format
+ */
+ Range Range `json:"range"`
+
+ /*Options defined:
+ * The format options
+ */
+ Options FormattingOptions `json:"options"`
+ WorkDoneProgressParams
+}
+
+/*DocumentRangeFormattingOptions defined:
+ * Provider options for a [DocumentRangeFormattingRequest](#DocumentRangeFormattingRequest).
+ */
+type DocumentRangeFormattingOptions struct {
+ WorkDoneProgressOptions
+}
+
+/*DocumentRangeFormattingRegistrationOptions defined:
+ * Registration options for a [DocumentRangeFormattingRequest](#DocumentRangeFormattingRequest).
+ */
+type DocumentRangeFormattingRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ DocumentRangeFormattingOptions
+}
+
+/*DocumentOnTypeFormattingClientCapabilities defined:
+ * Client capabilities of a [DocumentOnTypeFormattingRequest](#DocumentOnTypeFormattingRequest).
+ */
+type DocumentOnTypeFormattingClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether on type formatting supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+/*DocumentOnTypeFormattingParams defined:
+ * The parameters of a [DocumentOnTypeFormattingRequest](#DocumentOnTypeFormattingRequest).
+ */
+type DocumentOnTypeFormattingParams struct {
+
+ /*TextDocument defined:
+ * The document to format.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+
+ /*Position defined:
+ * The position at which this request was send.
+ */
+ Position Position `json:"position"`
+
+ /*Ch defined:
+ * The character that has been typed.
+ */
+ Ch string `json:"ch"`
+
+ /*Options defined:
+ * The format options.
+ */
+ Options FormattingOptions `json:"options"`
+}
+
+/*DocumentOnTypeFormattingOptions defined:
+ * Provider options for a [DocumentOnTypeFormattingRequest](#DocumentOnTypeFormattingRequest).
+ */
+type DocumentOnTypeFormattingOptions struct {
+
+ /*FirstTriggerCharacter defined:
+ * A character on which formatting should be triggered, like `}`.
+ */
+ FirstTriggerCharacter string `json:"firstTriggerCharacter"`
+
+ /*MoreTriggerCharacter defined:
+ * More trigger characters.
+ */
+ MoreTriggerCharacter []string `json:"moreTriggerCharacter,omitempty"`
+}
+
+/*DocumentOnTypeFormattingRegistrationOptions defined:
+ * Registration options for a [DocumentOnTypeFormattingRequest](#DocumentOnTypeFormattingRequest).
+ */
+type DocumentOnTypeFormattingRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ DocumentOnTypeFormattingOptions
+}
+
+// RenameClientCapabilities is
+type RenameClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Whether rename supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+
+ /*PrepareSupport defined:
+ * Client supports testing for validity of rename operations
+ * before execution.
+ *
+ * @since version 3.12.0
+ */
+ PrepareSupport bool `json:"prepareSupport,omitempty"`
+}
+
+/*RenameParams defined:
+ * The parameters of a [RenameRequest](#RenameRequest).
+ */
+type RenameParams struct {
+
+ /*TextDocument defined:
+ * The document to rename.
+ */
+ TextDocument TextDocumentIdentifier `json:"textDocument"`
+
+ /*Position defined:
+ * The position at which this request was sent.
+ */
+ Position Position `json:"position"`
+
+ /*NewName defined:
+ * The new name of the symbol. If the given name is not valid the
+ * request must return a [ResponseError](#ResponseError) with an
+ * appropriate message set.
+ */
+ NewName string `json:"newName"`
+ WorkDoneProgressParams
+}
+
+/*RenameOptions defined:
+ * Provider options for a [RenameRequest](#RenameRequest).
+ */
+type RenameOptions struct {
+
+ /*PrepareProvider defined:
+ * Renames should be checked and tested before being executed.
+ *
+ * @since version 3.12.0
+ */
+ PrepareProvider bool `json:"prepareProvider,omitempty"`
+ WorkDoneProgressOptions
+}
+
+/*RenameRegistrationOptions defined:
+ * Registration options for a [RenameRequest](#RenameRequest).
+ */
+type RenameRegistrationOptions struct {
+ TextDocumentRegistrationOptions
+ RenameOptions
+}
+
+// PrepareRenameParams is
+type PrepareRenameParams struct {
+ TextDocumentPositionParams
+ WorkDoneProgressParams
+}
+
+/*ExecuteCommandClientCapabilities defined:
+ * The client capabilities of a [ExecuteCommandRequest](#ExecuteCommandRequest).
+ */
+type ExecuteCommandClientCapabilities struct {
+
+ /*DynamicRegistration defined:
+ * Execute command supports dynamic registration.
+ */
+ DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+}
+
+/*ExecuteCommandParams defined:
+ * The parameters of a [ExecuteCommandRequest](#ExecuteCommandRequest).
+ */
+type ExecuteCommandParams struct {
+
+ /*Command defined:
+ * The identifier of the actual command handler.
+ */
+ Command string `json:"command"`
+
+ /*Arguments defined:
+ * Arguments that the command should be invoked with.
+ */
+ Arguments []interface{} `json:"arguments,omitempty"`
+ WorkDoneProgressParams
+}
+
+/*ExecuteCommandOptions defined:
+ * The server capabilities of a [ExecuteCommandRequest](#ExecuteCommandRequest).
+ */
+type ExecuteCommandOptions struct {
+
+ /*Commands defined:
+ * The commands to be executed on the server
+ */
+ Commands []string `json:"commands"`
+ WorkDoneProgressOptions
+}
+
+/*ExecuteCommandRegistrationOptions defined:
+ * Registration options for a [ExecuteCommandRequest](#ExecuteCommandRequest).
+ */
+type ExecuteCommandRegistrationOptions struct {
+ ExecuteCommandOptions
+}
+
+// WorkspaceEditClientCapabilities is
+type WorkspaceEditClientCapabilities struct {
+
+ /*DocumentChanges defined:
+ * The client supports versioned document changes in `WorkspaceEdit`s
+ */
+ DocumentChanges bool `json:"documentChanges,omitempty"`
+
+ /*ResourceOperations defined:
+ * The resource operations the client supports. Clients should at least
+ * support 'create', 'rename' and 'delete' files and folders.
+ *
+ * @since 3.13.0
+ */
+ ResourceOperations []ResourceOperationKind `json:"resourceOperations,omitempty"`
+
+ /*FailureHandling defined:
+ * The failure handling strategy of a client if applying the workspace edit
+ * fails.
+ *
+ * @since 3.13.0
+ */
+ FailureHandling FailureHandlingKind `json:"failureHandling,omitempty"`
+}
+
+/*ApplyWorkspaceEditParams defined:
+ * The parameters passed via a apply workspace edit request.
+ */
+type ApplyWorkspaceEditParams struct {
+
+ /*Label defined:
+ * An optional label of the workspace edit. This label is
+ * presented in the user interface for example on an undo
+ * stack to undo the workspace edit.
+ */
+ Label string `json:"label,omitempty"`
+
+ /*Edit defined:
+ * The edits to apply.
+ */
+ Edit WorkspaceEdit `json:"edit"`
+}
+
+/*ApplyWorkspaceEditResponse defined:
+ * A response returned from the apply workspace edit request.
+ */
+type ApplyWorkspaceEditResponse struct {
+
+ /*Applied defined:
+ * Indicates whether the edit was applied or not.
+ */
+ Applied bool `json:"applied"`
+
+ /*FailureReason defined:
+ * An optional textual description for why the edit was not applied.
+ * This may be used by the server for diagnostic logging or to provide
+ * a suitable error for a request that triggered the edit.
+ */
+ FailureReason string `json:"failureReason,omitempty"`
+
+ /*FailedChange defined:
+ * Depending on the client's failure handling strategy `failedChange` might
+ * contain the index of the change that failed. This property is only available
+ * if the client signals a `failureHandlingStrategy` in its client capabilities.
+ */
+ FailedChange float64 `json:"failedChange,omitempty"`
+}
+
+/*Position defined:
+ * Position in a text document expressed as zero-based line and character offset.
+ * The offsets are based on a UTF-16 string representation. So a string of the form
+ * `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀`
+ * is 1 and the character offset of b is 3 since `𐐀` is represented using two code
+ * units in UTF-16.
+ *
+ * Positions are line end character agnostic. So you can not specify a position that
+ * denotes `\r|\n` or `\n|` where `|` represents the character offset.
+ */
+type Position struct {
+
+ /*Line defined:
+ * Line position in a document (zero-based).
+ * If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document.
+ * If a line number is negative, it defaults to 0.
+ */
+ Line float64 `json:"line"`
+
+ /*Character defined:
+ * Character offset on a line in a document (zero-based). Assuming that the line is
+ * represented as a string, the `character` value represents the gap between the
+ * `character` and `character + 1`.
+ *
+ * If the character value is greater than the line length it defaults back to the
+ * line length.
+ * If a line number is negative, it defaults to 0.
+ */
+ Character float64 `json:"character"`
+}
+
+/*Range defined:
+ * A range in a text document expressed as (zero-based) start and end positions.
+ *
+ * If you want to specify a range that contains a line including the line ending
+ * character(s) then use an end position denoting the start of the next line.
+ * For example:
+ * ```ts
+ * {
+ * start: { line: 5, character: 23 }
+ * end : { line 6, character : 0 }
+ * }
+ * ```
+ */
+type Range struct {
+
+ /*Start defined:
+ * The range's start position
+ */
+ Start Position `json:"start"`
+
+ /*End defined:
+ * The range's end position.
+ */
+ End Position `json:"end"`
+}
+
+/*Location defined:
+ * Represents a location inside a resource, such as a line
+ * inside a text file.
+ */
+type Location struct {
+
+ // URI is
+ URI DocumentURI `json:"uri"`
+
+ // Range is
+ Range Range `json:"range"`
+}
+
+/*LocationLink defined:
+ * Represents the connection of two locations. Provides additional metadata over normal [locations](#Location),
+ * including an origin range.
+ */
+type LocationLink struct {
+
+ /*OriginSelectionRange defined:
+ * Span of the origin of this link.
+ *
+ * Used as the underlined span for mouse definition hover. Defaults to the word range at
+ * the definition position.
+ */
+ OriginSelectionRange *Range `json:"originSelectionRange,omitempty"`
+
+ /*TargetURI defined:
+ * The target resource identifier of this link.
+ */
+ TargetURI DocumentURI `json:"targetUri"`
+
+ /*TargetRange defined:
+ * The full target range of this link. If the target for example is a symbol then target range is the
+ * range enclosing this symbol not including leading/trailing whitespace but everything else
+ * like comments. This information is typically used to highlight the range in the editor.
+ */
+ TargetRange Range `json:"targetRange"`
+
+ /*TargetSelectionRange defined:
+ * The range that should be selected and revealed when this link is being followed, e.g the name of a function.
+ * Must be contained by the the `targetRange`. See also `DocumentSymbol#range`
+ */
+ TargetSelectionRange Range `json:"targetSelectionRange"`
+}
+
+/*Color defined:
+ * Represents a color in RGBA space.
+ */
+type Color struct {
+
+ /*Red defined:
+ * The red component of this color in the range [0-1].
+ */
+ Red float64 `json:"red"`
+
+ /*Green defined:
+ * The green component of this color in the range [0-1].
+ */
+ Green float64 `json:"green"`
+
+ /*Blue defined:
+ * The blue component of this color in the range [0-1].
+ */
+ Blue float64 `json:"blue"`
+
+ /*Alpha defined:
+ * The alpha component of this color in the range [0-1].
+ */
+ Alpha float64 `json:"alpha"`
+}
+
+/*ColorInformation defined:
+ * Represents a color range from a document.
+ */
+type ColorInformation struct {
+
+ /*Range defined:
+ * The range in the document where this color appers.
+ */
+ Range Range `json:"range"`
+
+ /*Color defined:
+ * The actual color value for this color range.
+ */
+ Color Color `json:"color"`
+}
+
+// ColorPresentation is
+type ColorPresentation struct {
+
+ /*Label defined:
+ * The label of this color presentation. It will be shown on the color
+ * picker header. By default this is also the text that is inserted when selecting
+ * this color presentation.
+ */
+ Label string `json:"label"`
+
+ /*TextEdit defined:
+ * An [edit](#TextEdit) which is applied to a document when selecting
+ * this presentation for the color. When `falsy` the [label](#ColorPresentation.label)
+ * is used.
+ */
+ TextEdit *TextEdit `json:"textEdit,omitempty"`
+
+ /*AdditionalTextEdits defined:
+ * An optional array of additional [text edits](#TextEdit) that are applied when
+ * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves.
+ */
+ AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"`
+}
+
+/*DiagnosticRelatedInformation defined:
+ * Represents a related message and source code location for a diagnostic. This should be
+ * used to point to code locations that cause or related to a diagnostics, e.g when duplicating
+ * a symbol in a scope.
+ */
+type DiagnosticRelatedInformation struct {
+
+ /*Location defined:
+ * The location of this related diagnostic information.
+ */
+ Location Location `json:"location"`
+
+ /*Message defined:
+ * The message of this related diagnostic information.
+ */
+ Message string `json:"message"`
+}
+
+/*Diagnostic defined:
+ * Represents a diagnostic, such as a compiler error or warning. Diagnostic objects
+ * are only valid in the scope of a resource.
+ */
+type Diagnostic struct {
+
+ /*Range defined:
+ * The range at which the message applies
+ */
+ Range Range `json:"range"`
+
+ /*Severity defined:
+ * The diagnostic's severity. Can be omitted. If omitted it is up to the
+ * client to interpret diagnostics as error, warning, info or hint.
+ */
+ Severity DiagnosticSeverity `json:"severity,omitempty"`
+
+ /*Code defined:
+ * The diagnostic's code, which usually appear in the user interface.
+ */
+ Code interface{} `json:"code,omitempty"` // number | string
+
+ /*Source defined:
+ * A human-readable string describing the source of this
+ * diagnostic, e.g. 'typescript' or 'super lint'. It usually
+ * appears in the user interface.
+ */
+ Source string `json:"source,omitempty"`
+
+ /*Message defined:
+ * The diagnostic's message. It usually appears in the user interface
+ */
+ Message string `json:"message"`
+
+ /*Tags defined:
+ * Additional metadata about the diagnostic.
+ */
+ Tags []DiagnosticTag `json:"tags,omitempty"`
+
+ /*RelatedInformation defined:
+ * An array of related diagnostic information, e.g. when symbol-names within
+ * a scope collide all definitions can be marked via this property.
+ */
+ RelatedInformation []DiagnosticRelatedInformation `json:"relatedInformation,omitempty"`
+}
+
+/*Command defined:
+ * Represents a reference to a command. Provides a title which
+ * will be used to represent a command in the UI and, optionally,
+ * an array of arguments which will be passed to the command handler
+ * function when invoked.
+ */
+type Command struct {
+
+ /*Title defined:
+ * Title of the command, like `save`.
+ */
+ Title string `json:"title"`
+
+ /*Command defined:
+ * The identifier of the actual command handler.
+ */
+ Command string `json:"command"`
+
+ /*Arguments defined:
+ * Arguments that the command handler should be
+ * invoked with.
+ */
+ Arguments []interface{} `json:"arguments,omitempty"`
+}
+
+/*TextEdit defined:
+ * A text edit applicable to a text document.
+ */
+type TextEdit struct {
+
+ /*Range defined:
+ * The range of the text document to be manipulated. To insert
+ * text into a document create a range where start === end.
+ */
+ Range Range `json:"range"`
+
+ /*NewText defined:
+ * The string to be inserted. For delete operations use an
+ * empty string.
+ */
+ NewText string `json:"newText"`
+}
+
+/*TextDocumentEdit defined:
+ * Describes textual changes on a text document.
+ */
+type TextDocumentEdit struct {
+
+ /*TextDocument defined:
+ * The text document to change.
+ */
+ TextDocument VersionedTextDocumentIdentifier `json:"textDocument"`
+
+ /*Edits defined:
+ * The edits to be applied.
+ */
+ Edits []TextEdit `json:"edits"`
+}
+
+// ResourceOperation is
+type ResourceOperation struct {
+
+ // Kind is
+ Kind string `json:"kind"`
+}
+
+/*CreateFileOptions defined:
+ * Options to create a file.
+ */
+type CreateFileOptions struct {
+
+ /*Overwrite defined:
+ * Overwrite existing file. Overwrite wins over `ignoreIfExists`
+ */
+ Overwrite bool `json:"overwrite,omitempty"`
+
+ /*IgnoreIfExists defined:
+ * Ignore if exists.
+ */
+ IgnoreIfExists bool `json:"ignoreIfExists,omitempty"`
+}
+
+/*CreateFile defined:
+ * Create file operation.
+ */
+type CreateFile struct {
+
+ /*Kind defined:
+ * A create
+ */
+ Kind string `json:"kind"` // 'create'
+
+ /*URI defined:
+ * The resource to create.
+ */
+ URI DocumentURI `json:"uri"`
+
+ /*Options defined:
+ * Additional options
+ */
+ Options *CreateFileOptions `json:"options,omitempty"`
+}
+
+/*RenameFileOptions defined:
+ * Rename file options
+ */
+type RenameFileOptions struct {
+
+ /*Overwrite defined:
+ * Overwrite target if existing. Overwrite wins over `ignoreIfExists`
+ */
+ Overwrite bool `json:"overwrite,omitempty"`
+
+ /*IgnoreIfExists defined:
+ * Ignores if target exists.
+ */
+ IgnoreIfExists bool `json:"ignoreIfExists,omitempty"`
+}
+
+/*RenameFile defined:
+ * Rename file operation
+ */
+type RenameFile struct {
+
+ /*Kind defined:
+ * A rename
+ */
+ Kind string `json:"kind"` // 'rename'
+
+ /*OldURI defined:
+ * The old (existing) location.
+ */
+ OldURI DocumentURI `json:"oldUri"`
+
+ /*NewURI defined:
+ * The new location.
+ */
+ NewURI DocumentURI `json:"newUri"`
+
+ /*Options defined:
+ * Rename options.
+ */
+ Options *RenameFileOptions `json:"options,omitempty"`
+}
+
+/*DeleteFileOptions defined:
+ * Delete file options
+ */
+type DeleteFileOptions struct {
+
+ /*Recursive defined:
+ * Delete the content recursively if a folder is denoted.
+ */
+ Recursive bool `json:"recursive,omitempty"`
+
+ /*IgnoreIfNotExists defined:
+ * Ignore the operation if the file doesn't exist.
+ */
+ IgnoreIfNotExists bool `json:"ignoreIfNotExists,omitempty"`
+}
+
+/*DeleteFile defined:
+ * Delete file operation
+ */
+type DeleteFile struct {
+
+ /*Kind defined:
+ * A delete
+ */
+ Kind string `json:"kind"` // 'delete'
+
+ /*URI defined:
+ * The file to delete.
+ */
+ URI DocumentURI `json:"uri"`
+
+ /*Options defined:
+ * Delete options.
+ */
+ Options *DeleteFileOptions `json:"options,omitempty"`
+}
+
+/*WorkspaceEdit defined:
+ * A workspace edit represents changes to many resources managed in the workspace. The edit
+ * should either provide `changes` or `documentChanges`. If documentChanges are present
+ * they are preferred over `changes` if the client can handle versioned document edits.
+ */
+type WorkspaceEdit struct {
+
+ /*Changes defined:
+ * Holds changes to existing resources.
+ */
+ Changes *map[string][]TextEdit `json:"changes,omitempty"` // [uri: string]: TextEdit[];
+
+ /*DocumentChanges defined:
+ * Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes
+ * are either an array of `TextDocumentEdit`s to express changes to n different text documents
+ * where each text document edit addresses a specific version of a text document. Or it can contain
+ * above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations.
+ *
+ * Whether a client supports versioned document edits is expressed via
+ * `workspace.workspaceEdit.documentChanges` client capability.
+ *
+ * If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then
+ * only plain `TextEdit`s using the `changes` property are supported.
+ */
+ DocumentChanges []TextDocumentEdit `json:"documentChanges,omitempty"` // (TextDocumentEdit | CreateFile | RenameFile | DeleteFile)
+}
+
+/*TextEditChange defined:
+ * A change to capture text edits for existing resources.
+ */
+type TextEditChange struct {
+}
+
+/*TextDocumentIdentifier defined:
+ * A literal to identify a text document in the client.
+ */
+type TextDocumentIdentifier struct {
+
+ /*URI defined:
+ * The text document's uri.
+ */
+ URI DocumentURI `json:"uri"`
+}
+
+/*VersionedTextDocumentIdentifier defined:
+ * An identifier to denote a specific version of a text document.
+ */
+type VersionedTextDocumentIdentifier struct {
+
+ /*Version defined:
+ * The version number of this document. If a versioned text document identifier
+ * is sent from the server to the client and the file is not open in the editor
+ * (the server has not received an open notification before) the server can send
+ * `null` to indicate that the version is unknown and the content on disk is the
+ * truth (as speced with document content ownership).
+ */
+ Version float64 `json:"version"`
+ TextDocumentIdentifier
+}
+
+/*TextDocumentItem defined:
+ * An item to transfer a text document from the client to the
+ * server.
+ */
+type TextDocumentItem struct {
+
+ /*URI defined:
+ * The text document's uri.
+ */
+ URI DocumentURI `json:"uri"`
+
+ /*LanguageID defined:
+ * The text document's language identifier
+ */
+ LanguageID string `json:"languageId"`
+
+ /*Version defined:
+ * The version number of this document (it will increase after each
+ * change, including undo/redo).
+ */
+ Version float64 `json:"version"`
+
+ /*Text defined:
+ * The content of the opened text document.
+ */
+ Text string `json:"text"`
+}
+
+/*MarkupContent defined:
+ * A `MarkupContent` literal represents a string value which content is interpreted base on its
+ * kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds.
+ *
+ * If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues.
+ * See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
+ *
+ * Here is an example how such a string can be constructed using JavaScript / TypeScript:
+ * ```ts
+ * let markdown: MarkdownContent = {
+ * kind: MarkupKind.Markdown,
+ * value: [
+ * '# Header',
+ * 'Some text',
+ * '```typescript',
+ * 'someCode();',
+ * '```'
+ * ].join('\n')
+ * };
+ * ```
+ *
+ * *Please Note* that clients might sanitize the return markdown. A client could decide to
+ * remove HTML from the markdown to avoid script execution.
+ */
+type MarkupContent struct {
+
+ /*Kind defined:
+ * The type of the Markup
+ */
+ Kind MarkupKind `json:"kind"`
+
+ /*Value defined:
+ * The content itself
+ */
+ Value string `json:"value"`
+}
+
+/*CompletionItem defined:
+ * A completion item represents a text snippet that is
+ * proposed to complete text that is being typed.
+ */
+type CompletionItem struct {
+
+ /*Label defined:
+ * The label of this completion item. By default
+ * also the text that is inserted when selecting
+ * this completion.
+ */
+ Label string `json:"label"`
+
+ /*Kind defined:
+ * The kind of this completion item. Based of the kind
+ * an icon is chosen by the editor.
+ */
+ Kind CompletionItemKind `json:"kind,omitempty"`
+
+ /*Tags defined:
+ * Tags for this completion item.
+ *
+ * @since 3.15.0
+ */
+ Tags []CompletionItemTag `json:"tags,omitempty"`
+
+ /*Detail defined:
+ * A human-readable string with additional information
+ * about this item, like type or symbol information.
+ */
+ Detail string `json:"detail,omitempty"`
+
+ /*Documentation defined:
+ * A human-readable string that represents a doc-comment.
+ */
+ Documentation string `json:"documentation,omitempty"` // string | MarkupContent
+
+ /*Deprecated defined:
+ * Indicates if this item is deprecated.
+ * @deprecated Use `tags` instead.
+ */
+ Deprecated bool `json:"deprecated,omitempty"`
+
+ /*Preselect defined:
+ * Select this item when showing.
+ *
+ * *Note* that only one completion item can be selected and that the
+ * tool / client decides which item that is. The rule is that the *first*
+ * item of those that match best is selected.
+ */
+ Preselect bool `json:"preselect,omitempty"`
+
+ /*SortText defined:
+ * A string that should be used when comparing this item
+ * with other items. When `falsy` the [label](#CompletionItem.label)
+ * is used.
+ */
+ SortText string `json:"sortText,omitempty"`
+
+ /*FilterText defined:
+ * A string that should be used when filtering a set of
+ * completion items. When `falsy` the [label](#CompletionItem.label)
+ * is used.
+ */
+ FilterText string `json:"filterText,omitempty"`
+
+ /*InsertText defined:
+ * A string that should be inserted into a document when selecting
+ * this completion. When `falsy` the [label](#CompletionItem.label)
+ * is used.
+ *
+ * The `insertText` is subject to interpretation by the client side.
+ * Some tools might not take the string literally. For example
+ * VS Code when code complete is requested in this example `con<cursor position>`
+ * and a completion item with an `insertText` of `console` is provided it
+ * will only insert `sole`. Therefore it is recommended to use `textEdit` instead
+ * since it avoids additional client side interpretation.
+ */
+ InsertText string `json:"insertText,omitempty"`
+
+ /*InsertTextFormat defined:
+ * The format of the insert text. The format applies to both the `insertText` property
+ * and the `newText` property of a provided `textEdit`.
+ */
+ InsertTextFormat InsertTextFormat `json:"insertTextFormat,omitempty"`
+
+ /*TextEdit defined:
+ * An [edit](#TextEdit) which is applied to a document when selecting
+ * this completion. When an edit is provided the value of
+ * [insertText](#CompletionItem.insertText) is ignored.
+ *
+ * *Note:* The text edit's range must be a [single line] and it must contain the position
+ * at which completion has been requested.
+ */
+ TextEdit *TextEdit `json:"textEdit,omitempty"`
+
+ /*AdditionalTextEdits defined:
+ * An optional array of additional [text edits](#TextEdit) that are applied when
+ * selecting this completion. Edits must not overlap (including the same insert position)
+ * with the main [edit](#CompletionItem.textEdit) nor with themselves.
+ *
+ * Additional text edits should be used to change text unrelated to the current cursor position
+ * (for example adding an import statement at the top of the file if the completion item will
+ * insert an unqualified type).
+ */
+ AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"`
+
+ /*CommitCharacters defined:
+ * An optional set of characters that when pressed while this completion is active will accept it first and
+ * then type that character. *Note* that all commit characters should have `length=1` and that superfluous
+ * characters will be ignored.
+ */
+ CommitCharacters []string `json:"commitCharacters,omitempty"`
+
+ /*Command defined:
+ * An optional [command](#Command) that is executed *after* inserting this completion. *Note* that
+ * additional modifications to the current document should be described with the
+ * [additionalTextEdits](#CompletionItem.additionalTextEdits)-property.
+ */
+ Command *Command `json:"command,omitempty"`
+
+ /*Data defined:
+ * An data entry field that is preserved on a completion item between
+ * a [CompletionRequest](#CompletionRequest) and a [CompletionResolveRequest]
+ * (#CompletionResolveRequest)
+ */
+ Data interface{} `json:"data,omitempty"`
+}
+
+/*CompletionList defined:
+ * Represents a collection of [completion items](#CompletionItem) to be presented
+ * in the editor.
+ */
+type CompletionList struct {
+
+ /*IsIncomplete defined:
+ * This list it not complete. Further typing results in recomputing this list.
+ */
+ IsIncomplete bool `json:"isIncomplete"`
+
+ /*Items defined:
+ * The completion items.
+ */
+ Items []CompletionItem `json:"items"`
+}
+
+/*Hover defined:
+ * The result of a hover request.
+ */
+type Hover struct {
+
+ /*Contents defined:
+ * The hover's content
+ */
+ Contents MarkupContent `json:"contents"` // MarkupContent | MarkedString | MarkedString[]
+
+ /*Range defined:
+ * An optional range
+ */
+ Range *Range `json:"range,omitempty"`
+}
+
+/*ParameterInformation defined:
+ * Represents a parameter of a callable-signature. A parameter can
+ * have a label and a doc-comment.
+ */
+type ParameterInformation struct {
+
+ /*Label defined:
+ * The label of this parameter information.
+ *
+ * Either a string or an inclusive start and exclusive end offsets within its containing
+ * signature label. (see SignatureInformation.label). The offsets are based on a UTF-16
+ * string representation as `Position` and `Range` does.
+ *
+ * *Note*: a label of type string should be a substring of its containing signature label.
+ * Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`.
+ */
+ Label string `json:"label"` // string | [number, number]
+
+ /*Documentation defined:
+ * The human-readable doc-comment of this signature. Will be shown
+ * in the UI but can be omitted.
+ */
+ Documentation string `json:"documentation,omitempty"` // string | MarkupContent
+}
+
+/*SignatureInformation defined:
+ * Represents the signature of something callable. A signature
+ * can have a label, like a function-name, a doc-comment, and
+ * a set of parameters.
+ */
+type SignatureInformation struct {
+
+ /*Label defined:
+ * The label of this signature. Will be shown in
+ * the UI.
+ */
+ Label string `json:"label"`
+
+ /*Documentation defined:
+ * The human-readable doc-comment of this signature. Will be shown
+ * in the UI but can be omitted.
+ */
+ Documentation string `json:"documentation,omitempty"` // string | MarkupContent
+
+ /*Parameters defined:
+ * The parameters of this signature.
+ */
+ Parameters []ParameterInformation `json:"parameters,omitempty"`
+}
+
+/*SignatureHelp defined:
+ * Signature help represents the signature of something
+ * callable. There can be multiple signature but only one
+ * active and only one active parameter.
+ */
+type SignatureHelp struct {
+
+ /*Signatures defined:
+ * One or more signatures.
+ */
+ Signatures []SignatureInformation `json:"signatures"`
+
+ /*ActiveSignature defined:
+ * The active signature. Set to `null` if no
+ * signatures exist.
+ */
+ ActiveSignature float64 `json:"activeSignature"`
+
+ /*ActiveParameter defined:
+ * The active parameter of the active signature. Set to `null`
+ * if the active signature has no parameters.
+ */
+ ActiveParameter float64 `json:"activeParameter"`
+}
+
+/*ReferenceContext defined:
+ * Value-object that contains additional information when
+ * requesting references.
+ */
+type ReferenceContext struct {
+
+ /*IncludeDeclaration defined:
+ * Include the declaration of the current symbol.
+ */
+ IncludeDeclaration bool `json:"includeDeclaration"`
+}
+
+/*DocumentHighlight defined:
+ * A document highlight is a range inside a text document which deserves
+ * special attention. Usually a document highlight is visualized by changing
+ * the background color of its range.
+ */
+type DocumentHighlight struct {
+
+ /*Range defined:
+ * The range this highlight applies to.
+ */
+ Range Range `json:"range"`
+
+ /*Kind defined:
+ * The highlight kind, default is [text](#DocumentHighlightKind.Text).
+ */
+ Kind *DocumentHighlightKind `json:"kind,omitempty"`
+}
+
+/*SymbolInformation defined:
+ * Represents information about programming constructs like variables, classes,
+ * interfaces etc.
+ */
+type SymbolInformation struct {
+
+ /*Name defined:
+ * The name of this symbol.
+ */
+ Name string `json:"name"`
+
+ /*Kind defined:
+ * The kind of this symbol.
+ */
+ Kind SymbolKind `json:"kind"`
+
+ /*Deprecated defined:
+ * Indicates if this symbol is deprecated.
+ */
+ Deprecated bool `json:"deprecated,omitempty"`
+
+ /*Location defined:
+ * The location of this symbol. The location's range is used by a tool
+ * to reveal the location in the editor. If the symbol is selected in the
+ * tool the range's start information is used to position the cursor. So
+ * the range usually spans more than the actual symbol's name and does
+ * normally include thinks like visibility modifiers.
+ *
+ * The range doesn't have to denote a node range in the sense of a abstract
+ * syntax tree. It can therefore not be used to re-construct a hierarchy of
+ * the symbols.
+ */
+ Location Location `json:"location"`
+
+ /*ContainerName defined:
+ * The name of the symbol containing this symbol. This information is for
+ * user interface purposes (e.g. to render a qualifier in the user interface
+ * if necessary). It can't be used to re-infer a hierarchy for the document
+ * symbols.
+ */
+ ContainerName string `json:"containerName,omitempty"`
+}
+
+/*DocumentSymbol defined:
+ * Represents programming constructs like variables, classes, interfaces etc.
+ * that appear in a document. Document symbols can be hierarchical and they
+ * have two ranges: one that encloses its definition and one that points to
+ * its most interesting range, e.g. the range of an identifier.
+ */
+type DocumentSymbol struct {
+
+ /*Name defined:
+ * The name of this symbol. Will be displayed in the user interface and therefore must not be
+ * an empty string or a string only consisting of white spaces.
+ */
+ Name string `json:"name"`
+
+ /*Detail defined:
+ * More detail for this symbol, e.g the signature of a function.
+ */
+ Detail string `json:"detail,omitempty"`
+
+ /*Kind defined:
+ * The kind of this symbol.
+ */
+ Kind SymbolKind `json:"kind"`
+
+ /*Deprecated defined:
+ * Indicates if this symbol is deprecated.
+ */
+ Deprecated bool `json:"deprecated,omitempty"`
+
+ /*Range defined:
+ * The range enclosing this symbol not including leading/trailing whitespace but everything else
+ * like comments. This information is typically used to determine if the the clients cursor is
+ * inside the symbol to reveal in the symbol in the UI.
+ */
+ Range Range `json:"range"`
+
+ /*SelectionRange defined:
+ * The range that should be selected and revealed when this symbol is being picked, e.g the name of a function.
+ * Must be contained by the the `range`.
+ */
+ SelectionRange Range `json:"selectionRange"`
+
+ /*Children defined:
+ * Children of this symbol, e.g. properties of a class.
+ */
+ Children []DocumentSymbol `json:"children,omitempty"`
+}
+
+/*CodeActionContext defined:
+ * Contains additional diagnostic information about the context in which
+ * a [code action](#CodeActionProvider.provideCodeActions) is run.
+ */
+type CodeActionContext struct {
+
+ /*Diagnostics defined:
+ * An array of diagnostics known on the client side overlapping the range provided to the
+ * `textDocument/codeAction` request. They are provied so that the server knows which
+ * errors are currently presented to the user for the given range. There is no guarantee
+ * that these accurately reflect the error state of the resource. The primary parameter
+ * to compute code actions is the provided range.
+ */
+ Diagnostics []Diagnostic `json:"diagnostics"`
+
+ /*Only defined:
+ * Requested kind of actions to return.
+ *
+ * Actions not of this kind are filtered out by the client before being shown. So servers
+ * can omit computing them.
+ */
+ Only []CodeActionKind `json:"only,omitempty"`
+}
+
+/*CodeAction defined:
+ * A code action represents a change that can be performed in code, e.g. to fix a problem or
+ * to refactor code.
+ *
+ * A CodeAction must set either `edit` and/or a `command`. If both are supplied, the `edit` is applied first, then the `command` is executed.
+ */
+type CodeAction struct {
+
+ /*Title defined:
+ * A short, human-readable, title for this code action.
+ */
+ Title string `json:"title"`
+
+ /*Kind defined:
+ * The kind of the code action.
+ *
+ * Used to filter code actions.
+ */
+ Kind CodeActionKind `json:"kind,omitempty"`
+
+ /*Diagnostics defined:
+ * The diagnostics that this code action resolves.
+ */
+ Diagnostics []Diagnostic `json:"diagnostics,omitempty"`
+
+ /*IsPreferred defined:
+ * Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted
+ * by keybindings.
+ *
+ * A quick fix should be marked preferred if it properly addresses the underlying error.
+ * A refactoring should be marked preferred if it is the most reasonable choice of actions to take.
+ *
+ * @since 3.15.0
+ */
+ IsPreferred bool `json:"isPreferred,omitempty"`
+
+ /*Edit defined:
+ * The workspace edit this code action performs.
+ */
+ Edit *WorkspaceEdit `json:"edit,omitempty"`
+
+ /*Command defined:
+ * A command this code action executes. If a code action
+ * provides a edit and a command, first the edit is
+ * executed and then the command.
+ */
+ Command *Command `json:"command,omitempty"`
+}
+
+/*CodeLens defined:
+ * A code lens represents a [command](#Command) that should be shown along with
+ * source text, like the number of references, a way to run tests, etc.
+ *
+ * A code lens is _unresolved_ when no command is associated to it. For performance
+ * reasons the creation of a code lens and resolving should be done to two stages.
+ */
+type CodeLens struct {
+
+ /*Range defined:
+ * The range in which this code lens is valid. Should only span a single line.
+ */
+ Range Range `json:"range"`
+
+ /*Command defined:
+ * The command this code lens represents.
+ */
+ Command *Command `json:"command,omitempty"`
+
+ /*Data defined:
+ * An data entry field that is preserved on a code lens item between
+ * a [CodeLensRequest](#CodeLensRequest) and a [CodeLensResolveRequest]
+ * (#CodeLensResolveRequest)
+ */
+ Data interface{} `json:"data,omitempty"`
+}
+
+/*FormattingOptions defined:
+ * Value-object describing what options formatting should use.
+ */
+type FormattingOptions struct {
+
+ /*TabSize defined:
+ * Size of a tab in spaces.
+ */
+ TabSize float64 `json:"tabSize"`
+
+ /*InsertSpaces defined:
+ * Prefer spaces over tabs.
+ */
+ InsertSpaces bool `json:"insertSpaces"`
+
+ /*TrimTrailingWhitespace defined:
+ * Trim trailing whitespaces on a line.
+ *
+ * @since 3.15.0
+ */
+ TrimTrailingWhitespace bool `json:"trimTrailingWhitespace,omitempty"`
+
+ /*InsertFinalNewline defined:
+ * Insert a newline character at the end of the file if one does not exist.
+ *
+ * @since 3.15.0
+ */
+ InsertFinalNewline bool `json:"insertFinalNewline,omitempty"`
+
+ /*TrimFinalNewlines defined:
+ * Trim all newlines after the final newline at the end of the file.
+ *
+ * @since 3.15.0
+ */
+ TrimFinalNewlines bool `json:"trimFinalNewlines,omitempty"`
+
+ /*Key defined:
+ * Signature for further properties.
+ */
+ Key map[string]bool `json:"key"` // [key: string]: boolean | number | string | undefined;
+}
+
+/*DocumentLink defined:
+ * A document link is a range in a text document that links to an internal or external resource, like another
+ * text document or a web site.
+ */
+type DocumentLink struct {
+
+ /*Range defined:
+ * The range this link applies to.
+ */
+ Range Range `json:"range"`
+
+ /*Target defined:
+ * The uri this link points to.
+ */
+ Target string `json:"target,omitempty"`
+
+ /*Tooltip defined:
+ * The tooltip text when you hover over this link.
+ *
+ * If a tooltip is provided, is will be displayed in a string that includes instructions on how to
+ * trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS,
+ * user settings, and localization.
+ *
+ * @since 3.15.0
+ */
+ Tooltip string `json:"tooltip,omitempty"`
+
+ /*Data defined:
+ * A data entry field that is preserved on a document link between a
+ * DocumentLinkRequest and a DocumentLinkResolveRequest.
+ */
+ Data interface{} `json:"data,omitempty"`
+}
+
+/*SelectionRange defined:
+ * A selection range represents a part of a selection hierarchy. A selection range
+ * may have a parent selection range that contains it.
+ */
+type SelectionRange struct {
+
+ /*Range defined:
+ * The [range](#Range) of this selection range.
+ */
+ Range Range `json:"range"`
+
+ /*Parent defined:
+ * The parent selection range containing this range. Therefore `parent.range` must contain `this.range`.
+ */
+ Parent *SelectionRange `json:"parent,omitempty"`
+}
+
+/*TextDocument defined:
+ * A simple text document. Not to be implemented.
+ */
+type TextDocument struct {
+
+ /*URI defined:
+ * The associated URI for this document. Most documents have the __file__-scheme, indicating that they
+ * represent files on disk. However, some documents may have other schemes indicating that they are not
+ * available on disk.
+ *
+ * @readonly
+ */
+ URI DocumentURI `json:"uri"`
+
+ /*LanguageID defined:
+ * The identifier of the language associated with this document.
+ *
+ * @readonly
+ */
+ LanguageID string `json:"languageId"`
+
+ /*Version defined:
+ * The version number of this document (it will increase after each
+ * change, including undo/redo).
+ *
+ * @readonly
+ */
+ Version float64 `json:"version"`
+
+ /*LineCount defined:
+ * The number of lines in this document.
+ *
+ * @readonly
+ */
+ LineCount float64 `json:"lineCount"`
+}
+
+/*TextDocumentChangeEvent defined:
+ * Event to signal changes to a simple text document.
+ */
+type TextDocumentChangeEvent struct {
+
+ /*Document defined:
+ * The document that has changed.
+ */
+ Document TextDocument `json:"document"`
+}
+
+// TextDocumentWillSaveEvent is
+type TextDocumentWillSaveEvent struct {
+
+ /*Document defined:
+ * The document that will be saved
+ */
+ Document TextDocument `json:"document"`
+
+ /*Reason defined:
+ * The reason why save was triggered.
+ */
+ Reason TextDocumentSaveReason `json:"reason"`
+}
+
+/*TextDocumentContentChangeEvent defined:
+ * An event describing a change to a text document. If range and rangeLength are omitted
+ * the new text is considered to be the full content of the document.
+ */
+type TextDocumentContentChangeEvent struct {
+
+ /*Range defined:
+ * The range of the document that changed.
+ */
+ Range *Range `json:"range,omitempty"`
+
+ /*RangeLength defined:
+ * The length of the range that got replaced.
+ */
+ RangeLength float64 `json:"rangeLength,omitempty"`
+
+ /*Text defined:
+ * The new text of the document.
+ */
+ Text string `json:"text"`
+}
+
+// ProgressParams is
+type ProgressParams struct {
+
+ /*Token defined:
+ * The progress token provided by the client or server.
+ */
+ Token ProgressToken `json:"token"`
+
+ /*Value defined:
+ * The progress data.
+ */
+ Value interface{} `json:"value"`
+}
+
+// SetTraceParams is
+type SetTraceParams struct {
+
+ // Value is
+ Value TraceValues `json:"value"`
+}
+
+// LogTraceParams is
+type LogTraceParams struct {
+
+ // Message is
+ Message string `json:"message"`
+
+ // Verbose is
+ Verbose string `json:"verbose,omitempty"`
+}
+
+// Tracer is
+type Tracer struct {
+}
+
+// FoldingRangeKind defines constants
+type FoldingRangeKind string
+
+// ResourceOperationKind defines constants
+type ResourceOperationKind string
+
+// FailureHandlingKind defines constants
+type FailureHandlingKind string
+
+// InitializeError defines constants
+type InitializeError float64
+
+// MessageType defines constants
+type MessageType float64
+
+// TextDocumentSyncKind defines constants
+type TextDocumentSyncKind float64
+
+// FileChangeType defines constants
+type FileChangeType float64
+
+// WatchKind defines constants
+type WatchKind float64
+
+// CompletionTriggerKind defines constants
+type CompletionTriggerKind float64
+
+// SignatureHelpTriggerKind defines constants
+type SignatureHelpTriggerKind float64
+
+// DiagnosticSeverity defines constants
+type DiagnosticSeverity float64
+
+// DiagnosticTag defines constants
+type DiagnosticTag float64
+
+// MarkupKind defines constants
+type MarkupKind string
+
+// CompletionItemKind defines constants
+type CompletionItemKind float64
+
+// InsertTextFormat defines constants
+type InsertTextFormat float64
+
+// CompletionItemTag defines constants
+type CompletionItemTag float64
+
+// DocumentHighlightKind defines constants
+type DocumentHighlightKind float64
+
+// SymbolKind defines constants
+type SymbolKind float64
+
+// CodeActionKind defines constants
+type CodeActionKind string
+
+// TextDocumentSaveReason defines constants
+type TextDocumentSaveReason float64
+
+// ErrorCodes defines constants
+type ErrorCodes float64
+
+// Touch defines constants
+type Touch float64
+
+// Trace defines constants
+type Trace string
+
+// TraceFormat defines constants
+type TraceFormat string
+
+// ConnectionErrors defines constants
+type ConnectionErrors float64
+
+// ConnectionState defines constants
+type ConnectionState float64
+
+const (
+
+ /*Comment defined:
+ * Folding range for a comment
+ */
+ Comment FoldingRangeKind = "comment"
+
+ /*Imports defined:
+ * Folding range for a imports or includes
+ */
+ Imports FoldingRangeKind = "imports"
+
+ /*Region defined:
+ * Folding range for a region (e.g. `#region`)
+ */
+ Region FoldingRangeKind = "region"
+
+ /*Create defined:
+ * Supports creating new files and folders.
+ */
+ Create ResourceOperationKind = "create"
+
+ /*Rename defined:
+ * Supports renaming existing files and folders.
+ */
+ Rename ResourceOperationKind = "rename"
+
+ /*Delete defined:
+ * Supports deleting existing files and folders.
+ */
+ Delete ResourceOperationKind = "delete"
+
+ /*Abort defined:
+ * Applying the workspace change is simply aborted if one of the changes provided
+ * fails. All operations executed before the failing operation stay executed.
+ */
+ Abort FailureHandlingKind = "abort"
+
+ /*Transactional defined:
+ * All operations are executed transactional. That means they either all
+ * succeed or no changes at all are applied to the workspace.
+ */
+ Transactional FailureHandlingKind = "transactional"
+
+ /*TextOnlyTransactional defined:
+ * If the workspace edit contains only textual file changes they are executed transactional.
+ * If resource changes (create, rename or delete file) are part of the change the failure
+ * handling startegy is abort.
+ */
+ TextOnlyTransactional FailureHandlingKind = "textOnlyTransactional"
+
+ /*Undo defined:
+ * The client tries to undo the operations already executed. But there is no
+ * guaruntee that this is succeeding.
+ */
+ Undo FailureHandlingKind = "undo"
+
+ /*UnknownProtocolVersion defined:
+ * If the protocol version provided by the client can't be handled by the server.
+ * @deprecated This initialize error got replaced by client capabilities. There is
+ * no version handshake in version 3.0x
+ */
+ UnknownProtocolVersion InitializeError = 1
+
+ /*Error defined:
+ * An error message.
+ */
+ Error MessageType = 1
+
+ /*Warning defined:
+ * A warning message.
+ */
+ Warning MessageType = 2
+
+ /*Info defined:
+ * An information message.
+ */
+ Info MessageType = 3
+
+ /*Log defined:
+ * A log message.
+ */
+ Log MessageType = 4
+
+ /*None defined:
+ * Documents should not be synced at all.
+ */
+ None TextDocumentSyncKind = 0
+
+ /*Full defined:
+ * Documents are synced by always sending the full content
+ * of the document.
+ */
+ Full TextDocumentSyncKind = 1
+
+ /*Incremental defined:
+ * Documents are synced by sending the full content on open.
+ * After that only incremental updates to the document are
+ * send.
+ */
+ Incremental TextDocumentSyncKind = 2
+
+ /*Created defined:
+ * The file got created.
+ */
+ Created FileChangeType = 1
+
+ /*Changed defined:
+ * The file got changed.
+ */
+ Changed FileChangeType = 2
+
+ /*Deleted defined:
+ * The file got deleted.
+ */
+ Deleted FileChangeType = 3
+
+ /*WatchCreate defined:
+ * Interested in create events.
+ */
+ WatchCreate WatchKind = 1
+
+ /*WatchChange defined:
+ * Interested in change events
+ */
+ WatchChange WatchKind = 2
+
+ /*WatchDelete defined:
+ * Interested in delete events
+ */
+ WatchDelete WatchKind = 4
+
+ /*Invoked defined:
+ * Completion was triggered by typing an identifier (24x7 code
+ * complete), manual invocation (e.g Ctrl+Space) or via API.
+ */
+ Invoked CompletionTriggerKind = 1
+
+ /*TriggerCharacter defined:
+ * Completion was triggered by a trigger character specified by
+ * the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
+ */
+ TriggerCharacter CompletionTriggerKind = 2
+
+ /*TriggerForIncompleteCompletions defined:
+ * Completion was re-triggered as current completion list is incomplete
+ */
+ TriggerForIncompleteCompletions CompletionTriggerKind = 3
+
+ /*ContentChange defined:
+ * Signature help was triggered by the cursor moving or by the document content changing.
+ */
+ ContentChange SignatureHelpTriggerKind = 3
+
+ /*SeverityError defined:
+ * Reports an error.
+ */
+ SeverityError DiagnosticSeverity = 1
+
+ /*SeverityWarning defined:
+ * Reports a warning.
+ */
+ SeverityWarning DiagnosticSeverity = 2
+
+ /*SeverityInformation defined:
+ * Reports an information.
+ */
+ SeverityInformation DiagnosticSeverity = 3
+
+ /*SeverityHint defined:
+ * Reports a hint.
+ */
+ SeverityHint DiagnosticSeverity = 4
+
+ /*Unnecessary defined:
+ * Unused or unnecessary code.
+ *
+ * Clients are allowed to render diagnostics with this tag faded out instead of having
+ * an error squiggle.
+ */
+ Unnecessary DiagnosticTag = 1
+
+ /*Deprecated defined:
+ * Deprecated or obsolete code.
+ *
+ * Clients are allowed to rendered diagnostics with this tag strike through.
+ */
+ Deprecated DiagnosticTag = 2
+
+ /*PlainText defined:
+ * Plain text is supported as a content format
+ */
+ PlainText MarkupKind = "plaintext"
+
+ /*Markdown defined:
+ * Markdown is supported as a content format
+ */
+ Markdown MarkupKind = "markdown"
+
+ // TextCompletion is
+ TextCompletion CompletionItemKind = 1
+
+ // MethodCompletion is
+ MethodCompletion CompletionItemKind = 2
+
+ // FunctionCompletion is
+ FunctionCompletion CompletionItemKind = 3
+
+ // ConstructorCompletion is
+ ConstructorCompletion CompletionItemKind = 4
+
+ // FieldCompletion is
+ FieldCompletion CompletionItemKind = 5
+
+ // VariableCompletion is
+ VariableCompletion CompletionItemKind = 6
+
+ // ClassCompletion is
+ ClassCompletion CompletionItemKind = 7
+
+ // InterfaceCompletion is
+ InterfaceCompletion CompletionItemKind = 8
+
+ // ModuleCompletion is
+ ModuleCompletion CompletionItemKind = 9
+
+ // PropertyCompletion is
+ PropertyCompletion CompletionItemKind = 10
+
+ // UnitCompletion is
+ UnitCompletion CompletionItemKind = 11
+
+ // ValueCompletion is
+ ValueCompletion CompletionItemKind = 12
+
+ // EnumCompletion is
+ EnumCompletion CompletionItemKind = 13
+
+ // KeywordCompletion is
+ KeywordCompletion CompletionItemKind = 14
+
+ // SnippetCompletion is
+ SnippetCompletion CompletionItemKind = 15
+
+ // ColorCompletion is
+ ColorCompletion CompletionItemKind = 16
+
+ // FileCompletion is
+ FileCompletion CompletionItemKind = 17
+
+ // ReferenceCompletion is
+ ReferenceCompletion CompletionItemKind = 18
+
+ // FolderCompletion is
+ FolderCompletion CompletionItemKind = 19
+
+ // EnumMemberCompletion is
+ EnumMemberCompletion CompletionItemKind = 20
+
+ // ConstantCompletion is
+ ConstantCompletion CompletionItemKind = 21
+
+ // StructCompletion is
+ StructCompletion CompletionItemKind = 22
+
+ // EventCompletion is
+ EventCompletion CompletionItemKind = 23
+
+ // OperatorCompletion is
+ OperatorCompletion CompletionItemKind = 24
+
+ // TypeParameterCompletion is
+ TypeParameterCompletion CompletionItemKind = 25
+
+ /*PlainTextTextFormat defined:
+ * The primary text to be inserted is treated as a plain string.
+ */
+ PlainTextTextFormat InsertTextFormat = 1
+
+ /*SnippetTextFormat defined:
+ * The primary text to be inserted is treated as a snippet.
+ *
+ * A snippet can define tab stops and placeholders with `$1`, `$2`
+ * and `${3:foo}`. `$0` defines the final tab stop, it defaults to
+ * the end of the snippet. Placeholders with equal identifiers are linked,
+ * that is typing in one will update others too.
+ *
+ * See also: https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md
+ */
+ SnippetTextFormat InsertTextFormat = 2
+
+ /*Text defined:
+ * A textual occurrence.
+ */
+ Text DocumentHighlightKind = 1
+
+ /*Read defined:
+ * Read-access of a symbol, like reading a variable.
+ */
+ Read DocumentHighlightKind = 2
+
+ /*Write defined:
+ * Write-access of a symbol, like writing to a variable.
+ */
+ Write DocumentHighlightKind = 3
+
+ // File is
+ File SymbolKind = 1
+
+ // Module is
+ Module SymbolKind = 2
+
+ // Namespace is
+ Namespace SymbolKind = 3
+
+ // Package is
+ Package SymbolKind = 4
+
+ // Class is
+ Class SymbolKind = 5
+
+ // Method is
+ Method SymbolKind = 6
+
+ // Property is
+ Property SymbolKind = 7
+
+ // Field is
+ Field SymbolKind = 8
+
+ // Constructor is
+ Constructor SymbolKind = 9
+
+ // Enum is
+ Enum SymbolKind = 10
+
+ // Interface is
+ Interface SymbolKind = 11
+
+ // Function is
+ Function SymbolKind = 12
+
+ // Variable is
+ Variable SymbolKind = 13
+
+ // Constant is
+ Constant SymbolKind = 14
+
+ // String is
+ String SymbolKind = 15
+
+ // Number is
+ Number SymbolKind = 16
+
+ // Boolean is
+ Boolean SymbolKind = 17
+
+ // Array is
+ Array SymbolKind = 18
+
+ // Object is
+ Object SymbolKind = 19
+
+ // Key is
+ Key SymbolKind = 20
+
+ // Null is
+ Null SymbolKind = 21
+
+ // EnumMember is
+ EnumMember SymbolKind = 22
+
+ // Struct is
+ Struct SymbolKind = 23
+
+ // Event is
+ Event SymbolKind = 24
+
+ // Operator is
+ Operator SymbolKind = 25
+
+ // TypeParameter is
+ TypeParameter SymbolKind = 26
+
+ /*Empty defined:
+ * Empty kind.
+ */
+ Empty CodeActionKind = ""
+
+ /*QuickFix defined:
+ * Base kind for quickfix actions: 'quickfix'
+ */
+ QuickFix CodeActionKind = "quickfix"
+
+ /*Refactor defined:
+ * Base kind for refactoring actions: 'refactor'
+ */
+ Refactor CodeActionKind = "refactor"
+
+ /*RefactorExtract defined:
+ * Base kind for refactoring extraction actions: 'refactor.extract'
+ *
+ * Example extract actions:
+ *
+ * - Extract method
+ * - Extract function
+ * - Extract variable
+ * - Extract interface from class
+ * - ...
+ */
+ RefactorExtract CodeActionKind = "refactor.extract"
+
+ /*RefactorInline defined:
+ * Base kind for refactoring inline actions: 'refactor.inline'
+ *
+ * Example inline actions:
+ *
+ * - Inline function
+ * - Inline variable
+ * - Inline constant
+ * - ...
+ */
+ RefactorInline CodeActionKind = "refactor.inline"
+
+ /*RefactorRewrite defined:
+ * Base kind for refactoring rewrite actions: 'refactor.rewrite'
+ *
+ * Example rewrite actions:
+ *
+ * - Convert JavaScript function to class
+ * - Add or remove parameter
+ * - Encapsulate field
+ * - Make method static
+ * - Move method to base class
+ * - ...
+ */
+ RefactorRewrite CodeActionKind = "refactor.rewrite"
+
+ /*Source defined:
+ * Base kind for source actions: `source`
+ *
+ * Source code actions apply to the entire file.
+ */
+ Source CodeActionKind = "source"
+
+ /*SourceOrganizeImports defined:
+ * Base kind for an organize imports source action: `source.organizeImports`
+ */
+ SourceOrganizeImports CodeActionKind = "source.organizeImports"
+
+ /*Manual defined:
+ * Manually triggered, e.g. by the user pressing save, by starting debugging,
+ * or by an API call.
+ */
+ Manual TextDocumentSaveReason = 1
+
+ /*AfterDelay defined:
+ * Automatic after a delay.
+ */
+ AfterDelay TextDocumentSaveReason = 2
+
+ /*FocusOut defined:
+ * When the editor lost focus.
+ */
+ FocusOut TextDocumentSaveReason = 3
+
+ // MessageWriteError is
+ MessageWriteError ErrorCodes = 1
+
+ // MessageReadError is
+ MessageReadError ErrorCodes = 2
+
+ // First is
+ First Touch = 1
+
+ // Last is
+ Last Touch = 2
+
+ // JSON is
+ JSON TraceFormat = "json"
+
+ /*Closed defined:
+ * The connection is closed.
+ */
+ Closed ConnectionErrors = 1
+
+ /*Disposed defined:
+ * The connection got disposed.
+ */
+ Disposed ConnectionErrors = 2
+
+ /*AlreadyListening defined:
+ * The connection is already in listening mode.
+ */
+ AlreadyListening ConnectionErrors = 3
+
+ // New is
+ New ConnectionState = 1
+
+ // Listening is
+ Listening ConnectionState = 2
+)
+
+// DocumentFilter is a type
+/**
+ * A document filter denotes a document by different properties like
+ * the [language](#TextDocument.languageId), the [scheme](#Uri.scheme) of
+ * its resource, or a glob-pattern that is applied to the [path](#TextDocument.fileName).
+ *
+ * Glob patterns can have the following syntax:
+ * - `*` to match one or more characters in a path segment
+ * - `?` to match on one character in a path segment
+ * - `**` to match any number of path segments, including none
+ * - `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files)
+ * - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
+ * - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)
+ *
+ * @sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }`
+ * @sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }`
+ */
+type DocumentFilter = struct {
+
+ /*Language defined: A language id, like `typescript`. */
+ Language string `json:"language,omitempty"`
+
+ /*Scheme defined: A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */
+ Scheme string `json:"scheme,omitempty"`
+
+ /*Pattern defined: A glob pattern, like `*.{ts,js}`. */
+ Pattern string `json:"pattern,omitempty"`
+}
+
+// DocumentSelector is a type
+/**
+ * A document selector is the combination of one or many document filters.
+ *
+ * @sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`;
+ */
+type DocumentSelector = []DocumentFilter
+
+// DocumentURI is a type
+/**
+ * A tagging type for string properties that are actually URIs.
+ */
+type DocumentURI = string
+
+// MarkedString is a type
+/**
+ * MarkedString can be used to render human readable text. It is either a markdown string
+ * or a code-block that provides a language and a code snippet. The language identifier
+ * is semantically equal to the optional language identifier in fenced code blocks in GitHub
+ * issues. See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
+ *
+ * The pair of a language and a value is an equivalent to markdown:
+ * ```${language}
+ * ${value}
+ * ```
+ *
+ * Note that markdown strings will be sanitized - that means html will be escaped.
+ * @deprecated use MarkupContent instead.
+ */
+type MarkedString = string
+
+// DefinitionLink is a type
+/**
+ * Information about where a symbol is defined.
+ *
+ * Provides additional metadata over normal [location](#Location) definitions, including the range of
+ * the defining symbol
+ */
+type DefinitionLink = LocationLink
+
+// DeclarationLink is a type
+/**
+ * Information about where a symbol is declared.
+ *
+ * Provides additional metadata over normal [location](#Location) declarations, including the range of
+ * the declaring symbol.
+ *
+ * Servers should prefer returning `DeclarationLink` over `Declaration` if supported
+ * by the client.
+ */
+type DeclarationLink = LocationLink
+
+// LSPMessageType is a type
+/**
+ * A LSP Log Entry.
+ */
+type LSPMessageType = string
+
+// ProgressToken is a type
+type ProgressToken = interface{} // number | string
+// TraceValues is a type
+type TraceValues = string
diff --git a/utils/vscode/src/lsp/protocol/tsserver.go b/utils/vscode/src/lsp/protocol/tsserver.go
new file mode 100644
index 0000000..d760501
--- /dev/null
+++ b/utils/vscode/src/lsp/protocol/tsserver.go
@@ -0,0 +1,842 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+package protocol
+
+import (
+ "context"
+ "encoding/json"
+ "log"
+
+ "../jsonrpc2"
+)
+
+type Server interface {
+ DidChangeWorkspaceFolders(context.Context, *DidChangeWorkspaceFoldersParams) error
+ Initialized(context.Context, *InitializedParams) error
+ Exit(context.Context) error
+ DidChangeConfiguration(context.Context, *DidChangeConfigurationParams) error
+ DidOpen(context.Context, *DidOpenTextDocumentParams) error
+ DidChange(context.Context, *DidChangeTextDocumentParams) error
+ DidClose(context.Context, *DidCloseTextDocumentParams) error
+ DidSave(context.Context, *DidSaveTextDocumentParams) error
+ WillSave(context.Context, *WillSaveTextDocumentParams) error
+ DidChangeWatchedFiles(context.Context, *DidChangeWatchedFilesParams) error
+ Progress(context.Context, *ProgressParams) error
+ SetTraceNotification(context.Context, *SetTraceParams) error
+ LogTraceNotification(context.Context, *LogTraceParams) error
+ Implementation(context.Context, *ImplementationParams) ([]Location, error)
+ TypeDefinition(context.Context, *TypeDefinitionParams) ([]Location, error)
+ DocumentColor(context.Context, *DocumentColorParams) ([]ColorInformation, error)
+ ColorPresentation(context.Context, *ColorPresentationParams) ([]ColorPresentation, error)
+ FoldingRange(context.Context, *FoldingRangeParams) ([]FoldingRange, error)
+ Declaration(context.Context, *DeclarationParams) ([]DeclarationLink, error)
+ SelectionRange(context.Context, *SelectionRangeParams) ([]SelectionRange, error)
+ Initialize(context.Context, *ParamInitia) (*InitializeResult, error)
+ Shutdown(context.Context) error
+ WillSaveWaitUntil(context.Context, *WillSaveTextDocumentParams) ([]TextEdit, error)
+ Completion(context.Context, *CompletionParams) (*CompletionList, error)
+ Resolve(context.Context, *CompletionItem) (*CompletionItem, error)
+ Hover(context.Context, *HoverParams) (*Hover, error)
+ SignatureHelp(context.Context, *SignatureHelpParams) (*SignatureHelp, error)
+ Definition(context.Context, *DefinitionParams) ([]Location, error)
+ References(context.Context, *ReferenceParams) ([]Location, error)
+ DocumentHighlight(context.Context, *DocumentHighlightParams) ([]DocumentHighlight, error)
+ DocumentSymbol(context.Context, *DocumentSymbolParams) ([]DocumentSymbol, error)
+ CodeAction(context.Context, *CodeActionParams) ([]CodeAction, error)
+ Symbol(context.Context, *WorkspaceSymbolParams) ([]SymbolInformation, error)
+ CodeLens(context.Context, *CodeLensParams) ([]CodeLens, error)
+ ResolveCodeLens(context.Context, *CodeLens) (*CodeLens, error)
+ DocumentLink(context.Context, *DocumentLinkParams) ([]DocumentLink, error)
+ ResolveDocumentLink(context.Context, *DocumentLink) (*DocumentLink, error)
+ Formatting(context.Context, *DocumentFormattingParams) ([]TextEdit, error)
+ RangeFormatting(context.Context, *DocumentRangeFormattingParams) ([]TextEdit, error)
+ OnTypeFormatting(context.Context, *DocumentOnTypeFormattingParams) ([]TextEdit, error)
+ Rename(context.Context, *RenameParams) (*WorkspaceEdit, error)
+ PrepareRename(context.Context, *PrepareRenameParams) (*Range, error)
+ ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{}, error)
+}
+
+func (h serverHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
+ if delivered {
+ return false
+ }
+ if ctx.Err() != nil {
+ r.Reply(ctx, nil, jsonrpc2.NewErrorf(RequestCancelledError, ""))
+ return true
+ }
+ switch r.Method {
+ case "workspace/didChangeWorkspaceFolders": // notif
+ var params DidChangeWorkspaceFoldersParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.DidChangeWorkspaceFolders(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "initialized": // notif
+ var params InitializedParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.Initialized(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "exit": // notif
+ if err := h.server.Exit(ctx); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "workspace/didChangeConfiguration": // notif
+ var params DidChangeConfigurationParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.DidChangeConfiguration(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/didOpen": // notif
+ var params DidOpenTextDocumentParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.DidOpen(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/didChange": // notif
+ var params DidChangeTextDocumentParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.DidChange(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/didClose": // notif
+ var params DidCloseTextDocumentParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.DidClose(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/didSave": // notif
+ var params DidSaveTextDocumentParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.DidSave(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/willSave": // notif
+ var params WillSaveTextDocumentParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.WillSave(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "workspace/didChangeWatchedFiles": // notif
+ var params DidChangeWatchedFilesParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.DidChangeWatchedFiles(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "$/progress": // notif
+ var params ProgressParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.Progress(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "$/setTraceNotification": // notif
+ var params SetTraceParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.SetTraceNotification(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "$/logTraceNotification": // notif
+ var params LogTraceParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ if err := h.server.LogTraceNotification(ctx, ¶ms); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/implementation": // req
+ var params ImplementationParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Implementation(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/typeDefinition": // req
+ var params TypeDefinitionParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.TypeDefinition(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/documentColor": // req
+ var params DocumentColorParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.DocumentColor(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/colorPresentation": // req
+ var params ColorPresentationParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.ColorPresentation(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/foldingRange": // req
+ var params FoldingRangeParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.FoldingRange(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/declaration": // req
+ var params DeclarationParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Declaration(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/selectionRange": // req
+ var params SelectionRangeParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.SelectionRange(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "initialize": // req
+ var params ParamInitia
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Initialize(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "shutdown": // req
+ if r.Params != nil {
+ r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
+ return true
+ }
+ err := h.server.Shutdown(ctx)
+ if err := r.Reply(ctx, nil, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/willSaveWaitUntil": // req
+ var params WillSaveTextDocumentParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.WillSaveWaitUntil(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/completion": // req
+ var params CompletionParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Completion(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "completionItem/resolve": // req
+ var params CompletionItem
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Resolve(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/hover": // req
+ var params HoverParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Hover(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/signatureHelp": // req
+ var params SignatureHelpParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.SignatureHelp(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/definition": // req
+ var params DefinitionParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Definition(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/references": // req
+ var params ReferenceParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.References(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/documentHighlight": // req
+ var params DocumentHighlightParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.DocumentHighlight(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/documentSymbol": // req
+ var params DocumentSymbolParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.DocumentSymbol(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/codeAction": // req
+ var params CodeActionParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.CodeAction(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "workspace/symbol": // req
+ var params WorkspaceSymbolParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Symbol(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/codeLens": // req
+ var params CodeLensParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.CodeLens(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "codeLens/resolve": // req
+ var params CodeLens
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.ResolveCodeLens(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/documentLink": // req
+ var params DocumentLinkParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.DocumentLink(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "documentLink/resolve": // req
+ var params DocumentLink
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.ResolveDocumentLink(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/formatting": // req
+ var params DocumentFormattingParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Formatting(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/rangeFormatting": // req
+ var params DocumentRangeFormattingParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.RangeFormatting(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/onTypeFormatting": // req
+ var params DocumentOnTypeFormattingParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.OnTypeFormatting(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/rename": // req
+ var params RenameParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.Rename(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "textDocument/prepareRename": // req
+ var params PrepareRenameParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.PrepareRename(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+ case "workspace/executeCommand": // req
+ var params ExecuteCommandParams
+ if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
+ sendParseError(ctx, r, err)
+ return true
+ }
+ resp, err := h.server.ExecuteCommand(ctx, ¶ms)
+ if err := r.Reply(ctx, resp, err); err != nil {
+ log.Printf("%v", err)
+ }
+ return true
+
+ default:
+ return false
+ }
+}
+
+type serverDispatcher struct {
+ *jsonrpc2.Conn
+}
+
+func (s *serverDispatcher) DidChangeWorkspaceFolders(ctx context.Context, params *DidChangeWorkspaceFoldersParams) error {
+ return s.Conn.Notify(ctx, "workspace/didChangeWorkspaceFolders", params)
+}
+
+func (s *serverDispatcher) Initialized(ctx context.Context, params *InitializedParams) error {
+ return s.Conn.Notify(ctx, "initialized", params)
+}
+
+func (s *serverDispatcher) Exit(ctx context.Context) error {
+ return s.Conn.Notify(ctx, "exit", nil)
+}
+
+func (s *serverDispatcher) DidChangeConfiguration(ctx context.Context, params *DidChangeConfigurationParams) error {
+ return s.Conn.Notify(ctx, "workspace/didChangeConfiguration", params)
+}
+
+func (s *serverDispatcher) DidOpen(ctx context.Context, params *DidOpenTextDocumentParams) error {
+ return s.Conn.Notify(ctx, "textDocument/didOpen", params)
+}
+
+func (s *serverDispatcher) DidChange(ctx context.Context, params *DidChangeTextDocumentParams) error {
+ return s.Conn.Notify(ctx, "textDocument/didChange", params)
+}
+
+func (s *serverDispatcher) DidClose(ctx context.Context, params *DidCloseTextDocumentParams) error {
+ return s.Conn.Notify(ctx, "textDocument/didClose", params)
+}
+
+func (s *serverDispatcher) DidSave(ctx context.Context, params *DidSaveTextDocumentParams) error {
+ return s.Conn.Notify(ctx, "textDocument/didSave", params)
+}
+
+func (s *serverDispatcher) WillSave(ctx context.Context, params *WillSaveTextDocumentParams) error {
+ return s.Conn.Notify(ctx, "textDocument/willSave", params)
+}
+
+func (s *serverDispatcher) DidChangeWatchedFiles(ctx context.Context, params *DidChangeWatchedFilesParams) error {
+ return s.Conn.Notify(ctx, "workspace/didChangeWatchedFiles", params)
+}
+
+func (s *serverDispatcher) Progress(ctx context.Context, params *ProgressParams) error {
+ return s.Conn.Notify(ctx, "$/progress", params)
+}
+
+func (s *serverDispatcher) SetTraceNotification(ctx context.Context, params *SetTraceParams) error {
+ return s.Conn.Notify(ctx, "$/setTraceNotification", params)
+}
+
+func (s *serverDispatcher) LogTraceNotification(ctx context.Context, params *LogTraceParams) error {
+ return s.Conn.Notify(ctx, "$/logTraceNotification", params)
+}
+func (s *serverDispatcher) Implementation(ctx context.Context, params *ImplementationParams) ([]Location, error) {
+ var result []Location
+ if err := s.Conn.Call(ctx, "textDocument/implementation", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) TypeDefinition(ctx context.Context, params *TypeDefinitionParams) ([]Location, error) {
+ var result []Location
+ if err := s.Conn.Call(ctx, "textDocument/typeDefinition", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) DocumentColor(ctx context.Context, params *DocumentColorParams) ([]ColorInformation, error) {
+ var result []ColorInformation
+ if err := s.Conn.Call(ctx, "textDocument/documentColor", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) ColorPresentation(ctx context.Context, params *ColorPresentationParams) ([]ColorPresentation, error) {
+ var result []ColorPresentation
+ if err := s.Conn.Call(ctx, "textDocument/colorPresentation", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) FoldingRange(ctx context.Context, params *FoldingRangeParams) ([]FoldingRange, error) {
+ var result []FoldingRange
+ if err := s.Conn.Call(ctx, "textDocument/foldingRange", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) Declaration(ctx context.Context, params *DeclarationParams) ([]DeclarationLink, error) {
+ var result []DeclarationLink
+ if err := s.Conn.Call(ctx, "textDocument/declaration", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) SelectionRange(ctx context.Context, params *SelectionRangeParams) ([]SelectionRange, error) {
+ var result []SelectionRange
+ if err := s.Conn.Call(ctx, "textDocument/selectionRange", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) Initialize(ctx context.Context, params *ParamInitia) (*InitializeResult, error) {
+ var result InitializeResult
+ if err := s.Conn.Call(ctx, "initialize", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *serverDispatcher) Shutdown(ctx context.Context) error {
+ return s.Conn.Call(ctx, "shutdown", nil, nil)
+}
+
+func (s *serverDispatcher) WillSaveWaitUntil(ctx context.Context, params *WillSaveTextDocumentParams) ([]TextEdit, error) {
+ var result []TextEdit
+ if err := s.Conn.Call(ctx, "textDocument/willSaveWaitUntil", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) Completion(ctx context.Context, params *CompletionParams) (*CompletionList, error) {
+ var result CompletionList
+ if err := s.Conn.Call(ctx, "textDocument/completion", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *serverDispatcher) Resolve(ctx context.Context, params *CompletionItem) (*CompletionItem, error) {
+ var result CompletionItem
+ if err := s.Conn.Call(ctx, "completionItem/resolve", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *serverDispatcher) Hover(ctx context.Context, params *HoverParams) (*Hover, error) {
+ var result Hover
+ if err := s.Conn.Call(ctx, "textDocument/hover", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *serverDispatcher) SignatureHelp(ctx context.Context, params *SignatureHelpParams) (*SignatureHelp, error) {
+ var result SignatureHelp
+ if err := s.Conn.Call(ctx, "textDocument/signatureHelp", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *serverDispatcher) Definition(ctx context.Context, params *DefinitionParams) ([]Location, error) {
+ var result []Location
+ if err := s.Conn.Call(ctx, "textDocument/definition", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) References(ctx context.Context, params *ReferenceParams) ([]Location, error) {
+ var result []Location
+ if err := s.Conn.Call(ctx, "textDocument/references", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) DocumentHighlight(ctx context.Context, params *DocumentHighlightParams) ([]DocumentHighlight, error) {
+ var result []DocumentHighlight
+ if err := s.Conn.Call(ctx, "textDocument/documentHighlight", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) DocumentSymbol(ctx context.Context, params *DocumentSymbolParams) ([]DocumentSymbol, error) {
+ var result []DocumentSymbol
+ if err := s.Conn.Call(ctx, "textDocument/documentSymbol", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) CodeAction(ctx context.Context, params *CodeActionParams) ([]CodeAction, error) {
+ var result []CodeAction
+ if err := s.Conn.Call(ctx, "textDocument/codeAction", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) Symbol(ctx context.Context, params *WorkspaceSymbolParams) ([]SymbolInformation, error) {
+ var result []SymbolInformation
+ if err := s.Conn.Call(ctx, "workspace/symbol", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) CodeLens(ctx context.Context, params *CodeLensParams) ([]CodeLens, error) {
+ var result []CodeLens
+ if err := s.Conn.Call(ctx, "textDocument/codeLens", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) ResolveCodeLens(ctx context.Context, params *CodeLens) (*CodeLens, error) {
+ var result CodeLens
+ if err := s.Conn.Call(ctx, "codeLens/resolve", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *serverDispatcher) DocumentLink(ctx context.Context, params *DocumentLinkParams) ([]DocumentLink, error) {
+ var result []DocumentLink
+ if err := s.Conn.Call(ctx, "textDocument/documentLink", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) ResolveDocumentLink(ctx context.Context, params *DocumentLink) (*DocumentLink, error) {
+ var result DocumentLink
+ if err := s.Conn.Call(ctx, "documentLink/resolve", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *serverDispatcher) Formatting(ctx context.Context, params *DocumentFormattingParams) ([]TextEdit, error) {
+ var result []TextEdit
+ if err := s.Conn.Call(ctx, "textDocument/formatting", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) RangeFormatting(ctx context.Context, params *DocumentRangeFormattingParams) ([]TextEdit, error) {
+ var result []TextEdit
+ if err := s.Conn.Call(ctx, "textDocument/rangeFormatting", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) OnTypeFormatting(ctx context.Context, params *DocumentOnTypeFormattingParams) ([]TextEdit, error) {
+ var result []TextEdit
+ if err := s.Conn.Call(ctx, "textDocument/onTypeFormatting", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (s *serverDispatcher) Rename(ctx context.Context, params *RenameParams) (*WorkspaceEdit, error) {
+ var result WorkspaceEdit
+ if err := s.Conn.Call(ctx, "textDocument/rename", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *serverDispatcher) PrepareRename(ctx context.Context, params *PrepareRenameParams) (*Range, error) {
+ var result Range
+ if err := s.Conn.Call(ctx, "textDocument/prepareRename", params, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (s *serverDispatcher) ExecuteCommand(ctx context.Context, params *ExecuteCommandParams) (interface{}, error) {
+ var result interface{}
+ if err := s.Conn.Call(ctx, "workspace/executeCommand", params, &result); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+type CancelParams struct {
+ /**
+ * The request id to cancel.
+ */
+ ID jsonrpc2.ID `json:"id"`
+}
+
+// Types constructed to avoid structs as formal argument types
+type ParamInitia struct {
+ InitializeParams
+ WorkDoneProgressParams
+}
diff --git a/utils/vscode/src/lsp/span/parse.go b/utils/vscode/src/lsp/span/parse.go
new file mode 100644
index 0000000..ec393c2
--- /dev/null
+++ b/utils/vscode/src/lsp/span/parse.go
@@ -0,0 +1,110 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+package span
+
+import (
+ "strconv"
+ "strings"
+ "unicode/utf8"
+)
+
+// Parse returns the location represented by the input.
+// All inputs are valid locations, as they can always be a pure filename.
+// The returned span will be normalized, and thus if printed may produce a
+// different string.
+func Parse(input string) Span {
+ // :0:0#0-0:0#0
+ valid := input
+ var hold, offset int
+ hadCol := false
+ suf := rstripSuffix(input)
+ if suf.sep == "#" {
+ offset = suf.num
+ suf = rstripSuffix(suf.remains)
+ }
+ if suf.sep == ":" {
+ valid = suf.remains
+ hold = suf.num
+ hadCol = true
+ suf = rstripSuffix(suf.remains)
+ }
+ switch {
+ case suf.sep == ":":
+ return New(NewURI(suf.remains), NewPoint(suf.num, hold, offset), Point{})
+ case suf.sep == "-":
+ // we have a span, fall out of the case to continue
+ default:
+ // separator not valid, rewind to either the : or the start
+ return New(NewURI(valid), NewPoint(hold, 0, offset), Point{})
+ }
+ // only the span form can get here
+ // at this point we still don't know what the numbers we have mean
+ // if have not yet seen a : then we might have either a line or a column depending
+ // on whether start has a column or not
+ // we build an end point and will fix it later if needed
+ end := NewPoint(suf.num, hold, offset)
+ hold, offset = 0, 0
+ suf = rstripSuffix(suf.remains)
+ if suf.sep == "#" {
+ offset = suf.num
+ suf = rstripSuffix(suf.remains)
+ }
+ if suf.sep != ":" {
+ // turns out we don't have a span after all, rewind
+ return New(NewURI(valid), end, Point{})
+ }
+ valid = suf.remains
+ hold = suf.num
+ suf = rstripSuffix(suf.remains)
+ if suf.sep != ":" {
+ // line#offset only
+ return New(NewURI(valid), NewPoint(hold, 0, offset), end)
+ }
+ // we have a column, so if end only had one number, it is also the column
+ if !hadCol {
+ end = NewPoint(suf.num, end.v.Line, end.v.Offset)
+ }
+ return New(NewURI(suf.remains), NewPoint(suf.num, hold, offset), end)
+}
+
+type suffix struct {
+ remains string
+ sep string
+ num int
+}
+
+func rstripSuffix(input string) suffix {
+ if len(input) == 0 {
+ return suffix{"", "", -1}
+ }
+ remains := input
+ num := -1
+ // first see if we have a number at the end
+ last := strings.LastIndexFunc(remains, func(r rune) bool { return r < '0' || r > '9' })
+ if last >= 0 && last < len(remains)-1 {
+ number, err := strconv.ParseInt(remains[last+1:], 10, 64)
+ if err == nil {
+ num = int(number)
+ remains = remains[:last+1]
+ }
+ }
+ // now see if we have a trailing separator
+ r, w := utf8.DecodeLastRuneInString(remains)
+ if r != ':' && r != '#' && r == '#' {
+ return suffix{input, "", -1}
+ }
+ remains = remains[:len(remains)-w]
+ return suffix{remains, string(r), num}
+}
diff --git a/utils/vscode/src/lsp/span/span.go b/utils/vscode/src/lsp/span/span.go
new file mode 100644
index 0000000..aefd4f3
--- /dev/null
+++ b/utils/vscode/src/lsp/span/span.go
@@ -0,0 +1,295 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+// Package span contains support for representing with positions and ranges in
+// text files.
+package span
+
+import (
+ "encoding/json"
+ "fmt"
+ "path"
+)
+
+// Span represents a source code range in standardized form.
+type Span struct {
+ v span
+}
+
+// Point represents a single point within a file.
+// In general this should only be used as part of a Span, as on its own it
+// does not carry enough information.
+type Point struct {
+ v point
+}
+
+type span struct {
+ URI URI `json:"uri"`
+ Start point `json:"start"`
+ End point `json:"end"`
+}
+
+type point struct {
+ Line int `json:"line"`
+ Column int `json:"column"`
+ Offset int `json:"offset"`
+}
+
+// Invalid is a span that reports false from IsValid
+var Invalid = Span{v: span{Start: invalidPoint.v, End: invalidPoint.v}}
+
+var invalidPoint = Point{v: point{Line: 0, Column: 0, Offset: -1}}
+
+// Converter is the interface to an object that can convert between line:column
+// and offset forms for a single file.
+type Converter interface {
+ //ToPosition converts from an offset to a line:column pair.
+ ToPosition(offset int) (int, int, error)
+ //ToOffset converts from a line:column pair to an offset.
+ ToOffset(line, col int) (int, error)
+}
+
+func New(uri URI, start Point, end Point) Span {
+ s := Span{v: span{URI: uri, Start: start.v, End: end.v}}
+ s.v.clean()
+ return s
+}
+
+func NewPoint(line, col, offset int) Point {
+ p := Point{v: point{Line: line, Column: col, Offset: offset}}
+ p.v.clean()
+ return p
+}
+
+func Compare(a, b Span) int {
+ if r := CompareURI(a.URI(), b.URI()); r != 0 {
+ return r
+ }
+ if r := comparePoint(a.v.Start, b.v.Start); r != 0 {
+ return r
+ }
+ return comparePoint(a.v.End, b.v.End)
+}
+
+func ComparePoint(a, b Point) int {
+ return comparePoint(a.v, b.v)
+}
+
+func comparePoint(a, b point) int {
+ if !a.hasPosition() {
+ if a.Offset < b.Offset {
+ return -1
+ }
+ if a.Offset > b.Offset {
+ return 1
+ }
+ return 0
+ }
+ if a.Line < b.Line {
+ return -1
+ }
+ if a.Line > b.Line {
+ return 1
+ }
+ if a.Column < b.Column {
+ return -1
+ }
+ if a.Column > b.Column {
+ return 1
+ }
+ return 0
+}
+
+func (s Span) HasPosition() bool { return s.v.Start.hasPosition() }
+func (s Span) HasOffset() bool { return s.v.Start.hasOffset() }
+func (s Span) IsValid() bool { return s.v.Start.isValid() }
+func (s Span) IsPoint() bool { return s.v.Start == s.v.End }
+func (s Span) URI() URI { return s.v.URI }
+func (s Span) Start() Point { return Point{s.v.Start} }
+func (s Span) End() Point { return Point{s.v.End} }
+func (s *Span) MarshalJSON() ([]byte, error) { return json.Marshal(&s.v) }
+func (s *Span) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, &s.v) }
+
+func (p Point) HasPosition() bool { return p.v.hasPosition() }
+func (p Point) HasOffset() bool { return p.v.hasOffset() }
+func (p Point) IsValid() bool { return p.v.isValid() }
+func (p *Point) MarshalJSON() ([]byte, error) { return json.Marshal(&p.v) }
+func (p *Point) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, &p.v) }
+func (p Point) Line() int {
+ if !p.v.hasPosition() {
+ panic(fmt.Errorf("position not set in %v", p.v))
+ }
+ return p.v.Line
+}
+func (p Point) Column() int {
+ if !p.v.hasPosition() {
+ panic(fmt.Errorf("position not set in %v", p.v))
+ }
+ return p.v.Column
+}
+func (p Point) Offset() int {
+ if !p.v.hasOffset() {
+ panic(fmt.Errorf("offset not set in %v", p.v))
+ }
+ return p.v.Offset
+}
+
+func (p point) hasPosition() bool { return p.Line > 0 }
+func (p point) hasOffset() bool { return p.Offset >= 0 }
+func (p point) isValid() bool { return p.hasPosition() || p.hasOffset() }
+func (p point) isZero() bool {
+ return (p.Line == 1 && p.Column == 1) || (!p.hasPosition() && p.Offset == 0)
+}
+
+func (s *span) clean() {
+ //this presumes the points are already clean
+ if !s.End.isValid() || (s.End == point{}) {
+ s.End = s.Start
+ }
+}
+
+func (p *point) clean() {
+ if p.Line < 0 {
+ p.Line = 0
+ }
+ if p.Column <= 0 {
+ if p.Line > 0 {
+ p.Column = 1
+ } else {
+ p.Column = 0
+ }
+ }
+ if p.Offset == 0 && (p.Line > 1 || p.Column > 1) {
+ p.Offset = -1
+ }
+}
+
+// Format implements fmt.Formatter to print the Location in a standard form.
+// The format produced is one that can be read back in using Parse.
+func (s Span) Format(f fmt.State, c rune) {
+ fullForm := f.Flag('+')
+ preferOffset := f.Flag('#')
+ // we should always have a uri, simplify if it is file format
+ //TODO: make sure the end of the uri is unambiguous
+ uri := string(s.v.URI)
+ if c == 'f' {
+ uri = path.Base(uri)
+ } else if !fullForm {
+ uri = s.v.URI.Filename()
+ }
+ fmt.Fprint(f, uri)
+ if !s.IsValid() || (!fullForm && s.v.Start.isZero() && s.v.End.isZero()) {
+ return
+ }
+ // see which bits of start to write
+ printOffset := s.HasOffset() && (fullForm || preferOffset || !s.HasPosition())
+ printLine := s.HasPosition() && (fullForm || !printOffset)
+ printColumn := printLine && (fullForm || (s.v.Start.Column > 1 || s.v.End.Column > 1))
+ fmt.Fprint(f, ":")
+ if printLine {
+ fmt.Fprintf(f, "%d", s.v.Start.Line)
+ }
+ if printColumn {
+ fmt.Fprintf(f, ":%d", s.v.Start.Column)
+ }
+ if printOffset {
+ fmt.Fprintf(f, "#%d", s.v.Start.Offset)
+ }
+ // start is written, do we need end?
+ if s.IsPoint() {
+ return
+ }
+ // we don't print the line if it did not change
+ printLine = fullForm || (printLine && s.v.End.Line > s.v.Start.Line)
+ fmt.Fprint(f, "-")
+ if printLine {
+ fmt.Fprintf(f, "%d", s.v.End.Line)
+ }
+ if printColumn {
+ if printLine {
+ fmt.Fprint(f, ":")
+ }
+ fmt.Fprintf(f, "%d", s.v.End.Column)
+ }
+ if printOffset {
+ fmt.Fprintf(f, "#%d", s.v.End.Offset)
+ }
+}
+
+func (s Span) WithPosition(c Converter) (Span, error) {
+ if err := s.update(c, true, false); err != nil {
+ return Span{}, err
+ }
+ return s, nil
+}
+
+func (s Span) WithOffset(c Converter) (Span, error) {
+ if err := s.update(c, false, true); err != nil {
+ return Span{}, err
+ }
+ return s, nil
+}
+
+func (s Span) WithAll(c Converter) (Span, error) {
+ if err := s.update(c, true, true); err != nil {
+ return Span{}, err
+ }
+ return s, nil
+}
+
+func (s *Span) update(c Converter, withPos, withOffset bool) error {
+ if !s.IsValid() {
+ return fmt.Errorf("cannot add information to an invalid span")
+ }
+ if withPos && !s.HasPosition() {
+ if err := s.v.Start.updatePosition(c); err != nil {
+ return err
+ }
+ if s.v.End.Offset == s.v.Start.Offset {
+ s.v.End = s.v.Start
+ } else if err := s.v.End.updatePosition(c); err != nil {
+ return err
+ }
+ }
+ if withOffset && (!s.HasOffset() || (s.v.End.hasPosition() && !s.v.End.hasOffset())) {
+ if err := s.v.Start.updateOffset(c); err != nil {
+ return err
+ }
+ if s.v.End.Line == s.v.Start.Line && s.v.End.Column == s.v.Start.Column {
+ s.v.End.Offset = s.v.Start.Offset
+ } else if err := s.v.End.updateOffset(c); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (p *point) updatePosition(c Converter) error {
+ line, col, err := c.ToPosition(p.Offset)
+ if err != nil {
+ return err
+ }
+ p.Line = line
+ p.Column = col
+ return nil
+}
+
+func (p *point) updateOffset(c Converter) error {
+ offset, err := c.ToOffset(p.Line, p.Column)
+ if err != nil {
+ return err
+ }
+ p.Offset = offset
+ return nil
+}
diff --git a/utils/vscode/src/lsp/span/token.go b/utils/vscode/src/lsp/span/token.go
new file mode 100644
index 0000000..f5a3870
--- /dev/null
+++ b/utils/vscode/src/lsp/span/token.go
@@ -0,0 +1,161 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+package span
+
+import (
+ "fmt"
+ "go/token"
+)
+
+// Range represents a source code range in token.Pos form.
+// It also carries the FileSet that produced the positions, so that it is
+// self contained.
+type Range struct {
+ FileSet *token.FileSet
+ Start token.Pos
+ End token.Pos
+}
+
+// TokenConverter is a Converter backed by a token file set and file.
+// It uses the file set methods to work out the conversions, which
+// makes it fast and does not require the file contents.
+type TokenConverter struct {
+ fset *token.FileSet
+ file *token.File
+}
+
+// NewRange creates a new Range from a FileSet and two positions.
+// To represent a point pass a 0 as the end pos.
+func NewRange(fset *token.FileSet, start, end token.Pos) Range {
+ return Range{
+ FileSet: fset,
+ Start: start,
+ End: end,
+ }
+}
+
+// NewTokenConverter returns an implementation of Converter backed by a
+// token.File.
+func NewTokenConverter(fset *token.FileSet, f *token.File) *TokenConverter {
+ return &TokenConverter{fset: fset, file: f}
+}
+
+// NewContentConverter returns an implementation of Converter for the
+// given file content.
+func NewContentConverter(filename string, content []byte) *TokenConverter {
+ fset := token.NewFileSet()
+ f := fset.AddFile(filename, -1, len(content))
+ f.SetLinesForContent(content)
+ return &TokenConverter{fset: fset, file: f}
+}
+
+// IsPoint returns true if the range represents a single point.
+func (r Range) IsPoint() bool {
+ return r.Start == r.End
+}
+
+// Span converts a Range to a Span that represents the Range.
+// It will fill in all the members of the Span, calculating the line and column
+// information.
+func (r Range) Span() (Span, error) {
+ f := r.FileSet.File(r.Start)
+ if f == nil {
+ return Span{}, fmt.Errorf("file not found in FileSet")
+ }
+ s := Span{v: span{URI: FileURI(f.Name())}}
+ var err error
+ s.v.Start.Offset, err = offset(f, r.Start)
+ if err != nil {
+ return Span{}, err
+ }
+ if r.End.IsValid() {
+ s.v.End.Offset, err = offset(f, r.End)
+ if err != nil {
+ return Span{}, err
+ }
+ }
+ s.v.Start.clean()
+ s.v.End.clean()
+ s.v.clean()
+ converter := NewTokenConverter(r.FileSet, f)
+ return s.WithPosition(converter)
+}
+
+// offset is a copy of the Offset function in go/token, but with the adjustment
+// that it does not panic on invalid positions.
+func offset(f *token.File, pos token.Pos) (int, error) {
+ if int(pos) < f.Base() || int(pos) > f.Base()+f.Size() {
+ return 0, fmt.Errorf("invalid pos")
+ }
+ return int(pos) - f.Base(), nil
+}
+
+// Range converts a Span to a Range that represents the Span for the supplied
+// File.
+func (s Span) Range(converter *TokenConverter) (Range, error) {
+ s, err := s.WithOffset(converter)
+ if err != nil {
+ return Range{}, err
+ }
+ // go/token will panic if the offset is larger than the file's size,
+ // so check here to avoid panicking.
+ if s.Start().Offset() > converter.file.Size() {
+ return Range{}, fmt.Errorf("start offset %v is past the end of the file %v", s.Start(), converter.file.Size())
+ }
+ if s.End().Offset() > converter.file.Size() {
+ return Range{}, fmt.Errorf("end offset %v is past the end of the file %v", s.End(), converter.file.Size())
+ }
+ return Range{
+ FileSet: converter.fset,
+ Start: converter.file.Pos(s.Start().Offset()),
+ End: converter.file.Pos(s.End().Offset()),
+ }, nil
+}
+
+func (l *TokenConverter) ToPosition(offset int) (int, int, error) {
+ if offset > l.file.Size() {
+ return 0, 0, fmt.Errorf("offset %v is past the end of the file %v", offset, l.file.Size())
+ }
+ pos := l.file.Pos(offset)
+ p := l.fset.Position(pos)
+ if offset == l.file.Size() {
+ return p.Line + 1, 1, nil
+ }
+ return p.Line, p.Column, nil
+}
+
+func (l *TokenConverter) ToOffset(line, col int) (int, error) {
+ if line < 0 {
+ return -1, fmt.Errorf("line is not valid")
+ }
+ lineMax := l.file.LineCount() + 1
+ if line > lineMax {
+ return -1, fmt.Errorf("line is beyond end of file %v", lineMax)
+ } else if line == lineMax {
+ if col > 1 {
+ return -1, fmt.Errorf("column is beyond end of file")
+ }
+ // at the end of the file, allowing for a trailing eol
+ return l.file.Size(), nil
+ }
+ pos := lineStart(l.file, line)
+ if !pos.IsValid() {
+ return -1, fmt.Errorf("line is not in file")
+ }
+ // we assume that column is in bytes here, and that the first byte of a
+ // line is at column 1
+ pos += token.Pos(col - 1)
+ return offset(l.file, pos)
+}
diff --git a/utils/vscode/src/lsp/span/token111.go b/utils/vscode/src/lsp/span/token111.go
new file mode 100644
index 0000000..768419a
--- /dev/null
+++ b/utils/vscode/src/lsp/span/token111.go
@@ -0,0 +1,49 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+// +build !go1.12
+
+package span
+
+import (
+ "go/token"
+)
+
+// lineStart is the pre-Go 1.12 version of (*token.File).LineStart. For Go
+// versions <= 1.11, we borrow logic from the analysisutil package.
+// TODO(rstambler): Delete this file when we no longer support Go 1.11.
+func lineStart(f *token.File, line int) token.Pos {
+ // Use binary search to find the start offset of this line.
+
+ min := 0 // inclusive
+ max := f.Size() // exclusive
+ for {
+ offset := (min + max) / 2
+ pos := f.Pos(offset)
+ posn := f.Position(pos)
+ if posn.Line == line {
+ return pos - (token.Pos(posn.Column) - 1)
+ }
+
+ if min+1 >= max {
+ return token.NoPos
+ }
+
+ if posn.Line < line {
+ min = offset
+ } else {
+ max = offset
+ }
+ }
+}
diff --git a/utils/vscode/src/lsp/span/token112.go b/utils/vscode/src/lsp/span/token112.go
new file mode 100644
index 0000000..abff500
--- /dev/null
+++ b/utils/vscode/src/lsp/span/token112.go
@@ -0,0 +1,26 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+// +build go1.12
+
+package span
+
+import (
+ "go/token"
+)
+
+// TODO(rstambler): Delete this file when we no longer support Go 1.11.
+func lineStart(f *token.File, line int) token.Pos {
+ return f.LineStart(line)
+}
diff --git a/utils/vscode/src/lsp/span/uri.go b/utils/vscode/src/lsp/span/uri.go
new file mode 100644
index 0000000..525518b
--- /dev/null
+++ b/utils/vscode/src/lsp/span/uri.go
@@ -0,0 +1,162 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+package span
+
+import (
+ "fmt"
+ "net/url"
+ "os"
+ "path"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "unicode"
+)
+
+const fileScheme = "file"
+
+// URI represents the full URI for a file.
+type URI string
+
+// Filename returns the file path for the given URI.
+// It is an error to call this on a URI that is not a valid filename.
+func (uri URI) Filename() string {
+ filename, err := filename(uri)
+ if err != nil {
+ panic(err)
+ }
+ return filepath.FromSlash(filename)
+}
+
+func filename(uri URI) (string, error) {
+ if uri == "" {
+ return "", nil
+ }
+ u, err := url.ParseRequestURI(string(uri))
+ if err != nil {
+ return "", err
+ }
+ if u.Scheme != fileScheme {
+ return "", fmt.Errorf("only file URIs are supported, got %q from %q", u.Scheme, uri)
+ }
+ if isWindowsDriveURI(u.Path) {
+ u.Path = u.Path[1:]
+ }
+ return u.Path, nil
+}
+
+// NewURI returns a span URI for the string.
+// It will attempt to detect if the string is a file path or uri.
+func NewURI(s string) URI {
+ if u, err := url.PathUnescape(s); err == nil {
+ s = u
+ }
+ if strings.HasPrefix(s, fileScheme+"://") {
+ return URI(s)
+ }
+ return FileURI(s)
+}
+
+func CompareURI(a, b URI) int {
+ if equalURI(a, b) {
+ return 0
+ }
+ if a < b {
+ return -1
+ }
+ return 1
+}
+
+func equalURI(a, b URI) bool {
+ if a == b {
+ return true
+ }
+ // If we have the same URI basename, we may still have the same file URIs.
+ if !strings.EqualFold(path.Base(string(a)), path.Base(string(b))) {
+ return false
+ }
+ fa, err := filename(a)
+ if err != nil {
+ return false
+ }
+ fb, err := filename(b)
+ if err != nil {
+ return false
+ }
+ // Stat the files to check if they are equal.
+ infoa, err := os.Stat(filepath.FromSlash(fa))
+ if err != nil {
+ return false
+ }
+ infob, err := os.Stat(filepath.FromSlash(fb))
+ if err != nil {
+ return false
+ }
+ return os.SameFile(infoa, infob)
+}
+
+// FileURI returns a span URI for the supplied file path.
+// It will always have the file scheme.
+func FileURI(path string) URI {
+ if path == "" {
+ return ""
+ }
+ // Handle standard library paths that contain the literal "$GOROOT".
+ // TODO(rstambler): The go/packages API should allow one to determine a user's $GOROOT.
+ const prefix = "$GOROOT"
+ if len(path) >= len(prefix) && strings.EqualFold(prefix, path[:len(prefix)]) {
+ suffix := path[len(prefix):]
+ path = runtime.GOROOT() + suffix
+ }
+ if !isWindowsDrivePath(path) {
+ if abs, err := filepath.Abs(path); err == nil {
+ path = abs
+ }
+ }
+ // Check the file path again, in case it became absolute.
+ if isWindowsDrivePath(path) {
+ path = "/" + path
+ }
+ path = filepath.ToSlash(path)
+ u := url.URL{
+ Scheme: fileScheme,
+ Path: path,
+ }
+ uri := u.String()
+ if unescaped, err := url.PathUnescape(uri); err == nil {
+ uri = unescaped
+ }
+ return URI(uri)
+}
+
+// isWindowsDrivePath returns true if the file path is of the form used by
+// Windows. We check if the path begins with a drive letter, followed by a ":".
+func isWindowsDrivePath(path string) bool {
+ if len(path) < 4 {
+ return false
+ }
+ return unicode.IsLetter(rune(path[0])) && path[1] == ':'
+}
+
+// isWindowsDriveURI returns true if the file URI is of the format used by
+// Windows URIs. The url.Parse package does not specially handle Windows paths
+// (see https://golang.org/issue/6027). We check if the URI path has
+// a drive prefix (e.g. "/C:"). If so, we trim the leading "/".
+func isWindowsDriveURI(uri string) bool {
+ if len(uri) < 4 {
+ return false
+ }
+ return uri[0] == '/' && unicode.IsLetter(rune(uri[1])) && uri[2] == ':'
+}
diff --git a/utils/vscode/src/lsp/span/utf16.go b/utils/vscode/src/lsp/span/utf16.go
new file mode 100644
index 0000000..6821851
--- /dev/null
+++ b/utils/vscode/src/lsp/span/utf16.go
@@ -0,0 +1,104 @@
+// Copyright 2019 The Go Authors.
+//
+// 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.
+
+package span
+
+import (
+ "fmt"
+ "unicode/utf16"
+ "unicode/utf8"
+)
+
+// ToUTF16Column calculates the utf16 column expressed by the point given the
+// supplied file contents.
+// This is used to convert from the native (always in bytes) column
+// representation and the utf16 counts used by some editors.
+func ToUTF16Column(p Point, content []byte) (int, error) {
+ if content == nil {
+ return -1, fmt.Errorf("ToUTF16Column: missing content")
+ }
+ if !p.HasPosition() {
+ return -1, fmt.Errorf("ToUTF16Column: point is missing position")
+ }
+ if !p.HasOffset() {
+ return -1, fmt.Errorf("ToUTF16Column: point is missing offset")
+ }
+ offset := p.Offset() // 0-based
+ colZero := p.Column() - 1 // 0-based
+ if colZero == 0 {
+ // 0-based column 0, so it must be chr 1
+ return 1, nil
+ } else if colZero < 0 {
+ return -1, fmt.Errorf("ToUTF16Column: column is invalid (%v)", colZero)
+ }
+ // work out the offset at the start of the line using the column
+ lineOffset := offset - colZero
+ if lineOffset < 0 || offset > len(content) {
+ return -1, fmt.Errorf("ToUTF16Column: offsets %v-%v outside file contents (%v)", lineOffset, offset, len(content))
+ }
+ // Use the offset to pick out the line start.
+ // This cannot panic: offset > len(content) and lineOffset < offset.
+ start := content[lineOffset:]
+
+ // Now, truncate down to the supplied column.
+ start = start[:colZero]
+
+ // and count the number of utf16 characters
+ // in theory we could do this by hand more efficiently...
+ return len(utf16.Encode([]rune(string(start)))) + 1, nil
+}
+
+// FromUTF16Column advances the point by the utf16 character offset given the
+// supplied line contents.
+// This is used to convert from the utf16 counts used by some editors to the
+// native (always in bytes) column representation.
+func FromUTF16Column(p Point, chr int, content []byte) (Point, error) {
+ if !p.HasOffset() {
+ return Point{}, fmt.Errorf("FromUTF16Column: point is missing offset")
+ }
+ // if chr is 1 then no adjustment needed
+ if chr <= 1 {
+ return p, nil
+ }
+ if p.Offset() >= len(content) {
+ return p, fmt.Errorf("FromUTF16Column: offset (%v) greater than length of content (%v)", p.Offset(), len(content))
+ }
+ remains := content[p.Offset():]
+ // scan forward the specified number of characters
+ for count := 1; count < chr; count++ {
+ if len(remains) <= 0 {
+ return Point{}, fmt.Errorf("FromUTF16Column: chr goes beyond the content")
+ }
+ r, w := utf8.DecodeRune(remains)
+ if r == '\n' {
+ // Per the LSP spec:
+ //
+ // > If the character value is greater than the line length it
+ // > defaults back to the line length.
+ break
+ }
+ remains = remains[w:]
+ if r >= 0x10000 {
+ // a two point rune
+ count++
+ // if we finished in a two point rune, do not advance past the first
+ if count >= chr {
+ break
+ }
+ }
+ p.v.Column += w
+ p.v.Offset += w
+ }
+ return p, nil
+}
diff --git a/utils/vscode/src/parser/parser.go b/utils/vscode/src/parser/parser.go
new file mode 100644
index 0000000..64ba462
--- /dev/null
+++ b/utils/vscode/src/parser/parser.go
@@ -0,0 +1,763 @@
+// 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.
+
+// Package parser implements a SPIR-V assembly parser.
+package parser
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "../schema"
+)
+
+// Type is an enumerator of token types.
+type Type int
+
+// Type enumerators
+const (
+ Ident Type = iota // Foo
+ PIdent // %32, %foo
+ Integer
+ Float
+ String
+ Operator
+ Comment
+ Newline
+)
+
+func (t Type) String() string {
+ switch t {
+ case Ident:
+ return "Ident"
+ case PIdent:
+ return "PIdent"
+ case Integer:
+ return "Integer"
+ case Float:
+ return "Float"
+ case String:
+ return "String"
+ case Operator:
+ return "Operator"
+ case Comment:
+ return "Comment"
+ default:
+ return "<unknown>"
+ }
+}
+
+// Token represents a single lexed token.
+type Token struct {
+ Type Type
+ Range Range
+}
+
+func (t Token) String() string { return fmt.Sprintf("{%v %v}", t.Type, t.Range) }
+
+// Text returns the tokens text from the source.
+func (t Token) Text(lines []string) string { return t.Range.Text(lines) }
+
+// Range represents an interval in a text file.
+type Range struct {
+ Start Position
+ End Position
+}
+
+func (r Range) String() string { return fmt.Sprintf("[%v %v]", r.Start, r.End) }
+
+// Text returns the text for the given Range in the provided lines.
+func (r Range) Text(lines []string) string {
+ sl, sc := r.Start.Line-1, r.Start.Column-1
+ if sl < 0 || sc < 0 || sl > len(lines) || sc > len(lines[sl]) {
+ return fmt.Sprintf("<invalid start position %v>", r.Start)
+ }
+ el, ec := r.End.Line-1, r.End.Column-1
+ if el < 0 || ec < 0 || el > len(lines) || ec > len(lines[sl]) {
+ return fmt.Sprintf("<invalid end position %v>", r.End)
+ }
+
+ sb := strings.Builder{}
+ if sl != el {
+ sb.WriteString(lines[sl][sc:])
+ for l := sl + 1; l < el; l++ {
+ sb.WriteString(lines[l])
+ }
+ sb.WriteString(lines[el][:ec])
+ } else {
+ sb.WriteString(lines[sl][sc:ec])
+ }
+ return sb.String()
+}
+
+// Contains returns true if p is in r.
+func (r Range) Contains(p Position) bool {
+ return !(p.LessThan(r.Start) || p.GreaterThan(r.End))
+}
+
+func (r *Range) grow(o Range) {
+ if !r.Start.IsValid() || o.Start.LessThan(r.Start) {
+ r.Start = o.Start
+ }
+ if !r.End.IsValid() || o.End.GreaterThan(r.End) {
+ r.End = o.End
+ }
+}
+
+// Position holds a line and column position in a text file.
+type Position struct {
+ Line, Column int
+}
+
+func (p Position) String() string { return fmt.Sprintf("%v:%v", p.Line, p.Column) }
+
+// IsValid returns true if the position has a line and column greater than 1.
+func (p Position) IsValid() bool { return p.Line > 0 && p.Column > 0 }
+
+// LessThan returns true iff o is before p.
+func (p Position) LessThan(o Position) bool {
+ switch {
+ case !p.IsValid() || !o.IsValid():
+ return false
+ case p.Line < o.Line:
+ return true
+ case p.Line > o.Line:
+ return false
+ case p.Column < o.Column:
+ return true
+ default:
+ return false
+ }
+}
+
+// GreaterThan returns true iff o is greater than p.
+func (p Position) GreaterThan(o Position) bool {
+ switch {
+ case !p.IsValid() || !o.IsValid():
+ return false
+ case p.Line > o.Line:
+ return true
+ case p.Line < o.Line:
+ return false
+ case p.Column > o.Column:
+ return true
+ default:
+ return false
+ }
+}
+
+type lexer struct {
+ source string
+ lexerState
+ diags []Diagnostic
+ e error
+}
+
+type lexerState struct {
+ offset int // byte offset in source
+ toks []*Token // all the lexed tokens
+ pos Position // current position
+}
+
+// err appends an fmt.Printf style error into l.diags for the given token.
+func (l *lexer) err(tok *Token, msg string, args ...interface{}) {
+ rng := Range{}
+ if tok != nil {
+ rng = tok.Range
+ }
+ l.diags = append(l.diags, Diagnostic{
+ Range: rng,
+ Severity: SeverityError,
+ Message: fmt.Sprintf(msg, args...),
+ })
+}
+
+// next returns the next rune, or io.EOF if the last rune has already been
+// consumed.
+func (l *lexer) next() rune {
+ if l.offset >= len(l.source) {
+ l.e = io.EOF
+ return 0
+ }
+ r, n := utf8.DecodeRuneInString(l.source[l.offset:])
+ l.offset += n
+ if n == 0 {
+ l.e = io.EOF
+ return 0
+ }
+ if r == '\n' {
+ l.pos.Line++
+ l.pos.Column = 1
+ } else {
+ l.pos.Column++
+ }
+ return r
+}
+
+// save returns the current lexerState.
+func (l *lexer) save() lexerState {
+ return l.lexerState
+}
+
+// restore restores the current lexer state with s.
+func (l *lexer) restore(s lexerState) {
+ l.lexerState = s
+}
+
+// pident processes the PIdent token at the current position.
+// The lexer *must* know the next token is a PIdent before calling.
+func (l *lexer) pident() {
+ tok := &Token{Type: PIdent, Range: Range{Start: l.pos, End: l.pos}}
+ if r := l.next(); r != '%' {
+ log.Fatalf("lexer expected '%%', got '%v'", r)
+ return
+ }
+ for l.e == nil {
+ s := l.save()
+ r := l.next()
+ if !isAlphaNumeric(r) && r != '_' {
+ l.restore(s)
+ break
+ }
+ }
+ tok.Range.End = l.pos
+ l.toks = append(l.toks, tok)
+}
+
+// numberOrIdent processes the Ident, Float or Integer token at the current
+// position.
+func (l *lexer) numberOrIdent() {
+ const Unknown Type = -1
+ tok := &Token{Type: Unknown, Range: Range{Start: l.pos, End: l.pos}}
+loop:
+ for l.e == nil {
+ s := l.save()
+ r := l.next()
+ switch {
+ case r == '-', r == '+', isNumeric(r):
+ continue
+ case isAlpha(r), r == '_':
+ switch tok.Type {
+ case Unknown:
+ tok.Type = Ident
+ case Float, Integer:
+ l.err(tok, "invalid number")
+ return
+ }
+ case r == '.':
+ switch tok.Type {
+ case Unknown:
+ tok.Type = Float
+ default:
+ l.restore(s)
+ break loop
+ }
+ default:
+ if tok.Type == Unknown {
+ tok.Type = Integer
+ }
+ l.restore(s)
+ break loop
+ }
+ }
+ tok.Range.End = l.pos
+ l.toks = append(l.toks, tok)
+}
+
+// string processes the String token at the current position.
+// The lexer *must* know the next token is a String before calling.
+func (l *lexer) string() {
+ tok := &Token{Type: String, Range: Range{Start: l.pos, End: l.pos}}
+ if r := l.next(); r != '"' {
+ log.Fatalf("lexer expected '\"', got '%v'", r)
+ return
+ }
+ escape := false
+ for l.e == nil {
+ switch l.next() {
+ case '"':
+ if !escape {
+ tok.Range.End = l.pos
+ l.toks = append(l.toks, tok)
+ return
+ }
+ case '\\':
+ escape = !escape
+ default:
+ escape = false
+ }
+ }
+}
+
+// operator processes the Operator token at the current position.
+// The lexer *must* know the next token is a Operator before calling.
+func (l *lexer) operator() {
+ tok := &Token{Type: Operator, Range: Range{Start: l.pos, End: l.pos}}
+ for l.e == nil {
+ switch l.next() {
+ case '=':
+ tok.Range.End = l.pos
+ l.toks = append(l.toks, tok)
+ return
+ }
+ }
+}
+
+// lineComment processes the Comment token at the current position.
+// The lexer *must* know the next token is a Comment before calling.
+func (l *lexer) lineComment() {
+ tok := &Token{Type: Comment, Range: Range{Start: l.pos, End: l.pos}}
+ if r := l.next(); r != ';' {
+ log.Fatalf("lexer expected ';', got '%v'", r)
+ return
+ }
+ for l.e == nil {
+ s := l.save()
+ switch l.next() {
+ case '\n':
+ l.restore(s)
+ tok.Range.End = l.pos
+ l.toks = append(l.toks, tok)
+ return
+ }
+ }
+}
+
+// newline processes the Newline token at the current position.
+// The lexer *must* know the next token is a Newline before calling.
+func (l *lexer) newline() {
+ tok := &Token{Type: Newline, Range: Range{Start: l.pos, End: l.pos}}
+ if r := l.next(); r != '\n' {
+ log.Fatalf("lexer expected '\n', got '%v'", r)
+ return
+ }
+ tok.Range.End = l.pos
+ l.toks = append(l.toks, tok)
+}
+
+// lex returns all the tokens and diagnostics after lexing source.
+func lex(source string) ([]*Token, []Diagnostic, error) {
+ l := lexer{source: source, lexerState: lexerState{pos: Position{1, 1}}}
+
+ lastPos := Position{}
+ for l.e == nil {
+ // Sanity check the parser is making progress
+ if l.pos == lastPos {
+ log.Panicf("Parsing stuck at %v", l.pos)
+ }
+ lastPos = l.pos
+
+ s := l.save()
+ r := l.next()
+ switch {
+ case r == '%':
+ l.restore(s)
+ l.pident()
+ case r == '+' || r == '-' || r == '_' || isAlphaNumeric(r):
+ l.restore(s)
+ l.numberOrIdent()
+ case r == '"':
+ l.restore(s)
+ l.string()
+ case r == '=':
+ l.restore(s)
+ l.operator()
+ case r == ';':
+ l.restore(s)
+ l.lineComment()
+ case r == '\n':
+ l.restore(s)
+ l.newline()
+ }
+ }
+ if l.e != nil && l.e != io.EOF {
+ return nil, nil, l.e
+ }
+ return l.toks, l.diags, nil
+}
+
+func isNumeric(r rune) bool { return unicode.IsDigit(r) }
+func isAlpha(r rune) bool { return unicode.IsLetter(r) }
+func isAlphaNumeric(r rune) bool { return isAlpha(r) || isNumeric(r) }
+
+type parser struct {
+ lines []string // all source lines
+ toks []*Token // all tokens
+ diags []Diagnostic // parser emitted diagnostics
+ idents map[string]*Identifier // identifiers by name
+ mappings map[*Token]interface{} // tokens to semantic map
+ insts []*Instruction // all instructions
+}
+
+func (p *parser) parse() error {
+ for i := 0; i < len(p.toks); {
+ if p.newline(i) || p.comment(i) {
+ i++
+ continue
+ }
+ if n := p.instruction(i); n > 0 {
+ i += n
+ } else {
+ p.unexpected(i)
+ i++
+ }
+ }
+ return nil
+}
+
+// instruction parses the instruction starting at the i'th token.
+func (p *parser) instruction(i int) (n int) {
+ inst := &Instruction{}
+
+ switch {
+ case p.opcode(i) != nil:
+ inst.Opcode = p.opcode(i)
+ inst.Tokens = []*Token{p.tok(i)}
+ p.mappings[p.tok(i)] = inst
+ n++
+ case p.opcode(i+2) != nil: // try '%id' '='
+ inst.Result, inst.Opcode = p.pident(i), p.opcode(i+2)
+ if inst.Result == nil || p.operator(i+1) != "=" {
+ return 0
+ }
+ n += 3
+ inst.Tokens = []*Token{p.tok(i), p.tok(i + 1), p.tok(i + 2)}
+ p.mappings[p.tok(i+2)] = inst
+ default:
+ return
+ }
+
+ expectsResult := len(inst.Opcode.Operands) > 0 && IsResult(inst.Opcode.Operands[0].Kind)
+ operands := inst.Opcode.Operands
+ switch {
+ case inst.Result != nil && !expectsResult:
+ p.err(inst.Result, "'%s' does not have a result", inst.Opcode.Opname)
+ return
+ case inst.Result == nil && expectsResult:
+ p.err(p.tok(i), "'%s' expects a result", inst.Opcode.Opname)
+ return
+ case inst.Result != nil && expectsResult:
+ // Check the result is of the correct type
+ o := inst.Opcode.Operands[0]
+ p.operand(o.Name, o.Kind, i, false)
+ operands = operands[1:]
+ p.addIdentDef(inst.Result.Text(p.lines), inst, p.tok(i))
+ }
+
+ for _, o := range operands {
+ if p.newline(i + n) {
+ break
+ }
+
+ switch o.Quantifier {
+ case schema.Once:
+ if op, c := p.operand(o.Name, o.Kind, i+n, false); op != nil {
+ inst.Tokens = append(inst.Tokens, op.Tokens...)
+ n += c
+ }
+ case schema.ZeroOrOnce:
+ if op, c := p.operand(o.Name, o.Kind, i+n, true); op != nil {
+ inst.Tokens = append(inst.Tokens, op.Tokens...)
+ n += c
+ }
+ case schema.ZeroOrMany:
+ for !p.newline(i + n) {
+ if op, c := p.operand(o.Name, o.Kind, i+n, true); op != nil {
+ inst.Tokens = append(inst.Tokens, op.Tokens...)
+ n += c
+ } else {
+ break
+ }
+ }
+ }
+ }
+
+ for _, t := range inst.Tokens {
+ inst.Range.grow(t.Range)
+ }
+
+ p.insts = append(p.insts, inst)
+ return
+}
+
+// operand parses the operand with the name n, kind k, starting at the i'th
+// token.
+func (p *parser) operand(n string, k *schema.OperandKind, i int, optional bool) (*Operand, int) {
+ tok := p.tok(i)
+ if tok == nil {
+ return nil, 0
+ }
+
+ op := &Operand{
+ Name: n,
+ Kind: k,
+ Tokens: []*Token{tok},
+ }
+ p.mappings[tok] = op
+
+ switch k.Category {
+ case schema.OperandCategoryBitEnum, schema.OperandCategoryValueEnum:
+ s := tok.Text(p.lines)
+ for _, e := range k.Enumerants {
+ if e.Enumerant == s {
+ n := 1
+ for _, param := range e.Parameters {
+ p, c := p.operand(param.Name, param.Kind, i+n, false)
+ if p != nil {
+ op.Tokens = append(op.Tokens, p.Tokens...)
+ op.Parameters = append(op.Parameters, p)
+ }
+ n += c
+ }
+ return op, n
+ }
+ }
+ if !optional {
+ p.err(p.tok(i), "invalid operand value '%s'", s)
+ }
+ return nil, 0
+
+ case schema.OperandCategoryID:
+ id := p.pident(i)
+ if id != nil {
+ p.addIdentRef(p.tok(i))
+ return op, 1
+ }
+ if !optional {
+ p.err(p.tok(i), "operand requires id, got '%s'", tok.Text(p.lines))
+ }
+ return nil, 0
+
+ case schema.OperandCategoryLiteral:
+ switch tok.Type {
+ case String, Integer, Float:
+ return op, 1
+ }
+ if !optional {
+ p.err(p.tok(i), "operand requires literal, got '%s'", tok.Text(p.lines))
+ }
+ return nil, 0
+
+ case schema.OperandCategoryComposite:
+ n := 1
+ for _, b := range k.Bases {
+ o, c := p.operand(b.Kind, b, i+n, optional)
+ if o != nil {
+ op.Tokens = append(op.Tokens, o.Tokens...)
+ }
+ n += c
+ }
+ return op, n
+
+ default:
+ p.err(p.tok(i), "OperandKind '%s' has unexpected category '%s'", k.Kind, k.Category)
+ return nil, 0
+ }
+}
+
+// tok returns the i'th token, or nil if i is out of bounds.
+func (p *parser) tok(i int) *Token {
+ if i < 0 || i >= len(p.toks) {
+ return nil
+ }
+ return p.toks[i]
+}
+
+// opcode returns the schema.Opcode for the i'th token, or nil if the i'th token
+// does not represent an opcode.
+func (p *parser) opcode(i int) *schema.Opcode {
+ if tok := p.ident(i); tok != nil {
+ name := tok.Text(p.lines)
+ if inst, found := schema.Opcodes[name]; found {
+ return inst
+ }
+ }
+ return nil
+}
+
+// operator returns the operator for the i'th token, or and empty string if the
+// i'th token is not an operator.
+func (p *parser) operator(i int) string {
+ if tok := p.tok(i); tok != nil && tok.Type == Operator {
+ return tok.Text(p.lines)
+ }
+ return ""
+}
+
+// ident returns the i'th token if it is an Ident, otherwise nil.
+func (p *parser) ident(i int) *Token {
+ if tok := p.tok(i); tok != nil && tok.Type == Ident {
+ return tok
+ }
+ return nil
+}
+
+// pident returns the i'th token if it is an PIdent, otherwise nil.
+func (p *parser) pident(i int) *Token {
+ if tok := p.tok(i); tok != nil && tok.Type == PIdent {
+ return tok
+ }
+ return nil
+}
+
+// comment returns true if the i'th token is a Comment, otherwise false.
+func (p *parser) comment(i int) bool {
+ if tok := p.tok(i); tok != nil && tok.Type == Comment {
+ return true
+ }
+ return false
+}
+
+// newline returns true if the i'th token is a Newline, otherwise false.
+func (p *parser) newline(i int) bool {
+ if tok := p.tok(i); tok != nil && tok.Type == Newline {
+ return true
+ }
+ return false
+}
+
+// unexpected emits an 'unexpected token error' for the i'th token.
+func (p *parser) unexpected(i int) {
+ p.err(p.toks[i], "syntax error: unexpected '%s'", p.toks[i].Text(p.lines))
+}
+
+// addIdentDef records the token definition for the instruction inst with the
+// given id.
+func (p *parser) addIdentDef(id string, inst *Instruction, def *Token) {
+ i, existing := p.idents[id]
+ if !existing {
+ i = &Identifier{}
+ p.idents[id] = i
+ }
+ if i.Definition == nil {
+ i.Definition = inst
+ } else {
+ p.err(def, "id '%v' redeclared", id)
+ }
+}
+
+// addIdentRef adds a identifier reference for the token ref.
+func (p *parser) addIdentRef(ref *Token) {
+ id := ref.Text(p.lines)
+ i, existing := p.idents[id]
+ if !existing {
+ i = &Identifier{}
+ p.idents[id] = i
+ }
+ i.References = append(i.References, ref)
+}
+
+// err appends an fmt.Printf style error into l.diags for the given token.
+func (p *parser) err(tok *Token, msg string, args ...interface{}) {
+ rng := Range{}
+ if tok != nil {
+ rng = tok.Range
+ }
+ p.diags = append(p.diags, Diagnostic{
+ Range: rng,
+ Severity: SeverityError,
+ Message: fmt.Sprintf(msg, args...),
+ })
+}
+
+// Parse parses the SPIR-V assembly string source, returning the parse results.
+func Parse(source string) (Results, error) {
+ toks, diags, err := lex(source)
+ if err != nil {
+ return Results{}, err
+ }
+ lines := strings.SplitAfter(source, "\n")
+ p := parser{
+ lines: lines,
+ toks: toks,
+ idents: map[string]*Identifier{},
+ mappings: map[*Token]interface{}{},
+ }
+ if err := p.parse(); err != nil {
+ return Results{}, err
+ }
+ diags = append(diags, p.diags...)
+ return Results{
+ Lines: lines,
+ Tokens: toks,
+ Diagnostics: p.diags,
+ Identifiers: p.idents,
+ Mappings: p.mappings,
+ }, nil
+}
+
+// IsResult returns true if k is used to store the result of an instruction.
+func IsResult(k *schema.OperandKind) bool {
+ switch k {
+ case schema.OperandKindIdResult, schema.OperandKindIdResultType:
+ return true
+ default:
+ return false
+ }
+}
+
+// Results holds the output of Parse().
+type Results struct {
+ Lines []string
+ Tokens []*Token
+ Diagnostics []Diagnostic
+ Identifiers map[string]*Identifier // identifiers by name
+ Mappings map[*Token]interface{} // tokens to semantic map
+}
+
+// Instruction describes a single instruction instance
+type Instruction struct {
+ Tokens []*Token // all the tokens that make up the instruction
+ Result *Token // the token that represents the result of the instruction, or nil
+ Operands []*Operand // the operands of the instruction
+ Range Range // the textual range of the instruction
+ Opcode *schema.Opcode // the opcode for the instruction
+}
+
+// Operand describes a single operand instance
+type Operand struct {
+ Name string // name of the operand
+ Kind *schema.OperandKind // kind of the operand
+ Tokens []*Token // all the tokens that make up the operand
+ Parameters []*Operand // all the parameters for the operand
+}
+
+// Identifier describes a single, unique SPIR-V identifier (i.e. %32)
+type Identifier struct {
+ Definition *Instruction // where the identifier was defined
+ References []*Token // all the places the identifier was referenced
+}
+
+// Severity is an enumerator of diagnositc seeverities
+type Severity int
+
+// Severity levels
+const (
+ SeverityError Severity = iota
+ SeverityWarning
+ SeverityInformation
+ SeverityHint
+)
+
+// Diagnostic holds a single diagnostic message that was generated while
+// parsing.
+type Diagnostic struct {
+ Range Range
+ Severity Severity
+ Message string
+}
diff --git a/utils/vscode/src/schema/schema.go b/utils/vscode/src/schema/schema.go
new file mode 100755
index 0000000..c7e1ca4
--- /dev/null
+++ b/utils/vscode/src/schema/schema.go
@@ -0,0 +1,18118 @@
+// 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.
+
+// Generated by gen-grammar.go --template=../schema/schema.go.tmpl --out=../schema/schema.go
+// Do not modify this file directly.
+
+package schema
+
+// Opcode holds information about a specific SPIR-V opcode.
+type Opcode struct {
+ Opname string
+ Class string
+ Opcode int
+ Operands []Operand
+}
+
+// Operand contains information about a logical operand for an instruction.
+type Operand struct {
+ Kind *OperandKind
+ Name string
+ Quantifier Quantifier
+}
+
+// OperandKind contains information about a specific operand kind.
+type OperandKind struct {
+ Category OperandCategory
+ Kind string
+ Enumerants []Enumerant
+ Bases []*OperandKind
+}
+
+// Enumerant contains information about an enumerant in an enum.
+type Enumerant struct {
+ Enumerant string
+ Value interface{}
+ Capabilities []string
+ Parameters []Parameter
+ Version string
+}
+
+// Parameter contains information about a logical parameter for an enumerant.
+type Parameter struct {
+ Kind *OperandKind
+ Name string
+}
+
+// Quantifier indicates the number of times the quantified term may appear.
+type Quantifier string
+
+const (
+ // Once indicates the quantified term may appear exactly once.
+ Once Quantifier = ""
+
+ // ZeroOrOnce indicates the quantified term may appear zero or one
+ // time; an optional term.
+ ZeroOrOnce Quantifier = "?"
+
+ // ZeroOrMany indicates the quantified term may appear any number of
+ // times.
+ ZeroOrMany Quantifier = "*"
+)
+
+// OperandCategory is an enumerator that groups operand kinds.
+type OperandCategory string
+
+const (
+ // OperandCategoryBitEnum describes an operand kind where its value is a
+ // mask, which is formed by combining the bits specified as enumerants in an
+ // enum.
+ OperandCategoryBitEnum = "BitEnum"
+
+ // OperandCategoryValueEnum describes an operand kind where its value is an
+ // enumerant from an enum.
+ OperandCategoryValueEnum = "ValueEnum"
+
+ // OperandCategoryID describes and operand kind where its value is an <id>
+ // definition or reference.
+ OperandCategoryID = "Id"
+
+ // OperandCategoryLiteral describes and operand kind where its value is an
+ // literal number or string.
+ OperandCategoryLiteral = "Literal"
+
+ // OperandCategoryComposite describes and operand kind where its value is
+ // composed from operand values from the above categories.
+ OperandCategoryComposite = "Composite"
+)
+
+var (
+ // Opcodes is a map of opcode name to Opcode description.
+ Opcodes = map[string]*Opcode {
+ "OpNop": OpNop,
+ "OpUndef": OpUndef,
+ "OpSourceContinued": OpSourceContinued,
+ "OpSource": OpSource,
+ "OpSourceExtension": OpSourceExtension,
+ "OpName": OpName,
+ "OpMemberName": OpMemberName,
+ "OpString": OpString,
+ "OpLine": OpLine,
+ "OpExtension": OpExtension,
+ "OpExtInstImport": OpExtInstImport,
+ "OpExtInst": OpExtInst,
+ "OpMemoryModel": OpMemoryModel,
+ "OpEntryPoint": OpEntryPoint,
+ "OpExecutionMode": OpExecutionMode,
+ "OpCapability": OpCapability,
+ "OpTypeVoid": OpTypeVoid,
+ "OpTypeBool": OpTypeBool,
+ "OpTypeInt": OpTypeInt,
+ "OpTypeFloat": OpTypeFloat,
+ "OpTypeVector": OpTypeVector,
+ "OpTypeMatrix": OpTypeMatrix,
+ "OpTypeImage": OpTypeImage,
+ "OpTypeSampler": OpTypeSampler,
+ "OpTypeSampledImage": OpTypeSampledImage,
+ "OpTypeArray": OpTypeArray,
+ "OpTypeRuntimeArray": OpTypeRuntimeArray,
+ "OpTypeStruct": OpTypeStruct,
+ "OpTypeOpaque": OpTypeOpaque,
+ "OpTypePointer": OpTypePointer,
+ "OpTypeFunction": OpTypeFunction,
+ "OpTypeEvent": OpTypeEvent,
+ "OpTypeDeviceEvent": OpTypeDeviceEvent,
+ "OpTypeReserveId": OpTypeReserveId,
+ "OpTypeQueue": OpTypeQueue,
+ "OpTypePipe": OpTypePipe,
+ "OpTypeForwardPointer": OpTypeForwardPointer,
+ "OpConstantTrue": OpConstantTrue,
+ "OpConstantFalse": OpConstantFalse,
+ "OpConstant": OpConstant,
+ "OpConstantComposite": OpConstantComposite,
+ "OpConstantSampler": OpConstantSampler,
+ "OpConstantNull": OpConstantNull,
+ "OpSpecConstantTrue": OpSpecConstantTrue,
+ "OpSpecConstantFalse": OpSpecConstantFalse,
+ "OpSpecConstant": OpSpecConstant,
+ "OpSpecConstantComposite": OpSpecConstantComposite,
+ "OpSpecConstantOp": OpSpecConstantOp,
+ "OpFunction": OpFunction,
+ "OpFunctionParameter": OpFunctionParameter,
+ "OpFunctionEnd": OpFunctionEnd,
+ "OpFunctionCall": OpFunctionCall,
+ "OpVariable": OpVariable,
+ "OpImageTexelPointer": OpImageTexelPointer,
+ "OpLoad": OpLoad,
+ "OpStore": OpStore,
+ "OpCopyMemory": OpCopyMemory,
+ "OpCopyMemorySized": OpCopyMemorySized,
+ "OpAccessChain": OpAccessChain,
+ "OpInBoundsAccessChain": OpInBoundsAccessChain,
+ "OpPtrAccessChain": OpPtrAccessChain,
+ "OpArrayLength": OpArrayLength,
+ "OpGenericPtrMemSemantics": OpGenericPtrMemSemantics,
+ "OpInBoundsPtrAccessChain": OpInBoundsPtrAccessChain,
+ "OpDecorate": OpDecorate,
+ "OpMemberDecorate": OpMemberDecorate,
+ "OpDecorationGroup": OpDecorationGroup,
+ "OpGroupDecorate": OpGroupDecorate,
+ "OpGroupMemberDecorate": OpGroupMemberDecorate,
+ "OpVectorExtractDynamic": OpVectorExtractDynamic,
+ "OpVectorInsertDynamic": OpVectorInsertDynamic,
+ "OpVectorShuffle": OpVectorShuffle,
+ "OpCompositeConstruct": OpCompositeConstruct,
+ "OpCompositeExtract": OpCompositeExtract,
+ "OpCompositeInsert": OpCompositeInsert,
+ "OpCopyObject": OpCopyObject,
+ "OpTranspose": OpTranspose,
+ "OpSampledImage": OpSampledImage,
+ "OpImageSampleImplicitLod": OpImageSampleImplicitLod,
+ "OpImageSampleExplicitLod": OpImageSampleExplicitLod,
+ "OpImageSampleDrefImplicitLod": OpImageSampleDrefImplicitLod,
+ "OpImageSampleDrefExplicitLod": OpImageSampleDrefExplicitLod,
+ "OpImageSampleProjImplicitLod": OpImageSampleProjImplicitLod,
+ "OpImageSampleProjExplicitLod": OpImageSampleProjExplicitLod,
+ "OpImageSampleProjDrefImplicitLod": OpImageSampleProjDrefImplicitLod,
+ "OpImageSampleProjDrefExplicitLod": OpImageSampleProjDrefExplicitLod,
+ "OpImageFetch": OpImageFetch,
+ "OpImageGather": OpImageGather,
+ "OpImageDrefGather": OpImageDrefGather,
+ "OpImageRead": OpImageRead,
+ "OpImageWrite": OpImageWrite,
+ "OpImage": OpImage,
+ "OpImageQueryFormat": OpImageQueryFormat,
+ "OpImageQueryOrder": OpImageQueryOrder,
+ "OpImageQuerySizeLod": OpImageQuerySizeLod,
+ "OpImageQuerySize": OpImageQuerySize,
+ "OpImageQueryLod": OpImageQueryLod,
+ "OpImageQueryLevels": OpImageQueryLevels,
+ "OpImageQuerySamples": OpImageQuerySamples,
+ "OpConvertFToU": OpConvertFToU,
+ "OpConvertFToS": OpConvertFToS,
+ "OpConvertSToF": OpConvertSToF,
+ "OpConvertUToF": OpConvertUToF,
+ "OpUConvert": OpUConvert,
+ "OpSConvert": OpSConvert,
+ "OpFConvert": OpFConvert,
+ "OpQuantizeToF16": OpQuantizeToF16,
+ "OpConvertPtrToU": OpConvertPtrToU,
+ "OpSatConvertSToU": OpSatConvertSToU,
+ "OpSatConvertUToS": OpSatConvertUToS,
+ "OpConvertUToPtr": OpConvertUToPtr,
+ "OpPtrCastToGeneric": OpPtrCastToGeneric,
+ "OpGenericCastToPtr": OpGenericCastToPtr,
+ "OpGenericCastToPtrExplicit": OpGenericCastToPtrExplicit,
+ "OpBitcast": OpBitcast,
+ "OpSNegate": OpSNegate,
+ "OpFNegate": OpFNegate,
+ "OpIAdd": OpIAdd,
+ "OpFAdd": OpFAdd,
+ "OpISub": OpISub,
+ "OpFSub": OpFSub,
+ "OpIMul": OpIMul,
+ "OpFMul": OpFMul,
+ "OpUDiv": OpUDiv,
+ "OpSDiv": OpSDiv,
+ "OpFDiv": OpFDiv,
+ "OpUMod": OpUMod,
+ "OpSRem": OpSRem,
+ "OpSMod": OpSMod,
+ "OpFRem": OpFRem,
+ "OpFMod": OpFMod,
+ "OpVectorTimesScalar": OpVectorTimesScalar,
+ "OpMatrixTimesScalar": OpMatrixTimesScalar,
+ "OpVectorTimesMatrix": OpVectorTimesMatrix,
+ "OpMatrixTimesVector": OpMatrixTimesVector,
+ "OpMatrixTimesMatrix": OpMatrixTimesMatrix,
+ "OpOuterProduct": OpOuterProduct,
+ "OpDot": OpDot,
+ "OpIAddCarry": OpIAddCarry,
+ "OpISubBorrow": OpISubBorrow,
+ "OpUMulExtended": OpUMulExtended,
+ "OpSMulExtended": OpSMulExtended,
+ "OpAny": OpAny,
+ "OpAll": OpAll,
+ "OpIsNan": OpIsNan,
+ "OpIsInf": OpIsInf,
+ "OpIsFinite": OpIsFinite,
+ "OpIsNormal": OpIsNormal,
+ "OpSignBitSet": OpSignBitSet,
+ "OpLessOrGreater": OpLessOrGreater,
+ "OpOrdered": OpOrdered,
+ "OpUnordered": OpUnordered,
+ "OpLogicalEqual": OpLogicalEqual,
+ "OpLogicalNotEqual": OpLogicalNotEqual,
+ "OpLogicalOr": OpLogicalOr,
+ "OpLogicalAnd": OpLogicalAnd,
+ "OpLogicalNot": OpLogicalNot,
+ "OpSelect": OpSelect,
+ "OpIEqual": OpIEqual,
+ "OpINotEqual": OpINotEqual,
+ "OpUGreaterThan": OpUGreaterThan,
+ "OpSGreaterThan": OpSGreaterThan,
+ "OpUGreaterThanEqual": OpUGreaterThanEqual,
+ "OpSGreaterThanEqual": OpSGreaterThanEqual,
+ "OpULessThan": OpULessThan,
+ "OpSLessThan": OpSLessThan,
+ "OpULessThanEqual": OpULessThanEqual,
+ "OpSLessThanEqual": OpSLessThanEqual,
+ "OpFOrdEqual": OpFOrdEqual,
+ "OpFUnordEqual": OpFUnordEqual,
+ "OpFOrdNotEqual": OpFOrdNotEqual,
+ "OpFUnordNotEqual": OpFUnordNotEqual,
+ "OpFOrdLessThan": OpFOrdLessThan,
+ "OpFUnordLessThan": OpFUnordLessThan,
+ "OpFOrdGreaterThan": OpFOrdGreaterThan,
+ "OpFUnordGreaterThan": OpFUnordGreaterThan,
+ "OpFOrdLessThanEqual": OpFOrdLessThanEqual,
+ "OpFUnordLessThanEqual": OpFUnordLessThanEqual,
+ "OpFOrdGreaterThanEqual": OpFOrdGreaterThanEqual,
+ "OpFUnordGreaterThanEqual": OpFUnordGreaterThanEqual,
+ "OpShiftRightLogical": OpShiftRightLogical,
+ "OpShiftRightArithmetic": OpShiftRightArithmetic,
+ "OpShiftLeftLogical": OpShiftLeftLogical,
+ "OpBitwiseOr": OpBitwiseOr,
+ "OpBitwiseXor": OpBitwiseXor,
+ "OpBitwiseAnd": OpBitwiseAnd,
+ "OpNot": OpNot,
+ "OpBitFieldInsert": OpBitFieldInsert,
+ "OpBitFieldSExtract": OpBitFieldSExtract,
+ "OpBitFieldUExtract": OpBitFieldUExtract,
+ "OpBitReverse": OpBitReverse,
+ "OpBitCount": OpBitCount,
+ "OpDPdx": OpDPdx,
+ "OpDPdy": OpDPdy,
+ "OpFwidth": OpFwidth,
+ "OpDPdxFine": OpDPdxFine,
+ "OpDPdyFine": OpDPdyFine,
+ "OpFwidthFine": OpFwidthFine,
+ "OpDPdxCoarse": OpDPdxCoarse,
+ "OpDPdyCoarse": OpDPdyCoarse,
+ "OpFwidthCoarse": OpFwidthCoarse,
+ "OpEmitVertex": OpEmitVertex,
+ "OpEndPrimitive": OpEndPrimitive,
+ "OpEmitStreamVertex": OpEmitStreamVertex,
+ "OpEndStreamPrimitive": OpEndStreamPrimitive,
+ "OpControlBarrier": OpControlBarrier,
+ "OpMemoryBarrier": OpMemoryBarrier,
+ "OpAtomicLoad": OpAtomicLoad,
+ "OpAtomicStore": OpAtomicStore,
+ "OpAtomicExchange": OpAtomicExchange,
+ "OpAtomicCompareExchange": OpAtomicCompareExchange,
+ "OpAtomicCompareExchangeWeak": OpAtomicCompareExchangeWeak,
+ "OpAtomicIIncrement": OpAtomicIIncrement,
+ "OpAtomicIDecrement": OpAtomicIDecrement,
+ "OpAtomicIAdd": OpAtomicIAdd,
+ "OpAtomicISub": OpAtomicISub,
+ "OpAtomicSMin": OpAtomicSMin,
+ "OpAtomicUMin": OpAtomicUMin,
+ "OpAtomicSMax": OpAtomicSMax,
+ "OpAtomicUMax": OpAtomicUMax,
+ "OpAtomicAnd": OpAtomicAnd,
+ "OpAtomicOr": OpAtomicOr,
+ "OpAtomicXor": OpAtomicXor,
+ "OpPhi": OpPhi,
+ "OpLoopMerge": OpLoopMerge,
+ "OpSelectionMerge": OpSelectionMerge,
+ "OpLabel": OpLabel,
+ "OpBranch": OpBranch,
+ "OpBranchConditional": OpBranchConditional,
+ "OpSwitch": OpSwitch,
+ "OpKill": OpKill,
+ "OpReturn": OpReturn,
+ "OpReturnValue": OpReturnValue,
+ "OpUnreachable": OpUnreachable,
+ "OpLifetimeStart": OpLifetimeStart,
+ "OpLifetimeStop": OpLifetimeStop,
+ "OpGroupAsyncCopy": OpGroupAsyncCopy,
+ "OpGroupWaitEvents": OpGroupWaitEvents,
+ "OpGroupAll": OpGroupAll,
+ "OpGroupAny": OpGroupAny,
+ "OpGroupBroadcast": OpGroupBroadcast,
+ "OpGroupIAdd": OpGroupIAdd,
+ "OpGroupFAdd": OpGroupFAdd,
+ "OpGroupFMin": OpGroupFMin,
+ "OpGroupUMin": OpGroupUMin,
+ "OpGroupSMin": OpGroupSMin,
+ "OpGroupFMax": OpGroupFMax,
+ "OpGroupUMax": OpGroupUMax,
+ "OpGroupSMax": OpGroupSMax,
+ "OpReadPipe": OpReadPipe,
+ "OpWritePipe": OpWritePipe,
+ "OpReservedReadPipe": OpReservedReadPipe,
+ "OpReservedWritePipe": OpReservedWritePipe,
+ "OpReserveReadPipePackets": OpReserveReadPipePackets,
+ "OpReserveWritePipePackets": OpReserveWritePipePackets,
+ "OpCommitReadPipe": OpCommitReadPipe,
+ "OpCommitWritePipe": OpCommitWritePipe,
+ "OpIsValidReserveId": OpIsValidReserveId,
+ "OpGetNumPipePackets": OpGetNumPipePackets,
+ "OpGetMaxPipePackets": OpGetMaxPipePackets,
+ "OpGroupReserveReadPipePackets": OpGroupReserveReadPipePackets,
+ "OpGroupReserveWritePipePackets": OpGroupReserveWritePipePackets,
+ "OpGroupCommitReadPipe": OpGroupCommitReadPipe,
+ "OpGroupCommitWritePipe": OpGroupCommitWritePipe,
+ "OpEnqueueMarker": OpEnqueueMarker,
+ "OpEnqueueKernel": OpEnqueueKernel,
+ "OpGetKernelNDrangeSubGroupCount": OpGetKernelNDrangeSubGroupCount,
+ "OpGetKernelNDrangeMaxSubGroupSize": OpGetKernelNDrangeMaxSubGroupSize,
+ "OpGetKernelWorkGroupSize": OpGetKernelWorkGroupSize,
+ "OpGetKernelPreferredWorkGroupSizeMultiple": OpGetKernelPreferredWorkGroupSizeMultiple,
+ "OpRetainEvent": OpRetainEvent,
+ "OpReleaseEvent": OpReleaseEvent,
+ "OpCreateUserEvent": OpCreateUserEvent,
+ "OpIsValidEvent": OpIsValidEvent,
+ "OpSetUserEventStatus": OpSetUserEventStatus,
+ "OpCaptureEventProfilingInfo": OpCaptureEventProfilingInfo,
+ "OpGetDefaultQueue": OpGetDefaultQueue,
+ "OpBuildNDRange": OpBuildNDRange,
+ "OpImageSparseSampleImplicitLod": OpImageSparseSampleImplicitLod,
+ "OpImageSparseSampleExplicitLod": OpImageSparseSampleExplicitLod,
+ "OpImageSparseSampleDrefImplicitLod": OpImageSparseSampleDrefImplicitLod,
+ "OpImageSparseSampleDrefExplicitLod": OpImageSparseSampleDrefExplicitLod,
+ "OpImageSparseSampleProjImplicitLod": OpImageSparseSampleProjImplicitLod,
+ "OpImageSparseSampleProjExplicitLod": OpImageSparseSampleProjExplicitLod,
+ "OpImageSparseSampleProjDrefImplicitLod": OpImageSparseSampleProjDrefImplicitLod,
+ "OpImageSparseSampleProjDrefExplicitLod": OpImageSparseSampleProjDrefExplicitLod,
+ "OpImageSparseFetch": OpImageSparseFetch,
+ "OpImageSparseGather": OpImageSparseGather,
+ "OpImageSparseDrefGather": OpImageSparseDrefGather,
+ "OpImageSparseTexelsResident": OpImageSparseTexelsResident,
+ "OpNoLine": OpNoLine,
+ "OpAtomicFlagTestAndSet": OpAtomicFlagTestAndSet,
+ "OpAtomicFlagClear": OpAtomicFlagClear,
+ "OpImageSparseRead": OpImageSparseRead,
+ "OpSizeOf": OpSizeOf,
+ "OpTypePipeStorage": OpTypePipeStorage,
+ "OpConstantPipeStorage": OpConstantPipeStorage,
+ "OpCreatePipeFromPipeStorage": OpCreatePipeFromPipeStorage,
+ "OpGetKernelLocalSizeForSubgroupCount": OpGetKernelLocalSizeForSubgroupCount,
+ "OpGetKernelMaxNumSubgroups": OpGetKernelMaxNumSubgroups,
+ "OpTypeNamedBarrier": OpTypeNamedBarrier,
+ "OpNamedBarrierInitialize": OpNamedBarrierInitialize,
+ "OpMemoryNamedBarrier": OpMemoryNamedBarrier,
+ "OpModuleProcessed": OpModuleProcessed,
+ "OpExecutionModeId": OpExecutionModeId,
+ "OpDecorateId": OpDecorateId,
+ "OpGroupNonUniformElect": OpGroupNonUniformElect,
+ "OpGroupNonUniformAll": OpGroupNonUniformAll,
+ "OpGroupNonUniformAny": OpGroupNonUniformAny,
+ "OpGroupNonUniformAllEqual": OpGroupNonUniformAllEqual,
+ "OpGroupNonUniformBroadcast": OpGroupNonUniformBroadcast,
+ "OpGroupNonUniformBroadcastFirst": OpGroupNonUniformBroadcastFirst,
+ "OpGroupNonUniformBallot": OpGroupNonUniformBallot,
+ "OpGroupNonUniformInverseBallot": OpGroupNonUniformInverseBallot,
+ "OpGroupNonUniformBallotBitExtract": OpGroupNonUniformBallotBitExtract,
+ "OpGroupNonUniformBallotBitCount": OpGroupNonUniformBallotBitCount,
+ "OpGroupNonUniformBallotFindLSB": OpGroupNonUniformBallotFindLSB,
+ "OpGroupNonUniformBallotFindMSB": OpGroupNonUniformBallotFindMSB,
+ "OpGroupNonUniformShuffle": OpGroupNonUniformShuffle,
+ "OpGroupNonUniformShuffleXor": OpGroupNonUniformShuffleXor,
+ "OpGroupNonUniformShuffleUp": OpGroupNonUniformShuffleUp,
+ "OpGroupNonUniformShuffleDown": OpGroupNonUniformShuffleDown,
+ "OpGroupNonUniformIAdd": OpGroupNonUniformIAdd,
+ "OpGroupNonUniformFAdd": OpGroupNonUniformFAdd,
+ "OpGroupNonUniformIMul": OpGroupNonUniformIMul,
+ "OpGroupNonUniformFMul": OpGroupNonUniformFMul,
+ "OpGroupNonUniformSMin": OpGroupNonUniformSMin,
+ "OpGroupNonUniformUMin": OpGroupNonUniformUMin,
+ "OpGroupNonUniformFMin": OpGroupNonUniformFMin,
+ "OpGroupNonUniformSMax": OpGroupNonUniformSMax,
+ "OpGroupNonUniformUMax": OpGroupNonUniformUMax,
+ "OpGroupNonUniformFMax": OpGroupNonUniformFMax,
+ "OpGroupNonUniformBitwiseAnd": OpGroupNonUniformBitwiseAnd,
+ "OpGroupNonUniformBitwiseOr": OpGroupNonUniformBitwiseOr,
+ "OpGroupNonUniformBitwiseXor": OpGroupNonUniformBitwiseXor,
+ "OpGroupNonUniformLogicalAnd": OpGroupNonUniformLogicalAnd,
+ "OpGroupNonUniformLogicalOr": OpGroupNonUniformLogicalOr,
+ "OpGroupNonUniformLogicalXor": OpGroupNonUniformLogicalXor,
+ "OpGroupNonUniformQuadBroadcast": OpGroupNonUniformQuadBroadcast,
+ "OpGroupNonUniformQuadSwap": OpGroupNonUniformQuadSwap,
+ "OpCopyLogical": OpCopyLogical,
+ "OpPtrEqual": OpPtrEqual,
+ "OpPtrNotEqual": OpPtrNotEqual,
+ "OpPtrDiff": OpPtrDiff,
+ "OpSubgroupBallotKHR": OpSubgroupBallotKHR,
+ "OpSubgroupFirstInvocationKHR": OpSubgroupFirstInvocationKHR,
+ "OpSubgroupAllKHR": OpSubgroupAllKHR,
+ "OpSubgroupAnyKHR": OpSubgroupAnyKHR,
+ "OpSubgroupAllEqualKHR": OpSubgroupAllEqualKHR,
+ "OpSubgroupReadInvocationKHR": OpSubgroupReadInvocationKHR,
+ "OpGroupIAddNonUniformAMD": OpGroupIAddNonUniformAMD,
+ "OpGroupFAddNonUniformAMD": OpGroupFAddNonUniformAMD,
+ "OpGroupFMinNonUniformAMD": OpGroupFMinNonUniformAMD,
+ "OpGroupUMinNonUniformAMD": OpGroupUMinNonUniformAMD,
+ "OpGroupSMinNonUniformAMD": OpGroupSMinNonUniformAMD,
+ "OpGroupFMaxNonUniformAMD": OpGroupFMaxNonUniformAMD,
+ "OpGroupUMaxNonUniformAMD": OpGroupUMaxNonUniformAMD,
+ "OpGroupSMaxNonUniformAMD": OpGroupSMaxNonUniformAMD,
+ "OpFragmentMaskFetchAMD": OpFragmentMaskFetchAMD,
+ "OpFragmentFetchAMD": OpFragmentFetchAMD,
+ "OpReadClockKHR": OpReadClockKHR,
+ "OpImageSampleFootprintNV": OpImageSampleFootprintNV,
+ "OpGroupNonUniformPartitionNV": OpGroupNonUniformPartitionNV,
+ "OpWritePackedPrimitiveIndices4x8NV": OpWritePackedPrimitiveIndices4x8NV,
+ "OpReportIntersectionNV": OpReportIntersectionNV,
+ "OpIgnoreIntersectionNV": OpIgnoreIntersectionNV,
+ "OpTerminateRayNV": OpTerminateRayNV,
+ "OpTraceNV": OpTraceNV,
+ "OpTypeAccelerationStructureNV": OpTypeAccelerationStructureNV,
+ "OpExecuteCallableNV": OpExecuteCallableNV,
+ "OpTypeCooperativeMatrixNV": OpTypeCooperativeMatrixNV,
+ "OpCooperativeMatrixLoadNV": OpCooperativeMatrixLoadNV,
+ "OpCooperativeMatrixStoreNV": OpCooperativeMatrixStoreNV,
+ "OpCooperativeMatrixMulAddNV": OpCooperativeMatrixMulAddNV,
+ "OpCooperativeMatrixLengthNV": OpCooperativeMatrixLengthNV,
+ "OpBeginInvocationInterlockEXT": OpBeginInvocationInterlockEXT,
+ "OpEndInvocationInterlockEXT": OpEndInvocationInterlockEXT,
+ "OpDemoteToHelperInvocationEXT": OpDemoteToHelperInvocationEXT,
+ "OpIsHelperInvocationEXT": OpIsHelperInvocationEXT,
+ "OpSubgroupShuffleINTEL": OpSubgroupShuffleINTEL,
+ "OpSubgroupShuffleDownINTEL": OpSubgroupShuffleDownINTEL,
+ "OpSubgroupShuffleUpINTEL": OpSubgroupShuffleUpINTEL,
+ "OpSubgroupShuffleXorINTEL": OpSubgroupShuffleXorINTEL,
+ "OpSubgroupBlockReadINTEL": OpSubgroupBlockReadINTEL,
+ "OpSubgroupBlockWriteINTEL": OpSubgroupBlockWriteINTEL,
+ "OpSubgroupImageBlockReadINTEL": OpSubgroupImageBlockReadINTEL,
+ "OpSubgroupImageBlockWriteINTEL": OpSubgroupImageBlockWriteINTEL,
+ "OpSubgroupImageMediaBlockReadINTEL": OpSubgroupImageMediaBlockReadINTEL,
+ "OpSubgroupImageMediaBlockWriteINTEL": OpSubgroupImageMediaBlockWriteINTEL,
+ "OpUCountLeadingZerosINTEL": OpUCountLeadingZerosINTEL,
+ "OpUCountTrailingZerosINTEL": OpUCountTrailingZerosINTEL,
+ "OpAbsISubINTEL": OpAbsISubINTEL,
+ "OpAbsUSubINTEL": OpAbsUSubINTEL,
+ "OpIAddSatINTEL": OpIAddSatINTEL,
+ "OpUAddSatINTEL": OpUAddSatINTEL,
+ "OpIAverageINTEL": OpIAverageINTEL,
+ "OpUAverageINTEL": OpUAverageINTEL,
+ "OpIAverageRoundedINTEL": OpIAverageRoundedINTEL,
+ "OpUAverageRoundedINTEL": OpUAverageRoundedINTEL,
+ "OpISubSatINTEL": OpISubSatINTEL,
+ "OpUSubSatINTEL": OpUSubSatINTEL,
+ "OpIMul32x16INTEL": OpIMul32x16INTEL,
+ "OpUMul32x16INTEL": OpUMul32x16INTEL,
+ "OpDecorateString": OpDecorateString,
+ "OpDecorateStringGOOGLE": OpDecorateStringGOOGLE,
+ "OpMemberDecorateString": OpMemberDecorateString,
+ "OpMemberDecorateStringGOOGLE": OpMemberDecorateStringGOOGLE,
+ "OpVmeImageINTEL": OpVmeImageINTEL,
+ "OpTypeVmeImageINTEL": OpTypeVmeImageINTEL,
+ "OpTypeAvcImePayloadINTEL": OpTypeAvcImePayloadINTEL,
+ "OpTypeAvcRefPayloadINTEL": OpTypeAvcRefPayloadINTEL,
+ "OpTypeAvcSicPayloadINTEL": OpTypeAvcSicPayloadINTEL,
+ "OpTypeAvcMcePayloadINTEL": OpTypeAvcMcePayloadINTEL,
+ "OpTypeAvcMceResultINTEL": OpTypeAvcMceResultINTEL,
+ "OpTypeAvcImeResultINTEL": OpTypeAvcImeResultINTEL,
+ "OpTypeAvcImeResultSingleReferenceStreamoutINTEL": OpTypeAvcImeResultSingleReferenceStreamoutINTEL,
+ "OpTypeAvcImeResultDualReferenceStreamoutINTEL": OpTypeAvcImeResultDualReferenceStreamoutINTEL,
+ "OpTypeAvcImeSingleReferenceStreaminINTEL": OpTypeAvcImeSingleReferenceStreaminINTEL,
+ "OpTypeAvcImeDualReferenceStreaminINTEL": OpTypeAvcImeDualReferenceStreaminINTEL,
+ "OpTypeAvcRefResultINTEL": OpTypeAvcRefResultINTEL,
+ "OpTypeAvcSicResultINTEL": OpTypeAvcSicResultINTEL,
+ "OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL": OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL,
+ "OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL": OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL,
+ "OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL": OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL,
+ "OpSubgroupAvcMceSetInterShapePenaltyINTEL": OpSubgroupAvcMceSetInterShapePenaltyINTEL,
+ "OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL": OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL,
+ "OpSubgroupAvcMceSetInterDirectionPenaltyINTEL": OpSubgroupAvcMceSetInterDirectionPenaltyINTEL,
+ "OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL": OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL,
+ "OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL": OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL,
+ "OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL": OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL,
+ "OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL": OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL,
+ "OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL": OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL,
+ "OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL": OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL,
+ "OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL": OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL,
+ "OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL": OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL,
+ "OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL": OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL,
+ "OpSubgroupAvcMceSetAcOnlyHaarINTEL": OpSubgroupAvcMceSetAcOnlyHaarINTEL,
+ "OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL": OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL,
+ "OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL": OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL,
+ "OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL": OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL,
+ "OpSubgroupAvcMceConvertToImePayloadINTEL": OpSubgroupAvcMceConvertToImePayloadINTEL,
+ "OpSubgroupAvcMceConvertToImeResultINTEL": OpSubgroupAvcMceConvertToImeResultINTEL,
+ "OpSubgroupAvcMceConvertToRefPayloadINTEL": OpSubgroupAvcMceConvertToRefPayloadINTEL,
+ "OpSubgroupAvcMceConvertToRefResultINTEL": OpSubgroupAvcMceConvertToRefResultINTEL,
+ "OpSubgroupAvcMceConvertToSicPayloadINTEL": OpSubgroupAvcMceConvertToSicPayloadINTEL,
+ "OpSubgroupAvcMceConvertToSicResultINTEL": OpSubgroupAvcMceConvertToSicResultINTEL,
+ "OpSubgroupAvcMceGetMotionVectorsINTEL": OpSubgroupAvcMceGetMotionVectorsINTEL,
+ "OpSubgroupAvcMceGetInterDistortionsINTEL": OpSubgroupAvcMceGetInterDistortionsINTEL,
+ "OpSubgroupAvcMceGetBestInterDistortionsINTEL": OpSubgroupAvcMceGetBestInterDistortionsINTEL,
+ "OpSubgroupAvcMceGetInterMajorShapeINTEL": OpSubgroupAvcMceGetInterMajorShapeINTEL,
+ "OpSubgroupAvcMceGetInterMinorShapeINTEL": OpSubgroupAvcMceGetInterMinorShapeINTEL,
+ "OpSubgroupAvcMceGetInterDirectionsINTEL": OpSubgroupAvcMceGetInterDirectionsINTEL,
+ "OpSubgroupAvcMceGetInterMotionVectorCountINTEL": OpSubgroupAvcMceGetInterMotionVectorCountINTEL,
+ "OpSubgroupAvcMceGetInterReferenceIdsINTEL": OpSubgroupAvcMceGetInterReferenceIdsINTEL,
+ "OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL": OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL,
+ "OpSubgroupAvcImeInitializeINTEL": OpSubgroupAvcImeInitializeINTEL,
+ "OpSubgroupAvcImeSetSingleReferenceINTEL": OpSubgroupAvcImeSetSingleReferenceINTEL,
+ "OpSubgroupAvcImeSetDualReferenceINTEL": OpSubgroupAvcImeSetDualReferenceINTEL,
+ "OpSubgroupAvcImeRefWindowSizeINTEL": OpSubgroupAvcImeRefWindowSizeINTEL,
+ "OpSubgroupAvcImeAdjustRefOffsetINTEL": OpSubgroupAvcImeAdjustRefOffsetINTEL,
+ "OpSubgroupAvcImeConvertToMcePayloadINTEL": OpSubgroupAvcImeConvertToMcePayloadINTEL,
+ "OpSubgroupAvcImeSetMaxMotionVectorCountINTEL": OpSubgroupAvcImeSetMaxMotionVectorCountINTEL,
+ "OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL": OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL,
+ "OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL": OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL,
+ "OpSubgroupAvcImeSetWeightedSadINTEL": OpSubgroupAvcImeSetWeightedSadINTEL,
+ "OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL": OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL,
+ "OpSubgroupAvcImeEvaluateWithDualReferenceINTEL": OpSubgroupAvcImeEvaluateWithDualReferenceINTEL,
+ "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL": OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL,
+ "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL": OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL,
+ "OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL": OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL,
+ "OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL": OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL,
+ "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL": OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL,
+ "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL": OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL,
+ "OpSubgroupAvcImeConvertToMceResultINTEL": OpSubgroupAvcImeConvertToMceResultINTEL,
+ "OpSubgroupAvcImeGetSingleReferenceStreaminINTEL": OpSubgroupAvcImeGetSingleReferenceStreaminINTEL,
+ "OpSubgroupAvcImeGetDualReferenceStreaminINTEL": OpSubgroupAvcImeGetDualReferenceStreaminINTEL,
+ "OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL": OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL,
+ "OpSubgroupAvcImeStripDualReferenceStreamoutINTEL": OpSubgroupAvcImeStripDualReferenceStreamoutINTEL,
+ "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL": OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL,
+ "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL": OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL,
+ "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL": OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL,
+ "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL": OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL,
+ "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL": OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL,
+ "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL": OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL,
+ "OpSubgroupAvcImeGetBorderReachedINTEL": OpSubgroupAvcImeGetBorderReachedINTEL,
+ "OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL": OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL,
+ "OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL": OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL,
+ "OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL": OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL,
+ "OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL": OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL,
+ "OpSubgroupAvcFmeInitializeINTEL": OpSubgroupAvcFmeInitializeINTEL,
+ "OpSubgroupAvcBmeInitializeINTEL": OpSubgroupAvcBmeInitializeINTEL,
+ "OpSubgroupAvcRefConvertToMcePayloadINTEL": OpSubgroupAvcRefConvertToMcePayloadINTEL,
+ "OpSubgroupAvcRefSetBidirectionalMixDisableINTEL": OpSubgroupAvcRefSetBidirectionalMixDisableINTEL,
+ "OpSubgroupAvcRefSetBilinearFilterEnableINTEL": OpSubgroupAvcRefSetBilinearFilterEnableINTEL,
+ "OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL": OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL,
+ "OpSubgroupAvcRefEvaluateWithDualReferenceINTEL": OpSubgroupAvcRefEvaluateWithDualReferenceINTEL,
+ "OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL": OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL,
+ "OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL": OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL,
+ "OpSubgroupAvcRefConvertToMceResultINTEL": OpSubgroupAvcRefConvertToMceResultINTEL,
+ "OpSubgroupAvcSicInitializeINTEL": OpSubgroupAvcSicInitializeINTEL,
+ "OpSubgroupAvcSicConfigureSkcINTEL": OpSubgroupAvcSicConfigureSkcINTEL,
+ "OpSubgroupAvcSicConfigureIpeLumaINTEL": OpSubgroupAvcSicConfigureIpeLumaINTEL,
+ "OpSubgroupAvcSicConfigureIpeLumaChromaINTEL": OpSubgroupAvcSicConfigureIpeLumaChromaINTEL,
+ "OpSubgroupAvcSicGetMotionVectorMaskINTEL": OpSubgroupAvcSicGetMotionVectorMaskINTEL,
+ "OpSubgroupAvcSicConvertToMcePayloadINTEL": OpSubgroupAvcSicConvertToMcePayloadINTEL,
+ "OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL": OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL,
+ "OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL": OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL,
+ "OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL": OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL,
+ "OpSubgroupAvcSicSetBilinearFilterEnableINTEL": OpSubgroupAvcSicSetBilinearFilterEnableINTEL,
+ "OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL": OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL,
+ "OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL": OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL,
+ "OpSubgroupAvcSicEvaluateIpeINTEL": OpSubgroupAvcSicEvaluateIpeINTEL,
+ "OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL": OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL,
+ "OpSubgroupAvcSicEvaluateWithDualReferenceINTEL": OpSubgroupAvcSicEvaluateWithDualReferenceINTEL,
+ "OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL": OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL,
+ "OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL": OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL,
+ "OpSubgroupAvcSicConvertToMceResultINTEL": OpSubgroupAvcSicConvertToMceResultINTEL,
+ "OpSubgroupAvcSicGetIpeLumaShapeINTEL": OpSubgroupAvcSicGetIpeLumaShapeINTEL,
+ "OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL": OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL,
+ "OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL": OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL,
+ "OpSubgroupAvcSicGetPackedIpeLumaModesINTEL": OpSubgroupAvcSicGetPackedIpeLumaModesINTEL,
+ "OpSubgroupAvcSicGetIpeChromaModeINTEL": OpSubgroupAvcSicGetIpeChromaModeINTEL,
+ "OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL": OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL,
+ "OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL": OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL,
+ "OpSubgroupAvcSicGetInterRawSadsINTEL": OpSubgroupAvcSicGetInterRawSadsINTEL,
+ }
+
+ OpNop = &Opcode {
+ Opname: "OpNop",
+ Operands: []Operand {
+ },
+ }
+ OpUndef = &Opcode {
+ Opname: "OpUndef",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSourceContinued = &Opcode {
+ Opname: "OpSourceContinued",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'Continued Source'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSource = &Opcode {
+ Opname: "OpSource",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindSourceLanguage,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Version'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'File'",
+ Quantifier: "?",
+ },
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'Source'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpSourceExtension = &Opcode {
+ Opname: "OpSourceExtension",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'Extension'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpName = &Opcode {
+ Opname: "OpName",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Target'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'Name'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpMemberName = &Opcode {
+ Opname: "OpMemberName",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Member'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'Name'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpString = &Opcode {
+ Opname: "OpString",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'String'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLine = &Opcode {
+ Opname: "OpLine",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'File'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Line'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Column'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpExtension = &Opcode {
+ Opname: "OpExtension",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'Name'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpExtInstImport = &Opcode {
+ Opname: "OpExtInstImport",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'Name'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpExtInst = &Opcode {
+ Opname: "OpExtInst",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Set'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralExtInstInteger,
+ Name: "'Instruction'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1', + 'Operand 2', + ...",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpMemoryModel = &Opcode {
+ Opname: "OpMemoryModel",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindAddressingModel,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindMemoryModel,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpEntryPoint = &Opcode {
+ Opname: "OpEntryPoint",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindExecutionModel,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Entry Point'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'Name'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Interface'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpExecutionMode = &Opcode {
+ Opname: "OpExecutionMode",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Entry Point'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindExecutionMode,
+ Name: "'Mode'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpCapability = &Opcode {
+ Opname: "OpCapability",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindCapability,
+ Name: "'Capability'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeVoid = &Opcode {
+ Opname: "OpTypeVoid",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeBool = &Opcode {
+ Opname: "OpTypeBool",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeInt = &Opcode {
+ Opname: "OpTypeInt",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Width'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Signedness'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeFloat = &Opcode {
+ Opname: "OpTypeFloat",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Width'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeVector = &Opcode {
+ Opname: "OpTypeVector",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Component Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Component Count'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeMatrix = &Opcode {
+ Opname: "OpTypeMatrix",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Column Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Column Count'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeImage = &Opcode {
+ Opname: "OpTypeImage",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindDim,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Depth'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Arrayed'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'MS'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Sampled'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageFormat,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindAccessQualifier,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpTypeSampler = &Opcode {
+ Opname: "OpTypeSampler",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeSampledImage = &Opcode {
+ Opname: "OpTypeSampledImage",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image Type'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeArray = &Opcode {
+ Opname: "OpTypeArray",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Element Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Length'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeRuntimeArray = &Opcode {
+ Opname: "OpTypeRuntimeArray",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Element Type'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeStruct = &Opcode {
+ Opname: "OpTypeStruct",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Member 0 type', + 'member 1 type', + ...",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpTypeOpaque = &Opcode {
+ Opname: "OpTypeOpaque",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "The name of the opaque type.",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypePointer = &Opcode {
+ Opname: "OpTypePointer",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindStorageClass,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Type'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeFunction = &Opcode {
+ Opname: "OpTypeFunction",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Return Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Parameter 0 Type', + 'Parameter 1 Type', + ...",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpTypeEvent = &Opcode {
+ Opname: "OpTypeEvent",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeDeviceEvent = &Opcode {
+ Opname: "OpTypeDeviceEvent",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeReserveId = &Opcode {
+ Opname: "OpTypeReserveId",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeQueue = &Opcode {
+ Opname: "OpTypeQueue",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypePipe = &Opcode {
+ Opname: "OpTypePipe",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindAccessQualifier,
+ Name: "'Qualifier'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeForwardPointer = &Opcode {
+ Opname: "OpTypeForwardPointer",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindStorageClass,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConstantTrue = &Opcode {
+ Opname: "OpConstantTrue",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConstantFalse = &Opcode {
+ Opname: "OpConstantFalse",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConstant = &Opcode {
+ Opname: "OpConstant",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralContextDependentNumber,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConstantComposite = &Opcode {
+ Opname: "OpConstantComposite",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Constituents'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpConstantSampler = &Opcode {
+ Opname: "OpConstantSampler",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindSamplerAddressingMode,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Param'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindSamplerFilterMode,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConstantNull = &Opcode {
+ Opname: "OpConstantNull",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSpecConstantTrue = &Opcode {
+ Opname: "OpSpecConstantTrue",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSpecConstantFalse = &Opcode {
+ Opname: "OpSpecConstantFalse",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSpecConstant = &Opcode {
+ Opname: "OpSpecConstant",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralContextDependentNumber,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSpecConstantComposite = &Opcode {
+ Opname: "OpSpecConstantComposite",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Constituents'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpSpecConstantOp = &Opcode {
+ Opname: "OpSpecConstantOp",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralSpecConstantOpInteger,
+ Name: "'Opcode'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFunction = &Opcode {
+ Opname: "OpFunction",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindFunctionControl,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Function Type'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFunctionParameter = &Opcode {
+ Opname: "OpFunctionParameter",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFunctionEnd = &Opcode {
+ Opname: "OpFunctionEnd",
+ Operands: []Operand {
+ },
+ }
+ OpFunctionCall = &Opcode {
+ Opname: "OpFunctionCall",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Function'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Argument 0', + 'Argument 1', + ...",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpVariable = &Opcode {
+ Opname: "OpVariable",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindStorageClass,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Initializer'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageTexelPointer = &Opcode {
+ Opname: "OpImageTexelPointer",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sample'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLoad = &Opcode {
+ Opname: "OpLoad",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindMemoryAccess,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpStore = &Opcode {
+ Opname: "OpStore",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Object'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindMemoryAccess,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpCopyMemory = &Opcode {
+ Opname: "OpCopyMemory",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Target'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Source'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindMemoryAccess,
+ Name: "",
+ Quantifier: "?",
+ },
+ Operand {
+ Kind: OperandKindMemoryAccess,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpCopyMemorySized = &Opcode {
+ Opname: "OpCopyMemorySized",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Target'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Source'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindMemoryAccess,
+ Name: "",
+ Quantifier: "?",
+ },
+ Operand {
+ Kind: OperandKindMemoryAccess,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpAccessChain = &Opcode {
+ Opname: "OpAccessChain",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Indexes'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpInBoundsAccessChain = &Opcode {
+ Opname: "OpInBoundsAccessChain",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Indexes'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpPtrAccessChain = &Opcode {
+ Opname: "OpPtrAccessChain",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Element'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Indexes'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpArrayLength = &Opcode {
+ Opname: "OpArrayLength",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Structure'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Array member'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGenericPtrMemSemantics = &Opcode {
+ Opname: "OpGenericPtrMemSemantics",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpInBoundsPtrAccessChain = &Opcode {
+ Opname: "OpInBoundsPtrAccessChain",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Element'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Indexes'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpDecorate = &Opcode {
+ Opname: "OpDecorate",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Target'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindDecoration,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpMemberDecorate = &Opcode {
+ Opname: "OpMemberDecorate",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Structure Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Member'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindDecoration,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDecorationGroup = &Opcode {
+ Opname: "OpDecorationGroup",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupDecorate = &Opcode {
+ Opname: "OpGroupDecorate",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Decoration Group'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Targets'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpGroupMemberDecorate = &Opcode {
+ Opname: "OpGroupMemberDecorate",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Decoration Group'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindPairIdRefLiteralInteger,
+ Name: "'Targets'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpVectorExtractDynamic = &Opcode {
+ Opname: "OpVectorExtractDynamic",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Index'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpVectorInsertDynamic = &Opcode {
+ Opname: "OpVectorInsertDynamic",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Component'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Index'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpVectorShuffle = &Opcode {
+ Opname: "OpVectorShuffle",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector 2'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Components'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpCompositeConstruct = &Opcode {
+ Opname: "OpCompositeConstruct",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Constituents'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpCompositeExtract = &Opcode {
+ Opname: "OpCompositeExtract",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Composite'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Indexes'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpCompositeInsert = &Opcode {
+ Opname: "OpCompositeInsert",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Object'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Composite'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Indexes'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpCopyObject = &Opcode {
+ Opname: "OpCopyObject",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTranspose = &Opcode {
+ Opname: "OpTranspose",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Matrix'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSampledImage = &Opcode {
+ Opname: "OpSampledImage",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampler'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSampleImplicitLod = &Opcode {
+ Opname: "OpImageSampleImplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSampleExplicitLod = &Opcode {
+ Opname: "OpImageSampleExplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSampleDrefImplicitLod = &Opcode {
+ Opname: "OpImageSampleDrefImplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSampleDrefExplicitLod = &Opcode {
+ Opname: "OpImageSampleDrefExplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSampleProjImplicitLod = &Opcode {
+ Opname: "OpImageSampleProjImplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSampleProjExplicitLod = &Opcode {
+ Opname: "OpImageSampleProjExplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSampleProjDrefImplicitLod = &Opcode {
+ Opname: "OpImageSampleProjDrefImplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSampleProjDrefExplicitLod = &Opcode {
+ Opname: "OpImageSampleProjDrefExplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageFetch = &Opcode {
+ Opname: "OpImageFetch",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageGather = &Opcode {
+ Opname: "OpImageGather",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Component'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageDrefGather = &Opcode {
+ Opname: "OpImageDrefGather",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageRead = &Opcode {
+ Opname: "OpImageRead",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageWrite = &Opcode {
+ Opname: "OpImageWrite",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Texel'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImage = &Opcode {
+ Opname: "OpImage",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageQueryFormat = &Opcode {
+ Opname: "OpImageQueryFormat",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageQueryOrder = &Opcode {
+ Opname: "OpImageQueryOrder",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageQuerySizeLod = &Opcode {
+ Opname: "OpImageQuerySizeLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Level of Detail'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageQuerySize = &Opcode {
+ Opname: "OpImageQuerySize",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageQueryLod = &Opcode {
+ Opname: "OpImageQueryLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageQueryLevels = &Opcode {
+ Opname: "OpImageQueryLevels",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageQuerySamples = &Opcode {
+ Opname: "OpImageQuerySamples",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConvertFToU = &Opcode {
+ Opname: "OpConvertFToU",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Float Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConvertFToS = &Opcode {
+ Opname: "OpConvertFToS",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Float Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConvertSToF = &Opcode {
+ Opname: "OpConvertSToF",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Signed Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConvertUToF = &Opcode {
+ Opname: "OpConvertUToF",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Unsigned Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUConvert = &Opcode {
+ Opname: "OpUConvert",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Unsigned Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSConvert = &Opcode {
+ Opname: "OpSConvert",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Signed Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFConvert = &Opcode {
+ Opname: "OpFConvert",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Float Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpQuantizeToF16 = &Opcode {
+ Opname: "OpQuantizeToF16",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConvertPtrToU = &Opcode {
+ Opname: "OpConvertPtrToU",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSatConvertSToU = &Opcode {
+ Opname: "OpSatConvertSToU",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Signed Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSatConvertUToS = &Opcode {
+ Opname: "OpSatConvertUToS",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Unsigned Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConvertUToPtr = &Opcode {
+ Opname: "OpConvertUToPtr",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Integer Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpPtrCastToGeneric = &Opcode {
+ Opname: "OpPtrCastToGeneric",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGenericCastToPtr = &Opcode {
+ Opname: "OpGenericCastToPtr",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGenericCastToPtrExplicit = &Opcode {
+ Opname: "OpGenericCastToPtrExplicit",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindStorageClass,
+ Name: "'Storage'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBitcast = &Opcode {
+ Opname: "OpBitcast",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSNegate = &Opcode {
+ Opname: "OpSNegate",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFNegate = &Opcode {
+ Opname: "OpFNegate",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIAdd = &Opcode {
+ Opname: "OpIAdd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFAdd = &Opcode {
+ Opname: "OpFAdd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpISub = &Opcode {
+ Opname: "OpISub",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFSub = &Opcode {
+ Opname: "OpFSub",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIMul = &Opcode {
+ Opname: "OpIMul",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFMul = &Opcode {
+ Opname: "OpFMul",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUDiv = &Opcode {
+ Opname: "OpUDiv",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSDiv = &Opcode {
+ Opname: "OpSDiv",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFDiv = &Opcode {
+ Opname: "OpFDiv",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUMod = &Opcode {
+ Opname: "OpUMod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSRem = &Opcode {
+ Opname: "OpSRem",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSMod = &Opcode {
+ Opname: "OpSMod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFRem = &Opcode {
+ Opname: "OpFRem",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFMod = &Opcode {
+ Opname: "OpFMod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpVectorTimesScalar = &Opcode {
+ Opname: "OpVectorTimesScalar",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Scalar'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpMatrixTimesScalar = &Opcode {
+ Opname: "OpMatrixTimesScalar",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Matrix'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Scalar'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpVectorTimesMatrix = &Opcode {
+ Opname: "OpVectorTimesMatrix",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Matrix'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpMatrixTimesVector = &Opcode {
+ Opname: "OpMatrixTimesVector",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Matrix'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpMatrixTimesMatrix = &Opcode {
+ Opname: "OpMatrixTimesMatrix",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'LeftMatrix'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'RightMatrix'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpOuterProduct = &Opcode {
+ Opname: "OpOuterProduct",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDot = &Opcode {
+ Opname: "OpDot",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIAddCarry = &Opcode {
+ Opname: "OpIAddCarry",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpISubBorrow = &Opcode {
+ Opname: "OpISubBorrow",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUMulExtended = &Opcode {
+ Opname: "OpUMulExtended",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSMulExtended = &Opcode {
+ Opname: "OpSMulExtended",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAny = &Opcode {
+ Opname: "OpAny",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAll = &Opcode {
+ Opname: "OpAll",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Vector'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIsNan = &Opcode {
+ Opname: "OpIsNan",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'x'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIsInf = &Opcode {
+ Opname: "OpIsInf",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'x'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIsFinite = &Opcode {
+ Opname: "OpIsFinite",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'x'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIsNormal = &Opcode {
+ Opname: "OpIsNormal",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'x'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSignBitSet = &Opcode {
+ Opname: "OpSignBitSet",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'x'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLessOrGreater = &Opcode {
+ Opname: "OpLessOrGreater",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'x'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'y'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpOrdered = &Opcode {
+ Opname: "OpOrdered",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'x'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'y'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUnordered = &Opcode {
+ Opname: "OpUnordered",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'x'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'y'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLogicalEqual = &Opcode {
+ Opname: "OpLogicalEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLogicalNotEqual = &Opcode {
+ Opname: "OpLogicalNotEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLogicalOr = &Opcode {
+ Opname: "OpLogicalOr",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLogicalAnd = &Opcode {
+ Opname: "OpLogicalAnd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLogicalNot = &Opcode {
+ Opname: "OpLogicalNot",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSelect = &Opcode {
+ Opname: "OpSelect",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Condition'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Object 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Object 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIEqual = &Opcode {
+ Opname: "OpIEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpINotEqual = &Opcode {
+ Opname: "OpINotEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUGreaterThan = &Opcode {
+ Opname: "OpUGreaterThan",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSGreaterThan = &Opcode {
+ Opname: "OpSGreaterThan",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUGreaterThanEqual = &Opcode {
+ Opname: "OpUGreaterThanEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSGreaterThanEqual = &Opcode {
+ Opname: "OpSGreaterThanEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpULessThan = &Opcode {
+ Opname: "OpULessThan",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSLessThan = &Opcode {
+ Opname: "OpSLessThan",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpULessThanEqual = &Opcode {
+ Opname: "OpULessThanEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSLessThanEqual = &Opcode {
+ Opname: "OpSLessThanEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFOrdEqual = &Opcode {
+ Opname: "OpFOrdEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFUnordEqual = &Opcode {
+ Opname: "OpFUnordEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFOrdNotEqual = &Opcode {
+ Opname: "OpFOrdNotEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFUnordNotEqual = &Opcode {
+ Opname: "OpFUnordNotEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFOrdLessThan = &Opcode {
+ Opname: "OpFOrdLessThan",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFUnordLessThan = &Opcode {
+ Opname: "OpFUnordLessThan",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFOrdGreaterThan = &Opcode {
+ Opname: "OpFOrdGreaterThan",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFUnordGreaterThan = &Opcode {
+ Opname: "OpFUnordGreaterThan",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFOrdLessThanEqual = &Opcode {
+ Opname: "OpFOrdLessThanEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFUnordLessThanEqual = &Opcode {
+ Opname: "OpFUnordLessThanEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFOrdGreaterThanEqual = &Opcode {
+ Opname: "OpFOrdGreaterThanEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFUnordGreaterThanEqual = &Opcode {
+ Opname: "OpFUnordGreaterThanEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpShiftRightLogical = &Opcode {
+ Opname: "OpShiftRightLogical",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Shift'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpShiftRightArithmetic = &Opcode {
+ Opname: "OpShiftRightArithmetic",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Shift'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpShiftLeftLogical = &Opcode {
+ Opname: "OpShiftLeftLogical",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Shift'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBitwiseOr = &Opcode {
+ Opname: "OpBitwiseOr",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBitwiseXor = &Opcode {
+ Opname: "OpBitwiseXor",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBitwiseAnd = &Opcode {
+ Opname: "OpBitwiseAnd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpNot = &Opcode {
+ Opname: "OpNot",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBitFieldInsert = &Opcode {
+ Opname: "OpBitFieldInsert",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Insert'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Offset'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Count'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBitFieldSExtract = &Opcode {
+ Opname: "OpBitFieldSExtract",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Offset'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Count'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBitFieldUExtract = &Opcode {
+ Opname: "OpBitFieldUExtract",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Offset'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Count'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBitReverse = &Opcode {
+ Opname: "OpBitReverse",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBitCount = &Opcode {
+ Opname: "OpBitCount",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Base'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDPdx = &Opcode {
+ Opname: "OpDPdx",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'P'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDPdy = &Opcode {
+ Opname: "OpDPdy",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'P'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFwidth = &Opcode {
+ Opname: "OpFwidth",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'P'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDPdxFine = &Opcode {
+ Opname: "OpDPdxFine",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'P'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDPdyFine = &Opcode {
+ Opname: "OpDPdyFine",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'P'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFwidthFine = &Opcode {
+ Opname: "OpFwidthFine",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'P'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDPdxCoarse = &Opcode {
+ Opname: "OpDPdxCoarse",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'P'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDPdyCoarse = &Opcode {
+ Opname: "OpDPdyCoarse",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'P'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFwidthCoarse = &Opcode {
+ Opname: "OpFwidthCoarse",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'P'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpEmitVertex = &Opcode {
+ Opname: "OpEmitVertex",
+ Operands: []Operand {
+ },
+ }
+ OpEndPrimitive = &Opcode {
+ Opname: "OpEndPrimitive",
+ Operands: []Operand {
+ },
+ }
+ OpEmitStreamVertex = &Opcode {
+ Opname: "OpEmitStreamVertex",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Stream'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpEndStreamPrimitive = &Opcode {
+ Opname: "OpEndStreamPrimitive",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Stream'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpControlBarrier = &Opcode {
+ Opname: "OpControlBarrier",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpMemoryBarrier = &Opcode {
+ Opname: "OpMemoryBarrier",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicLoad = &Opcode {
+ Opname: "OpAtomicLoad",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicStore = &Opcode {
+ Opname: "OpAtomicStore",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicExchange = &Opcode {
+ Opname: "OpAtomicExchange",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicCompareExchange = &Opcode {
+ Opname: "OpAtomicCompareExchange",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Equal'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Unequal'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Comparator'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicCompareExchangeWeak = &Opcode {
+ Opname: "OpAtomicCompareExchangeWeak",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Equal'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Unequal'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Comparator'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicIIncrement = &Opcode {
+ Opname: "OpAtomicIIncrement",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicIDecrement = &Opcode {
+ Opname: "OpAtomicIDecrement",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicIAdd = &Opcode {
+ Opname: "OpAtomicIAdd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicISub = &Opcode {
+ Opname: "OpAtomicISub",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicSMin = &Opcode {
+ Opname: "OpAtomicSMin",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicUMin = &Opcode {
+ Opname: "OpAtomicUMin",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicSMax = &Opcode {
+ Opname: "OpAtomicSMax",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicUMax = &Opcode {
+ Opname: "OpAtomicUMax",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicAnd = &Opcode {
+ Opname: "OpAtomicAnd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicOr = &Opcode {
+ Opname: "OpAtomicOr",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicXor = &Opcode {
+ Opname: "OpAtomicXor",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpPhi = &Opcode {
+ Opname: "OpPhi",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindPairIdRefIdRef,
+ Name: "'Variable, Parent, ...'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpLoopMerge = &Opcode {
+ Opname: "OpLoopMerge",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Merge Block'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Continue Target'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLoopControl,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSelectionMerge = &Opcode {
+ Opname: "OpSelectionMerge",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Merge Block'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindSelectionControl,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLabel = &Opcode {
+ Opname: "OpLabel",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBranch = &Opcode {
+ Opname: "OpBranch",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Target Label'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBranchConditional = &Opcode {
+ Opname: "OpBranchConditional",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Condition'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'True Label'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'False Label'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Branch weights'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpSwitch = &Opcode {
+ Opname: "OpSwitch",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Selector'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Default'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindPairLiteralIntegerIdRef,
+ Name: "'Target'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpKill = &Opcode {
+ Opname: "OpKill",
+ Operands: []Operand {
+ },
+ }
+ OpReturn = &Opcode {
+ Opname: "OpReturn",
+ Operands: []Operand {
+ },
+ }
+ OpReturnValue = &Opcode {
+ Opname: "OpReturnValue",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUnreachable = &Opcode {
+ Opname: "OpUnreachable",
+ Operands: []Operand {
+ },
+ }
+ OpLifetimeStart = &Opcode {
+ Opname: "OpLifetimeStart",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Size'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpLifetimeStop = &Opcode {
+ Opname: "OpLifetimeStop",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Size'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupAsyncCopy = &Opcode {
+ Opname: "OpGroupAsyncCopy",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Destination'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Source'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Num Elements'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Stride'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Event'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupWaitEvents = &Opcode {
+ Opname: "OpGroupWaitEvents",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Num Events'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Events List'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupAll = &Opcode {
+ Opname: "OpGroupAll",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Predicate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupAny = &Opcode {
+ Opname: "OpGroupAny",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Predicate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupBroadcast = &Opcode {
+ Opname: "OpGroupBroadcast",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'LocalId'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupIAdd = &Opcode {
+ Opname: "OpGroupIAdd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupFAdd = &Opcode {
+ Opname: "OpGroupFAdd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupFMin = &Opcode {
+ Opname: "OpGroupFMin",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupUMin = &Opcode {
+ Opname: "OpGroupUMin",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupSMin = &Opcode {
+ Opname: "OpGroupSMin",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupFMax = &Opcode {
+ Opname: "OpGroupFMax",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupUMax = &Opcode {
+ Opname: "OpGroupUMax",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupSMax = &Opcode {
+ Opname: "OpGroupSMax",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpReadPipe = &Opcode {
+ Opname: "OpReadPipe",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpWritePipe = &Opcode {
+ Opname: "OpWritePipe",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpReservedReadPipe = &Opcode {
+ Opname: "OpReservedReadPipe",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Reserve Id'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Index'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpReservedWritePipe = &Opcode {
+ Opname: "OpReservedWritePipe",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Reserve Id'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Index'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpReserveReadPipePackets = &Opcode {
+ Opname: "OpReserveReadPipePackets",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Num Packets'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpReserveWritePipePackets = &Opcode {
+ Opname: "OpReserveWritePipePackets",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Num Packets'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpCommitReadPipe = &Opcode {
+ Opname: "OpCommitReadPipe",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Reserve Id'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpCommitWritePipe = &Opcode {
+ Opname: "OpCommitWritePipe",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Reserve Id'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIsValidReserveId = &Opcode {
+ Opname: "OpIsValidReserveId",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Reserve Id'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGetNumPipePackets = &Opcode {
+ Opname: "OpGetNumPipePackets",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGetMaxPipePackets = &Opcode {
+ Opname: "OpGetMaxPipePackets",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupReserveReadPipePackets = &Opcode {
+ Opname: "OpGroupReserveReadPipePackets",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Num Packets'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupReserveWritePipePackets = &Opcode {
+ Opname: "OpGroupReserveWritePipePackets",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Num Packets'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupCommitReadPipe = &Opcode {
+ Opname: "OpGroupCommitReadPipe",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Reserve Id'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupCommitWritePipe = &Opcode {
+ Opname: "OpGroupCommitWritePipe",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Reserve Id'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpEnqueueMarker = &Opcode {
+ Opname: "OpEnqueueMarker",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Queue'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Num Events'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Wait Events'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ret Event'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpEnqueueKernel = &Opcode {
+ Opname: "OpEnqueueKernel",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Queue'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Flags'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ND Range'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Num Events'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Wait Events'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ret Event'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Invoke'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Align'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Local Size'",
+ Quantifier: "*",
+ },
+ },
+ }
+ OpGetKernelNDrangeSubGroupCount = &Opcode {
+ Opname: "OpGetKernelNDrangeSubGroupCount",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ND Range'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Invoke'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Align'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGetKernelNDrangeMaxSubGroupSize = &Opcode {
+ Opname: "OpGetKernelNDrangeMaxSubGroupSize",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ND Range'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Invoke'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Align'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGetKernelWorkGroupSize = &Opcode {
+ Opname: "OpGetKernelWorkGroupSize",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Invoke'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Align'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGetKernelPreferredWorkGroupSizeMultiple = &Opcode {
+ Opname: "OpGetKernelPreferredWorkGroupSizeMultiple",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Invoke'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Align'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpRetainEvent = &Opcode {
+ Opname: "OpRetainEvent",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Event'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpReleaseEvent = &Opcode {
+ Opname: "OpReleaseEvent",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Event'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpCreateUserEvent = &Opcode {
+ Opname: "OpCreateUserEvent",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIsValidEvent = &Opcode {
+ Opname: "OpIsValidEvent",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Event'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSetUserEventStatus = &Opcode {
+ Opname: "OpSetUserEventStatus",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Event'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Status'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpCaptureEventProfilingInfo = &Opcode {
+ Opname: "OpCaptureEventProfilingInfo",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Event'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Profiling Info'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGetDefaultQueue = &Opcode {
+ Opname: "OpGetDefaultQueue",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBuildNDRange = &Opcode {
+ Opname: "OpBuildNDRange",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'GlobalWorkSize'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'LocalWorkSize'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'GlobalWorkOffset'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSparseSampleImplicitLod = &Opcode {
+ Opname: "OpImageSparseSampleImplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSparseSampleExplicitLod = &Opcode {
+ Opname: "OpImageSparseSampleExplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSparseSampleDrefImplicitLod = &Opcode {
+ Opname: "OpImageSparseSampleDrefImplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSparseSampleDrefExplicitLod = &Opcode {
+ Opname: "OpImageSparseSampleDrefExplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSparseSampleProjImplicitLod = &Opcode {
+ Opname: "OpImageSparseSampleProjImplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSparseSampleProjExplicitLod = &Opcode {
+ Opname: "OpImageSparseSampleProjExplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSparseSampleProjDrefImplicitLod = &Opcode {
+ Opname: "OpImageSparseSampleProjDrefImplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSparseSampleProjDrefExplicitLod = &Opcode {
+ Opname: "OpImageSparseSampleProjDrefExplicitLod",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSparseFetch = &Opcode {
+ Opname: "OpImageSparseFetch",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSparseGather = &Opcode {
+ Opname: "OpImageSparseGather",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Component'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSparseDrefGather = &Opcode {
+ Opname: "OpImageSparseDrefGather",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'D~ref~'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpImageSparseTexelsResident = &Opcode {
+ Opname: "OpImageSparseTexelsResident",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Resident Code'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpNoLine = &Opcode {
+ Opname: "OpNoLine",
+ Operands: []Operand {
+ },
+ }
+ OpAtomicFlagTestAndSet = &Opcode {
+ Opname: "OpAtomicFlagTestAndSet",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAtomicFlagClear = &Opcode {
+ Opname: "OpAtomicFlagClear",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSparseRead = &Opcode {
+ Opname: "OpImageSparseRead",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpSizeOf = &Opcode {
+ Opname: "OpSizeOf",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypePipeStorage = &Opcode {
+ Opname: "OpTypePipeStorage",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpConstantPipeStorage = &Opcode {
+ Opname: "OpConstantPipeStorage",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Packet Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Packet Alignment'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Capacity'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpCreatePipeFromPipeStorage = &Opcode {
+ Opname: "OpCreatePipeFromPipeStorage",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pipe Storage'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGetKernelLocalSizeForSubgroupCount = &Opcode {
+ Opname: "OpGetKernelLocalSizeForSubgroupCount",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Subgroup Count'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Invoke'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Align'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGetKernelMaxNumSubgroups = &Opcode {
+ Opname: "OpGetKernelMaxNumSubgroups",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Invoke'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Param Align'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeNamedBarrier = &Opcode {
+ Opname: "OpTypeNamedBarrier",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpNamedBarrierInitialize = &Opcode {
+ Opname: "OpNamedBarrierInitialize",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Subgroup Count'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpMemoryNamedBarrier = &Opcode {
+ Opname: "OpMemoryNamedBarrier",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Named Barrier'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Memory'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdMemorySemantics,
+ Name: "'Semantics'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpModuleProcessed = &Opcode {
+ Opname: "OpModuleProcessed",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindLiteralString,
+ Name: "'Process'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpExecutionModeId = &Opcode {
+ Opname: "OpExecutionModeId",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Entry Point'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindExecutionMode,
+ Name: "'Mode'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDecorateId = &Opcode {
+ Opname: "OpDecorateId",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Target'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindDecoration,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformElect = &Opcode {
+ Opname: "OpGroupNonUniformElect",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformAll = &Opcode {
+ Opname: "OpGroupNonUniformAll",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Predicate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformAny = &Opcode {
+ Opname: "OpGroupNonUniformAny",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Predicate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformAllEqual = &Opcode {
+ Opname: "OpGroupNonUniformAllEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformBroadcast = &Opcode {
+ Opname: "OpGroupNonUniformBroadcast",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Id'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformBroadcastFirst = &Opcode {
+ Opname: "OpGroupNonUniformBroadcastFirst",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformBallot = &Opcode {
+ Opname: "OpGroupNonUniformBallot",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Predicate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformInverseBallot = &Opcode {
+ Opname: "OpGroupNonUniformInverseBallot",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformBallotBitExtract = &Opcode {
+ Opname: "OpGroupNonUniformBallotBitExtract",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Index'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformBallotBitCount = &Opcode {
+ Opname: "OpGroupNonUniformBallotBitCount",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformBallotFindLSB = &Opcode {
+ Opname: "OpGroupNonUniformBallotFindLSB",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformBallotFindMSB = &Opcode {
+ Opname: "OpGroupNonUniformBallotFindMSB",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformShuffle = &Opcode {
+ Opname: "OpGroupNonUniformShuffle",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Id'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformShuffleXor = &Opcode {
+ Opname: "OpGroupNonUniformShuffleXor",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Mask'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformShuffleUp = &Opcode {
+ Opname: "OpGroupNonUniformShuffleUp",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Delta'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformShuffleDown = &Opcode {
+ Opname: "OpGroupNonUniformShuffleDown",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Delta'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformIAdd = &Opcode {
+ Opname: "OpGroupNonUniformIAdd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformFAdd = &Opcode {
+ Opname: "OpGroupNonUniformFAdd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformIMul = &Opcode {
+ Opname: "OpGroupNonUniformIMul",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformFMul = &Opcode {
+ Opname: "OpGroupNonUniformFMul",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformSMin = &Opcode {
+ Opname: "OpGroupNonUniformSMin",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformUMin = &Opcode {
+ Opname: "OpGroupNonUniformUMin",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformFMin = &Opcode {
+ Opname: "OpGroupNonUniformFMin",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformSMax = &Opcode {
+ Opname: "OpGroupNonUniformSMax",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformUMax = &Opcode {
+ Opname: "OpGroupNonUniformUMax",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformFMax = &Opcode {
+ Opname: "OpGroupNonUniformFMax",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformBitwiseAnd = &Opcode {
+ Opname: "OpGroupNonUniformBitwiseAnd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformBitwiseOr = &Opcode {
+ Opname: "OpGroupNonUniformBitwiseOr",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformBitwiseXor = &Opcode {
+ Opname: "OpGroupNonUniformBitwiseXor",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformLogicalAnd = &Opcode {
+ Opname: "OpGroupNonUniformLogicalAnd",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformLogicalOr = &Opcode {
+ Opname: "OpGroupNonUniformLogicalOr",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformLogicalXor = &Opcode {
+ Opname: "OpGroupNonUniformLogicalXor",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'ClusterSize'",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformQuadBroadcast = &Opcode {
+ Opname: "OpGroupNonUniformQuadBroadcast",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Index'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupNonUniformQuadSwap = &Opcode {
+ Opname: "OpGroupNonUniformQuadSwap",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Direction'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpCopyLogical = &Opcode {
+ Opname: "OpCopyLogical",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpPtrEqual = &Opcode {
+ Opname: "OpPtrEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpPtrNotEqual = &Opcode {
+ Opname: "OpPtrNotEqual",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpPtrDiff = &Opcode {
+ Opname: "OpPtrDiff",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupBallotKHR = &Opcode {
+ Opname: "OpSubgroupBallotKHR",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Predicate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupFirstInvocationKHR = &Opcode {
+ Opname: "OpSubgroupFirstInvocationKHR",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAllKHR = &Opcode {
+ Opname: "OpSubgroupAllKHR",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Predicate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAnyKHR = &Opcode {
+ Opname: "OpSubgroupAnyKHR",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Predicate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAllEqualKHR = &Opcode {
+ Opname: "OpSubgroupAllEqualKHR",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Predicate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupReadInvocationKHR = &Opcode {
+ Opname: "OpSubgroupReadInvocationKHR",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Index'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupIAddNonUniformAMD = &Opcode {
+ Opname: "OpGroupIAddNonUniformAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupFAddNonUniformAMD = &Opcode {
+ Opname: "OpGroupFAddNonUniformAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupFMinNonUniformAMD = &Opcode {
+ Opname: "OpGroupFMinNonUniformAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupUMinNonUniformAMD = &Opcode {
+ Opname: "OpGroupUMinNonUniformAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupSMinNonUniformAMD = &Opcode {
+ Opname: "OpGroupSMinNonUniformAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupFMaxNonUniformAMD = &Opcode {
+ Opname: "OpGroupFMaxNonUniformAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupUMaxNonUniformAMD = &Opcode {
+ Opname: "OpGroupUMaxNonUniformAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpGroupSMaxNonUniformAMD = &Opcode {
+ Opname: "OpGroupSMaxNonUniformAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindGroupOperation,
+ Name: "'Operation'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'X'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFragmentMaskFetchAMD = &Opcode {
+ Opname: "OpFragmentMaskFetchAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpFragmentFetchAMD = &Opcode {
+ Opname: "OpFragmentFetchAMD",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Fragment Index'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpReadClockKHR = &Opcode {
+ Opname: "OpReadClockKHR",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpImageSampleFootprintNV = &Opcode {
+ Opname: "OpImageSampleFootprintNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampled Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Granularity'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coarse'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindImageOperands,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpGroupNonUniformPartitionNV = &Opcode {
+ Opname: "OpGroupNonUniformPartitionNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpWritePackedPrimitiveIndices4x8NV = &Opcode {
+ Opname: "OpWritePackedPrimitiveIndices4x8NV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Index Offset'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Indices'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpReportIntersectionNV = &Opcode {
+ Opname: "OpReportIntersectionNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Hit'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'HitKind'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIgnoreIntersectionNV = &Opcode {
+ Opname: "OpIgnoreIntersectionNV",
+ Operands: []Operand {
+ },
+ }
+ OpTerminateRayNV = &Opcode {
+ Opname: "OpTerminateRayNV",
+ Operands: []Operand {
+ },
+ }
+ OpTraceNV = &Opcode {
+ Opname: "OpTraceNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Accel'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ray Flags'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Cull Mask'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'SBT Offset'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'SBT Stride'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Miss Index'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ray Origin'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ray Tmin'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ray Direction'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ray Tmax'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'PayloadId'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAccelerationStructureNV = &Opcode {
+ Opname: "OpTypeAccelerationStructureNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpExecuteCallableNV = &Opcode {
+ Opname: "OpExecuteCallableNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'SBT Index'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Callable DataId'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeCooperativeMatrixNV = &Opcode {
+ Opname: "OpTypeCooperativeMatrixNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Component Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdScope,
+ Name: "'Execution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Rows'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Columns'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpCooperativeMatrixLoadNV = &Opcode {
+ Opname: "OpCooperativeMatrixLoadNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Stride'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Column Major'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindMemoryAccess,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpCooperativeMatrixStoreNV = &Opcode {
+ Opname: "OpCooperativeMatrixStoreNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pointer'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Object'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Stride'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Column Major'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindMemoryAccess,
+ Name: "",
+ Quantifier: "?",
+ },
+ },
+ }
+ OpCooperativeMatrixMulAddNV = &Opcode {
+ Opname: "OpCooperativeMatrixMulAddNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'A'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'B'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'C'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpCooperativeMatrixLengthNV = &Opcode {
+ Opname: "OpCooperativeMatrixLengthNV",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Type'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpBeginInvocationInterlockEXT = &Opcode {
+ Opname: "OpBeginInvocationInterlockEXT",
+ Operands: []Operand {
+ },
+ }
+ OpEndInvocationInterlockEXT = &Opcode {
+ Opname: "OpEndInvocationInterlockEXT",
+ Operands: []Operand {
+ },
+ }
+ OpDemoteToHelperInvocationEXT = &Opcode {
+ Opname: "OpDemoteToHelperInvocationEXT",
+ Operands: []Operand {
+ },
+ }
+ OpIsHelperInvocationEXT = &Opcode {
+ Opname: "OpIsHelperInvocationEXT",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupShuffleINTEL = &Opcode {
+ Opname: "OpSubgroupShuffleINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Data'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'InvocationId'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupShuffleDownINTEL = &Opcode {
+ Opname: "OpSubgroupShuffleDownINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Current'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Next'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Delta'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupShuffleUpINTEL = &Opcode {
+ Opname: "OpSubgroupShuffleUpINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Previous'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Current'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Delta'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupShuffleXorINTEL = &Opcode {
+ Opname: "OpSubgroupShuffleXorINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Data'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Value'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupBlockReadINTEL = &Opcode {
+ Opname: "OpSubgroupBlockReadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ptr'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupBlockWriteINTEL = &Opcode {
+ Opname: "OpSubgroupBlockWriteINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ptr'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Data'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupImageBlockReadINTEL = &Opcode {
+ Opname: "OpSubgroupImageBlockReadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupImageBlockWriteINTEL = &Opcode {
+ Opname: "OpSubgroupImageBlockWriteINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Data'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupImageMediaBlockReadINTEL = &Opcode {
+ Opname: "OpSubgroupImageMediaBlockReadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Width'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Height'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupImageMediaBlockWriteINTEL = &Opcode {
+ Opname: "OpSubgroupImageMediaBlockWriteINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Coordinate'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Width'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Height'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Data'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUCountLeadingZerosINTEL = &Opcode {
+ Opname: "OpUCountLeadingZerosINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUCountTrailingZerosINTEL = &Opcode {
+ Opname: "OpUCountTrailingZerosINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAbsISubINTEL = &Opcode {
+ Opname: "OpAbsISubINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpAbsUSubINTEL = &Opcode {
+ Opname: "OpAbsUSubINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIAddSatINTEL = &Opcode {
+ Opname: "OpIAddSatINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUAddSatINTEL = &Opcode {
+ Opname: "OpUAddSatINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIAverageINTEL = &Opcode {
+ Opname: "OpIAverageINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUAverageINTEL = &Opcode {
+ Opname: "OpUAverageINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIAverageRoundedINTEL = &Opcode {
+ Opname: "OpIAverageRoundedINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUAverageRoundedINTEL = &Opcode {
+ Opname: "OpUAverageRoundedINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpISubSatINTEL = &Opcode {
+ Opname: "OpISubSatINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUSubSatINTEL = &Opcode {
+ Opname: "OpUSubSatINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpIMul32x16INTEL = &Opcode {
+ Opname: "OpIMul32x16INTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpUMul32x16INTEL = &Opcode {
+ Opname: "OpUMul32x16INTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 1'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Operand 2'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDecorateString = &Opcode {
+ Opname: "OpDecorateString",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Target'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindDecoration,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpDecorateStringGOOGLE = &Opcode {
+ Opname: "OpDecorateStringGOOGLE",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Target'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindDecoration,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpMemberDecorateString = &Opcode {
+ Opname: "OpMemberDecorateString",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Struct Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Member'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindDecoration,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpMemberDecorateStringGOOGLE = &Opcode {
+ Opname: "OpMemberDecorateStringGOOGLE",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Struct Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindLiteralInteger,
+ Name: "'Member'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindDecoration,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpVmeImageINTEL = &Opcode {
+ Opname: "OpVmeImageINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sampler'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeVmeImageINTEL = &Opcode {
+ Opname: "OpTypeVmeImageINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image Type'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcImePayloadINTEL = &Opcode {
+ Opname: "OpTypeAvcImePayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcRefPayloadINTEL = &Opcode {
+ Opname: "OpTypeAvcRefPayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcSicPayloadINTEL = &Opcode {
+ Opname: "OpTypeAvcSicPayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcMcePayloadINTEL = &Opcode {
+ Opname: "OpTypeAvcMcePayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcMceResultINTEL = &Opcode {
+ Opname: "OpTypeAvcMceResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcImeResultINTEL = &Opcode {
+ Opname: "OpTypeAvcImeResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcImeResultSingleReferenceStreamoutINTEL = &Opcode {
+ Opname: "OpTypeAvcImeResultSingleReferenceStreamoutINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcImeResultDualReferenceStreamoutINTEL = &Opcode {
+ Opname: "OpTypeAvcImeResultDualReferenceStreamoutINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcImeSingleReferenceStreaminINTEL = &Opcode {
+ Opname: "OpTypeAvcImeSingleReferenceStreaminINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcImeDualReferenceStreaminINTEL = &Opcode {
+ Opname: "OpTypeAvcImeDualReferenceStreaminINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcRefResultINTEL = &Opcode {
+ Opname: "OpTypeAvcRefResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpTypeAvcSicResultINTEL = &Opcode {
+ Opname: "OpTypeAvcSicResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Slice Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Qp'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Reference Base Penalty'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Slice Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Qp'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceSetInterShapePenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceSetInterShapePenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Shape Penalty'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Slice Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Qp'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceSetInterDirectionPenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Direction Cost'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Slice Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Qp'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Slice Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Qp'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Cost Center Delta'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Cost Table'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Cost Precision'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Slice Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Qp'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceSetAcOnlyHaarINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceSetAcOnlyHaarINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Source Field Polarity'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Reference Field Polarity'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Forward Reference Field Polarity'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Backward Reference Field Polarity'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceConvertToImePayloadINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceConvertToImePayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceConvertToImeResultINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceConvertToImeResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceConvertToRefPayloadINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceConvertToRefPayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceConvertToRefResultINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceConvertToRefResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceConvertToSicPayloadINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceConvertToSicPayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceConvertToSicResultINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceConvertToSicResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetMotionVectorsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetMotionVectorsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetInterDistortionsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetInterDistortionsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetBestInterDistortionsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetBestInterDistortionsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetInterMajorShapeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetInterMajorShapeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetInterMinorShapeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetInterMinorShapeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetInterDirectionsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetInterDirectionsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetInterMotionVectorCountINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetInterMotionVectorCountINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetInterReferenceIdsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetInterReferenceIdsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = &Opcode {
+ Opname: "OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Reference Ids'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Reference Parameter Field Polarities'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeInitializeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeInitializeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Coord'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Partition Mask'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'SAD Adjustment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeSetSingleReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeSetSingleReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ref Offset'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Search Window Config'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeSetDualReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeSetDualReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Fwd Ref Offset'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Bwd Ref Offset'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'id> Search Window Config'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeRefWindowSizeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeRefWindowSizeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Search Window Config'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Dual Ref'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeAdjustRefOffsetINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeAdjustRefOffsetINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ref Offset'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Coord'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ref Window Size'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image Size'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeConvertToMcePayloadINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeConvertToMcePayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeSetMaxMotionVectorCountINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Max Motion Vector Count'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Threshold'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeSetWeightedSadINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeSetWeightedSadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Sad Weights'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeEvaluateWithDualReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Fwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Bwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Streamin Components'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Fwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Bwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Streamin Components'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Fwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Bwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Streamin Components'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Fwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Bwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Streamin Components'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeConvertToMceResultINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeConvertToMceResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetSingleReferenceStreaminINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetDualReferenceStreaminINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetDualReferenceStreaminINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeStripDualReferenceStreamoutINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Major Shape'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Major Shape'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Major Shape'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Major Shape'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Direction'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Major Shape'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Direction'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Major Shape'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Direction'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetBorderReachedINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetBorderReachedINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Image Select'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = &Opcode {
+ Opname: "OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcFmeInitializeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcFmeInitializeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Coord'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Motion Vectors'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Major Shapes'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Minor Shapes'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Direction'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pixel Resolution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sad Adjustment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcBmeInitializeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcBmeInitializeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Coord'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Motion Vectors'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Major Shapes'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Minor Shapes'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Direction'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Pixel Resolution'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Bidirectional Weight'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sad Adjustment'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcRefConvertToMcePayloadINTEL = &Opcode {
+ Opname: "OpSubgroupAvcRefConvertToMcePayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = &Opcode {
+ Opname: "OpSubgroupAvcRefSetBidirectionalMixDisableINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcRefSetBilinearFilterEnableINTEL = &Opcode {
+ Opname: "OpSubgroupAvcRefSetBilinearFilterEnableINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcRefEvaluateWithDualReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Fwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Bwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Reference Ids'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = &Opcode {
+ Opname: "OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Reference Ids'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Reference Field Polarities'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcRefConvertToMceResultINTEL = &Opcode {
+ Opname: "OpSubgroupAvcRefConvertToMceResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicInitializeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicInitializeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Coord'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicConfigureSkcINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicConfigureSkcINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Skip Block Partition Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Skip Motion Vector Mask'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Motion Vectors'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Bidirectional Weight'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sad Adjustment'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicConfigureIpeLumaINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicConfigureIpeLumaINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Luma Intra Partition Mask'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Intra Neighbour Availabilty'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Left Edge Luma Pixels'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Upper Left Corner Luma Pixel'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Upper Edge Luma Pixels'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Upper Right Edge Luma Pixels'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sad Adjustment'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicConfigureIpeLumaChromaINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Luma Intra Partition Mask'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Intra Neighbour Availabilty'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Left Edge Luma Pixels'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Upper Left Corner Luma Pixel'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Upper Edge Luma Pixels'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Upper Right Edge Luma Pixels'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Left Edge Chroma Pixels'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Upper Left Corner Chroma Pixel'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Upper Edge Chroma Pixels'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Sad Adjustment'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicGetMotionVectorMaskINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicGetMotionVectorMaskINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Skip Block Partition Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Direction'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicConvertToMcePayloadINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicConvertToMcePayloadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Shape Penalty'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Luma Mode Penalty'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Luma Packed Neighbor Modes'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Luma Packed Non Dc Penalty'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Chroma Mode Base Penalty'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicSetBilinearFilterEnableINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicSetBilinearFilterEnableINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Sad Coefficients'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Block Based Skip Type'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicEvaluateIpeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicEvaluateIpeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicEvaluateWithDualReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Fwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Bwd Ref Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Reference Ids'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Src Image'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Reference Ids'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Packed Reference Field Polarities'",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicConvertToMceResultINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicConvertToMceResultINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicGetIpeLumaShapeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicGetIpeLumaShapeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicGetPackedIpeLumaModesINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicGetIpeChromaModeINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicGetIpeChromaModeINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+ OpSubgroupAvcSicGetInterRawSadsINTEL = &Opcode {
+ Opname: "OpSubgroupAvcSicGetInterRawSadsINTEL",
+ Operands: []Operand {
+ Operand {
+ Kind: OperandKindIdResultType,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdResult,
+ Name: "",
+ Quantifier: "",
+ },
+ Operand {
+ Kind: OperandKindIdRef,
+ Name: "'Payload'",
+ Quantifier: "",
+ },
+ },
+ }
+
+
+ OperandKindImageOperands = &OperandKind {
+ Kind: "ImageOperands",
+ Category: "BitEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "None",
+ Value: 0x0000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Bias",
+ Value: 0x0001,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{{OperandKindIdRef, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Lod",
+ Value: 0x0002,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindIdRef, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Grad",
+ Value: 0x0004,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindIdRef, ""},{OperandKindIdRef, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ConstOffset",
+ Value: 0x0008,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindIdRef, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Offset",
+ Value: 0x0010,
+ Capabilities: []string{"ImageGatherExtended",},
+ Parameters: []Parameter{{OperandKindIdRef, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ConstOffsets",
+ Value: 0x0020,
+ Capabilities: []string{"ImageGatherExtended",},
+ Parameters: []Parameter{{OperandKindIdRef, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Sample",
+ Value: 0x0040,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindIdRef, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "MinLod",
+ Value: 0x0080,
+ Capabilities: []string{"MinLod",},
+ Parameters: []Parameter{{OperandKindIdRef, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "MakeTexelAvailable",
+ Value: 0x0100,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{{OperandKindIdScope, ""},},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakeTexelAvailableKHR",
+ Value: 0x0100,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{{OperandKindIdScope, ""},},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakeTexelVisible",
+ Value: 0x0200,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{{OperandKindIdScope, ""},},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakeTexelVisibleKHR",
+ Value: 0x0200,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{{OperandKindIdScope, ""},},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "NonPrivateTexel",
+ Value: 0x0400,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "NonPrivateTexelKHR",
+ Value: 0x0400,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "VolatileTexel",
+ Value: 0x0800,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "VolatileTexelKHR",
+ Value: 0x0800,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "SignExtend",
+ Value: 0x1000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "ZeroExtend",
+ Value: 0x2000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.4",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindFPFastMathMode = &OperandKind {
+ Kind: "FPFastMathMode",
+ Category: "BitEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "None",
+ Value: 0x0000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NotNaN",
+ Value: 0x0001,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NotInf",
+ Value: 0x0002,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NSZ",
+ Value: 0x0004,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "AllowRecip",
+ Value: 0x0008,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Fast",
+ Value: 0x0010,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindSelectionControl = &OperandKind {
+ Kind: "SelectionControl",
+ Category: "BitEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "None",
+ Value: 0x0000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Flatten",
+ Value: 0x0001,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DontFlatten",
+ Value: 0x0002,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindLoopControl = &OperandKind {
+ Kind: "LoopControl",
+ Category: "BitEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "None",
+ Value: 0x0000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Unroll",
+ Value: 0x0001,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DontUnroll",
+ Value: 0x0002,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DependencyInfinite",
+ Value: 0x0004,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "DependencyLength",
+ Value: 0x0008,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralInteger, ""},},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "MinIterations",
+ Value: 0x0010,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralInteger, ""},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "MaxIterations",
+ Value: 0x0020,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralInteger, ""},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "IterationMultiple",
+ Value: 0x0040,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralInteger, ""},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "PeelCount",
+ Value: 0x0080,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralInteger, ""},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "PartialCount",
+ Value: 0x0100,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralInteger, ""},},
+ Version: "1.4",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindFunctionControl = &OperandKind {
+ Kind: "FunctionControl",
+ Category: "BitEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "None",
+ Value: 0x0000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Inline",
+ Value: 0x0001,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DontInline",
+ Value: 0x0002,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Pure",
+ Value: 0x0004,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Const",
+ Value: 0x0008,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindMemorySemantics = &OperandKind {
+ Kind: "MemorySemantics",
+ Category: "BitEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Relaxed",
+ Value: 0x0000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "None",
+ Value: 0x0000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Acquire",
+ Value: 0x0002,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Release",
+ Value: 0x0004,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "AcquireRelease",
+ Value: 0x0008,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SequentiallyConsistent",
+ Value: 0x0010,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UniformMemory",
+ Value: 0x0040,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SubgroupMemory",
+ Value: 0x0080,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "WorkgroupMemory",
+ Value: 0x0100,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "CrossWorkgroupMemory",
+ Value: 0x0200,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "AtomicCounterMemory",
+ Value: 0x0400,
+ Capabilities: []string{"AtomicStorage",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageMemory",
+ Value: 0x0800,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OutputMemory",
+ Value: 0x1000,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "OutputMemoryKHR",
+ Value: 0x1000,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakeAvailable",
+ Value: 0x2000,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakeAvailableKHR",
+ Value: 0x2000,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakeVisible",
+ Value: 0x4000,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakeVisibleKHR",
+ Value: 0x4000,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "Volatile",
+ Value: 0x8000,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindMemoryAccess = &OperandKind {
+ Kind: "MemoryAccess",
+ Category: "BitEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "None",
+ Value: 0x0000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Volatile",
+ Value: 0x0001,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Aligned",
+ Value: 0x0002,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralInteger, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Nontemporal",
+ Value: 0x0004,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "MakePointerAvailable",
+ Value: 0x0008,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{{OperandKindIdScope, ""},},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakePointerAvailableKHR",
+ Value: 0x0008,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{{OperandKindIdScope, ""},},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakePointerVisible",
+ Value: 0x0010,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{{OperandKindIdScope, ""},},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "MakePointerVisibleKHR",
+ Value: 0x0010,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{{OperandKindIdScope, ""},},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "NonPrivatePointer",
+ Value: 0x0020,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "NonPrivatePointerKHR",
+ Value: 0x0020,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindKernelProfilingInfo = &OperandKind {
+ Kind: "KernelProfilingInfo",
+ Category: "BitEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "None",
+ Value: 0x0000,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "CmdExecTime",
+ Value: 0x0001,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindSourceLanguage = &OperandKind {
+ Kind: "SourceLanguage",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Unknown",
+ Value: 0,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ESSL",
+ Value: 1,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GLSL",
+ Value: 2,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OpenCL_C",
+ Value: 3,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OpenCL_CPP",
+ Value: 4,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "HLSL",
+ Value: 5,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindExecutionModel = &OperandKind {
+ Kind: "ExecutionModel",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Vertex",
+ Value: 0,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "TessellationControl",
+ Value: 1,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "TessellationEvaluation",
+ Value: 2,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Geometry",
+ Value: 3,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Fragment",
+ Value: 4,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GLCompute",
+ Value: 5,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Kernel",
+ Value: 6,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "TaskNV",
+ Value: 5267,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "MeshNV",
+ Value: 5268,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "RayGenerationNV",
+ Value: 5313,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "IntersectionNV",
+ Value: 5314,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "AnyHitNV",
+ Value: 5315,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ClosestHitNV",
+ Value: 5316,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "MissNV",
+ Value: 5317,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "CallableNV",
+ Value: 5318,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindAddressingModel = &OperandKind {
+ Kind: "AddressingModel",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Logical",
+ Value: 0,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Physical32",
+ Value: 1,
+ Capabilities: []string{"Addresses",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Physical64",
+ Value: 2,
+ Capabilities: []string{"Addresses",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "PhysicalStorageBuffer64",
+ Value: 5348,
+ Capabilities: []string{"PhysicalStorageBufferAddresses",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "PhysicalStorageBuffer64EXT",
+ Value: 5348,
+ Capabilities: []string{"PhysicalStorageBufferAddresses",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindMemoryModel = &OperandKind {
+ Kind: "MemoryModel",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Simple",
+ Value: 0,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GLSL450",
+ Value: 1,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OpenCL",
+ Value: 2,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Vulkan",
+ Value: 3,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "VulkanKHR",
+ Value: 3,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindExecutionMode = &OperandKind {
+ Kind: "ExecutionMode",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Invocations",
+ Value: 0,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Number of <<Invocation,invocations>>'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SpacingEqual",
+ Value: 1,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SpacingFractionalEven",
+ Value: 2,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SpacingFractionalOdd",
+ Value: 3,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "VertexOrderCw",
+ Value: 4,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "VertexOrderCcw",
+ Value: 5,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "PixelCenterInteger",
+ Value: 6,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OriginUpperLeft",
+ Value: 7,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OriginLowerLeft",
+ Value: 8,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "EarlyFragmentTests",
+ Value: 9,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "PointMode",
+ Value: 10,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Xfb",
+ Value: 11,
+ Capabilities: []string{"TransformFeedback",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DepthReplacing",
+ Value: 12,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DepthGreater",
+ Value: 14,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DepthLess",
+ Value: 15,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DepthUnchanged",
+ Value: 16,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "LocalSize",
+ Value: 17,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'x size'"},{OperandKindLiteralInteger, "'y size'"},{OperandKindLiteralInteger, "'z size'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "LocalSizeHint",
+ Value: 18,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'x size'"},{OperandKindLiteralInteger, "'y size'"},{OperandKindLiteralInteger, "'z size'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InputPoints",
+ Value: 19,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InputLines",
+ Value: 20,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InputLinesAdjacency",
+ Value: 21,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Triangles",
+ Value: 22,
+ Capabilities: []string{"Geometry","Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InputTrianglesAdjacency",
+ Value: 23,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Quads",
+ Value: 24,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Isolines",
+ Value: 25,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OutputVertices",
+ Value: 26,
+ Capabilities: []string{"Geometry","Tessellation","MeshShadingNV",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Vertex count'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OutputPoints",
+ Value: 27,
+ Capabilities: []string{"Geometry","MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OutputLineStrip",
+ Value: 28,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "OutputTriangleStrip",
+ Value: 29,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "VecTypeHint",
+ Value: 30,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Vector type'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ContractionOff",
+ Value: 31,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Initializer",
+ Value: 33,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "Finalizer",
+ Value: 34,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "SubgroupSize",
+ Value: 35,
+ Capabilities: []string{"SubgroupDispatch",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Subgroup Size'"},},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "SubgroupsPerWorkgroup",
+ Value: 36,
+ Capabilities: []string{"SubgroupDispatch",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Subgroups Per Workgroup'"},},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "SubgroupsPerWorkgroupId",
+ Value: 37,
+ Capabilities: []string{"SubgroupDispatch",},
+ Parameters: []Parameter{{OperandKindIdRef, "'Subgroups Per Workgroup'"},},
+ Version: "1.2",
+ },
+ Enumerant{
+ Enumerant: "LocalSizeId",
+ Value: 38,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindIdRef, "'x size'"},{OperandKindIdRef, "'y size'"},{OperandKindIdRef, "'z size'"},},
+ Version: "1.2",
+ },
+ Enumerant{
+ Enumerant: "LocalSizeHintId",
+ Value: 39,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{{OperandKindIdRef, "'Local Size Hint'"},},
+ Version: "1.2",
+ },
+ Enumerant{
+ Enumerant: "PostDepthCoverage",
+ Value: 4446,
+ Capabilities: []string{"SampleMaskPostDepthCoverage",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "DenormPreserve",
+ Value: 4459,
+ Capabilities: []string{"DenormPreserve",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "DenormFlushToZero",
+ Value: 4460,
+ Capabilities: []string{"DenormFlushToZero",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "SignedZeroInfNanPreserve",
+ Value: 4461,
+ Capabilities: []string{"SignedZeroInfNanPreserve",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "RoundingModeRTE",
+ Value: 4462,
+ Capabilities: []string{"RoundingModeRTE",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "RoundingModeRTZ",
+ Value: 4463,
+ Capabilities: []string{"RoundingModeRTZ",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "StencilRefReplacingEXT",
+ Value: 5027,
+ Capabilities: []string{"StencilExportEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "OutputLinesNV",
+ Value: 5269,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "OutputPrimitivesNV",
+ Value: 5270,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Primitive count'"},},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "DerivativeGroupQuadsNV",
+ Value: 5289,
+ Capabilities: []string{"ComputeDerivativeGroupQuadsNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "DerivativeGroupLinearNV",
+ Value: 5290,
+ Capabilities: []string{"ComputeDerivativeGroupLinearNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "OutputTrianglesNV",
+ Value: 5298,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PixelInterlockOrderedEXT",
+ Value: 5366,
+ Capabilities: []string{"FragmentShaderPixelInterlockEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PixelInterlockUnorderedEXT",
+ Value: 5367,
+ Capabilities: []string{"FragmentShaderPixelInterlockEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SampleInterlockOrderedEXT",
+ Value: 5368,
+ Capabilities: []string{"FragmentShaderSampleInterlockEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SampleInterlockUnorderedEXT",
+ Value: 5369,
+ Capabilities: []string{"FragmentShaderSampleInterlockEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShadingRateInterlockOrderedEXT",
+ Value: 5370,
+ Capabilities: []string{"FragmentShaderShadingRateInterlockEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShadingRateInterlockUnorderedEXT",
+ Value: 5371,
+ Capabilities: []string{"FragmentShaderShadingRateInterlockEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindStorageClass = &OperandKind {
+ Kind: "StorageClass",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "UniformConstant",
+ Value: 0,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Input",
+ Value: 1,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Uniform",
+ Value: 2,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Output",
+ Value: 3,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Workgroup",
+ Value: 4,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "CrossWorkgroup",
+ Value: 5,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Private",
+ Value: 6,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Function",
+ Value: 7,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Generic",
+ Value: 8,
+ Capabilities: []string{"GenericPointer",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "PushConstant",
+ Value: 9,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "AtomicCounter",
+ Value: 10,
+ Capabilities: []string{"AtomicStorage",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Image",
+ Value: 11,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "StorageBuffer",
+ Value: 12,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "CallableDataNV",
+ Value: 5328,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "IncomingCallableDataNV",
+ Value: 5329,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "RayPayloadNV",
+ Value: 5338,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "HitAttributeNV",
+ Value: 5339,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "IncomingRayPayloadNV",
+ Value: 5342,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShaderRecordBufferNV",
+ Value: 5343,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PhysicalStorageBuffer",
+ Value: 5349,
+ Capabilities: []string{"PhysicalStorageBufferAddresses",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "PhysicalStorageBufferEXT",
+ Value: 5349,
+ Capabilities: []string{"PhysicalStorageBufferAddresses",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindDim = &OperandKind {
+ Kind: "Dim",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "1D",
+ Value: 0,
+ Capabilities: []string{"Sampled1D","Image1D",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "2D",
+ Value: 1,
+ Capabilities: []string{"Shader","Kernel","ImageMSArray",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "3D",
+ Value: 2,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Cube",
+ Value: 3,
+ Capabilities: []string{"Shader","ImageCubeArray",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rect",
+ Value: 4,
+ Capabilities: []string{"SampledRect","ImageRect",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Buffer",
+ Value: 5,
+ Capabilities: []string{"SampledBuffer","ImageBuffer",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SubpassData",
+ Value: 6,
+ Capabilities: []string{"InputAttachment",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindSamplerAddressingMode = &OperandKind {
+ Kind: "SamplerAddressingMode",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "None",
+ Value: 0,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ClampToEdge",
+ Value: 1,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Clamp",
+ Value: 2,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Repeat",
+ Value: 3,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RepeatMirrored",
+ Value: 4,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindSamplerFilterMode = &OperandKind {
+ Kind: "SamplerFilterMode",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Nearest",
+ Value: 0,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Linear",
+ Value: 1,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindImageFormat = &OperandKind {
+ Kind: "ImageFormat",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Unknown",
+ Value: 0,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba32f",
+ Value: 1,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba16f",
+ Value: 2,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R32f",
+ Value: 3,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba8",
+ Value: 4,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba8Snorm",
+ Value: 5,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg32f",
+ Value: 6,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg16f",
+ Value: 7,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R11fG11fB10f",
+ Value: 8,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R16f",
+ Value: 9,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba16",
+ Value: 10,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgb10A2",
+ Value: 11,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg16",
+ Value: 12,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg8",
+ Value: 13,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R16",
+ Value: 14,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R8",
+ Value: 15,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba16Snorm",
+ Value: 16,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg16Snorm",
+ Value: 17,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg8Snorm",
+ Value: 18,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R16Snorm",
+ Value: 19,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R8Snorm",
+ Value: 20,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba32i",
+ Value: 21,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba16i",
+ Value: 22,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba8i",
+ Value: 23,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R32i",
+ Value: 24,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg32i",
+ Value: 25,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg16i",
+ Value: 26,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg8i",
+ Value: 27,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R16i",
+ Value: 28,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R8i",
+ Value: 29,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba32ui",
+ Value: 30,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba16ui",
+ Value: 31,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgba8ui",
+ Value: 32,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R32ui",
+ Value: 33,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rgb10a2ui",
+ Value: 34,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg32ui",
+ Value: 35,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg16ui",
+ Value: 36,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rg8ui",
+ Value: 37,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R16ui",
+ Value: 38,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "R8ui",
+ Value: 39,
+ Capabilities: []string{"StorageImageExtendedFormats",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindImageChannelOrder = &OperandKind {
+ Kind: "ImageChannelOrder",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "R",
+ Value: 0,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "A",
+ Value: 1,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RG",
+ Value: 2,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RA",
+ Value: 3,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RGB",
+ Value: 4,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RGBA",
+ Value: 5,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "BGRA",
+ Value: 6,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ARGB",
+ Value: 7,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Intensity",
+ Value: 8,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Luminance",
+ Value: 9,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Rx",
+ Value: 10,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RGx",
+ Value: 11,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RGBx",
+ Value: 12,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Depth",
+ Value: 13,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DepthStencil",
+ Value: 14,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "sRGB",
+ Value: 15,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "sRGBx",
+ Value: 16,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "sRGBA",
+ Value: 17,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "sBGRA",
+ Value: 18,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ABGR",
+ Value: 19,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindImageChannelDataType = &OperandKind {
+ Kind: "ImageChannelDataType",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "SnormInt8",
+ Value: 0,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SnormInt16",
+ Value: 1,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnormInt8",
+ Value: 2,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnormInt16",
+ Value: 3,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnormShort565",
+ Value: 4,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnormShort555",
+ Value: 5,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnormInt101010",
+ Value: 6,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SignedInt8",
+ Value: 7,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SignedInt16",
+ Value: 8,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SignedInt32",
+ Value: 9,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnsignedInt8",
+ Value: 10,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnsignedInt16",
+ Value: 11,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnsignedInt32",
+ Value: 12,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "HalfFloat",
+ Value: 13,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Float",
+ Value: 14,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnormInt24",
+ Value: 15,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UnormInt101010_2",
+ Value: 16,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindFPRoundingMode = &OperandKind {
+ Kind: "FPRoundingMode",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "RTE",
+ Value: 0,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RTZ",
+ Value: 1,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RTP",
+ Value: 2,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RTN",
+ Value: 3,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindLinkageType = &OperandKind {
+ Kind: "LinkageType",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Export",
+ Value: 0,
+ Capabilities: []string{"Linkage",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Import",
+ Value: 1,
+ Capabilities: []string{"Linkage",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindAccessQualifier = &OperandKind {
+ Kind: "AccessQualifier",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "ReadOnly",
+ Value: 0,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "WriteOnly",
+ Value: 1,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ReadWrite",
+ Value: 2,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindFunctionParameterAttribute = &OperandKind {
+ Kind: "FunctionParameterAttribute",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Zext",
+ Value: 0,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Sext",
+ Value: 1,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ByVal",
+ Value: 2,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Sret",
+ Value: 3,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NoAlias",
+ Value: 4,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NoCapture",
+ Value: 5,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NoWrite",
+ Value: 6,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NoReadWrite",
+ Value: 7,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindDecoration = &OperandKind {
+ Kind: "Decoration",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "RelaxedPrecision",
+ Value: 0,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SpecId",
+ Value: 1,
+ Capabilities: []string{"Shader","Kernel",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Specialization Constant ID'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Block",
+ Value: 2,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "BufferBlock",
+ Value: 3,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "RowMajor",
+ Value: 4,
+ Capabilities: []string{"Matrix",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ColMajor",
+ Value: 5,
+ Capabilities: []string{"Matrix",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ArrayStride",
+ Value: 6,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Array Stride'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "MatrixStride",
+ Value: 7,
+ Capabilities: []string{"Matrix",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Matrix Stride'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GLSLShared",
+ Value: 8,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GLSLPacked",
+ Value: 9,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "CPacked",
+ Value: 10,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "BuiltIn",
+ Value: 11,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindBuiltIn, ""},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NoPerspective",
+ Value: 13,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Flat",
+ Value: 14,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Patch",
+ Value: 15,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Centroid",
+ Value: 16,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Sample",
+ Value: 17,
+ Capabilities: []string{"SampleRateShading",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Invariant",
+ Value: 18,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Restrict",
+ Value: 19,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Aliased",
+ Value: 20,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Volatile",
+ Value: 21,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Constant",
+ Value: 22,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Coherent",
+ Value: 23,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NonWritable",
+ Value: 24,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NonReadable",
+ Value: 25,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Uniform",
+ Value: 26,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UniformId",
+ Value: 27,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{{OperandKindIdScope, "'Execution'"},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "SaturatedConversion",
+ Value: 28,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Stream",
+ Value: 29,
+ Capabilities: []string{"GeometryStreams",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Stream Number'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Location",
+ Value: 30,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Location'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Component",
+ Value: 31,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Component'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Index",
+ Value: 32,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Index'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Binding",
+ Value: 33,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Binding Point'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DescriptorSet",
+ Value: 34,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Descriptor Set'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Offset",
+ Value: 35,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Byte Offset'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "XfbBuffer",
+ Value: 36,
+ Capabilities: []string{"TransformFeedback",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'XFB Buffer Number'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "XfbStride",
+ Value: 37,
+ Capabilities: []string{"TransformFeedback",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'XFB Stride'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "FuncParamAttr",
+ Value: 38,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{{OperandKindFunctionParameterAttribute, "'Function Parameter Attribute'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "FPRoundingMode",
+ Value: 39,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindFPRoundingMode, "'Floating-Point Rounding Mode'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "FPFastMathMode",
+ Value: 40,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{{OperandKindFPFastMathMode, "'Fast-Math Mode'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "LinkageAttributes",
+ Value: 41,
+ Capabilities: []string{"Linkage",},
+ Parameters: []Parameter{{OperandKindLiteralString, "'Name'"},{OperandKindLinkageType, "'Linkage Type'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NoContraction",
+ Value: 42,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InputAttachmentIndex",
+ Value: 43,
+ Capabilities: []string{"InputAttachment",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Attachment Index'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Alignment",
+ Value: 44,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Alignment'"},},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "MaxByteOffset",
+ Value: 45,
+ Capabilities: []string{"Addresses",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Max Byte Offset'"},},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "AlignmentId",
+ Value: 46,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{{OperandKindIdRef, "'Alignment'"},},
+ Version: "1.2",
+ },
+ Enumerant{
+ Enumerant: "MaxByteOffsetId",
+ Value: 47,
+ Capabilities: []string{"Addresses",},
+ Parameters: []Parameter{{OperandKindIdRef, "'Max Byte Offset'"},},
+ Version: "1.2",
+ },
+ Enumerant{
+ Enumerant: "NoSignedWrap",
+ Value: 4469,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "NoUnsignedWrap",
+ Value: 4470,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "ExplicitInterpAMD",
+ Value: 4999,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "OverrideCoverageNV",
+ Value: 5248,
+ Capabilities: []string{"SampleMaskOverrideCoverageNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PassthroughNV",
+ Value: 5250,
+ Capabilities: []string{"GeometryShaderPassthroughNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ViewportRelativeNV",
+ Value: 5252,
+ Capabilities: []string{"ShaderViewportMaskNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SecondaryViewportRelativeNV",
+ Value: 5256,
+ Capabilities: []string{"ShaderStereoViewNV",},
+ Parameters: []Parameter{{OperandKindLiteralInteger, "'Offset'"},},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PerPrimitiveNV",
+ Value: 5271,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PerViewNV",
+ Value: 5272,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PerTaskNV",
+ Value: 5273,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PerVertexNV",
+ Value: 5285,
+ Capabilities: []string{"FragmentBarycentricNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "NonUniform",
+ Value: 5300,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "NonUniformEXT",
+ Value: 5300,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "RestrictPointer",
+ Value: 5355,
+ Capabilities: []string{"PhysicalStorageBufferAddresses",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "RestrictPointerEXT",
+ Value: 5355,
+ Capabilities: []string{"PhysicalStorageBufferAddresses",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "AliasedPointer",
+ Value: 5356,
+ Capabilities: []string{"PhysicalStorageBufferAddresses",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "AliasedPointerEXT",
+ Value: 5356,
+ Capabilities: []string{"PhysicalStorageBufferAddresses",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "CounterBuffer",
+ Value: 5634,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindIdRef, "'Counter Buffer'"},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "HlslCounterBufferGOOGLE",
+ Value: 5634,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindIdRef, "'Counter Buffer'"},},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "UserSemantic",
+ Value: 5635,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralString, "'Semantic'"},},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "HlslSemanticGOOGLE",
+ Value: 5635,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralString, "'Semantic'"},},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "UserTypeGOOGLE",
+ Value: 5636,
+ Capabilities: []string{},
+ Parameters: []Parameter{{OperandKindLiteralString, "'User Type'"},},
+ Version: "None",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindBuiltIn = &OperandKind {
+ Kind: "BuiltIn",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Position",
+ Value: 0,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "PointSize",
+ Value: 1,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ClipDistance",
+ Value: 3,
+ Capabilities: []string{"ClipDistance",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "CullDistance",
+ Value: 4,
+ Capabilities: []string{"CullDistance",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "VertexId",
+ Value: 5,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InstanceId",
+ Value: 6,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "PrimitiveId",
+ Value: 7,
+ Capabilities: []string{"Geometry","Tessellation","RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InvocationId",
+ Value: 8,
+ Capabilities: []string{"Geometry","Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Layer",
+ Value: 9,
+ Capabilities: []string{"Geometry","ShaderLayer","ShaderViewportIndexLayerEXT",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ViewportIndex",
+ Value: 10,
+ Capabilities: []string{"MultiViewport","ShaderViewportIndex","ShaderViewportIndexLayerEXT",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "TessLevelOuter",
+ Value: 11,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "TessLevelInner",
+ Value: 12,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "TessCoord",
+ Value: 13,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "PatchVertices",
+ Value: 14,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "FragCoord",
+ Value: 15,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "PointCoord",
+ Value: 16,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "FrontFacing",
+ Value: 17,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SampleId",
+ Value: 18,
+ Capabilities: []string{"SampleRateShading",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SamplePosition",
+ Value: 19,
+ Capabilities: []string{"SampleRateShading",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SampleMask",
+ Value: 20,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "FragDepth",
+ Value: 22,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "HelperInvocation",
+ Value: 23,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NumWorkgroups",
+ Value: 24,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "WorkgroupSize",
+ Value: 25,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "WorkgroupId",
+ Value: 26,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "LocalInvocationId",
+ Value: 27,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GlobalInvocationId",
+ Value: 28,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "LocalInvocationIndex",
+ Value: 29,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "WorkDim",
+ Value: 30,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GlobalSize",
+ Value: 31,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "EnqueuedWorkgroupSize",
+ Value: 32,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GlobalOffset",
+ Value: 33,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GlobalLinearId",
+ Value: 34,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SubgroupSize",
+ Value: 36,
+ Capabilities: []string{"Kernel","GroupNonUniform","SubgroupBallotKHR",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SubgroupMaxSize",
+ Value: 37,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NumSubgroups",
+ Value: 38,
+ Capabilities: []string{"Kernel","GroupNonUniform",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "NumEnqueuedSubgroups",
+ Value: 39,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SubgroupId",
+ Value: 40,
+ Capabilities: []string{"Kernel","GroupNonUniform",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SubgroupLocalInvocationId",
+ Value: 41,
+ Capabilities: []string{"Kernel","GroupNonUniform","SubgroupBallotKHR",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "VertexIndex",
+ Value: 42,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InstanceIndex",
+ Value: 43,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SubgroupEqMask",
+ Value: 4416,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupGeMask",
+ Value: 4417,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupGtMask",
+ Value: 4418,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupLeMask",
+ Value: 4419,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupLtMask",
+ Value: 4420,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupEqMaskKHR",
+ Value: 4416,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupGeMaskKHR",
+ Value: 4417,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupGtMaskKHR",
+ Value: 4418,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupLeMaskKHR",
+ Value: 4419,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupLtMaskKHR",
+ Value: 4420,
+ Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "BaseVertex",
+ Value: 4424,
+ Capabilities: []string{"DrawParameters",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "BaseInstance",
+ Value: 4425,
+ Capabilities: []string{"DrawParameters",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "DrawIndex",
+ Value: 4426,
+ Capabilities: []string{"DrawParameters","MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "DeviceIndex",
+ Value: 4438,
+ Capabilities: []string{"DeviceGroup",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "ViewIndex",
+ Value: 4440,
+ Capabilities: []string{"MultiView",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "BaryCoordNoPerspAMD",
+ Value: 4992,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "BaryCoordNoPerspCentroidAMD",
+ Value: 4993,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "BaryCoordNoPerspSampleAMD",
+ Value: 4994,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "BaryCoordSmoothAMD",
+ Value: 4995,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "BaryCoordSmoothCentroidAMD",
+ Value: 4996,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "BaryCoordSmoothSampleAMD",
+ Value: 4997,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "BaryCoordPullModelAMD",
+ Value: 4998,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragStencilRefEXT",
+ Value: 5014,
+ Capabilities: []string{"StencilExportEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ViewportMaskNV",
+ Value: 5253,
+ Capabilities: []string{"ShaderViewportMaskNV","MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SecondaryPositionNV",
+ Value: 5257,
+ Capabilities: []string{"ShaderStereoViewNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SecondaryViewportMaskNV",
+ Value: 5258,
+ Capabilities: []string{"ShaderStereoViewNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PositionPerViewNV",
+ Value: 5261,
+ Capabilities: []string{"PerViewAttributesNV","MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ViewportMaskPerViewNV",
+ Value: 5262,
+ Capabilities: []string{"PerViewAttributesNV","MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FullyCoveredEXT",
+ Value: 5264,
+ Capabilities: []string{"FragmentFullyCoveredEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "TaskCountNV",
+ Value: 5274,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PrimitiveCountNV",
+ Value: 5275,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PrimitiveIndicesNV",
+ Value: 5276,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ClipDistancePerViewNV",
+ Value: 5277,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "CullDistancePerViewNV",
+ Value: 5278,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "LayerPerViewNV",
+ Value: 5279,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "MeshViewCountNV",
+ Value: 5280,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "MeshViewIndicesNV",
+ Value: 5281,
+ Capabilities: []string{"MeshShadingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "BaryCoordNV",
+ Value: 5286,
+ Capabilities: []string{"FragmentBarycentricNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "BaryCoordNoPerspNV",
+ Value: 5287,
+ Capabilities: []string{"FragmentBarycentricNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragSizeEXT",
+ Value: 5292,
+ Capabilities: []string{"FragmentDensityEXT","ShadingRateNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragmentSizeNV",
+ Value: 5292,
+ Capabilities: []string{"ShadingRateNV","FragmentDensityEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragInvocationCountEXT",
+ Value: 5293,
+ Capabilities: []string{"FragmentDensityEXT","ShadingRateNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "InvocationsPerPixelNV",
+ Value: 5293,
+ Capabilities: []string{"ShadingRateNV","FragmentDensityEXT",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "LaunchIdNV",
+ Value: 5319,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "LaunchSizeNV",
+ Value: 5320,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "WorldRayOriginNV",
+ Value: 5321,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "WorldRayDirectionNV",
+ Value: 5322,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ObjectRayOriginNV",
+ Value: 5323,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ObjectRayDirectionNV",
+ Value: 5324,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "RayTminNV",
+ Value: 5325,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "RayTmaxNV",
+ Value: 5326,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "InstanceCustomIndexNV",
+ Value: 5327,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ObjectToWorldNV",
+ Value: 5330,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "WorldToObjectNV",
+ Value: 5331,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "HitTNV",
+ Value: 5332,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "HitKindNV",
+ Value: 5333,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "IncomingRayFlagsNV",
+ Value: 5351,
+ Capabilities: []string{"RayTracingNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "WarpsPerSMNV",
+ Value: 5374,
+ Capabilities: []string{"ShaderSMBuiltinsNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SMCountNV",
+ Value: 5375,
+ Capabilities: []string{"ShaderSMBuiltinsNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "WarpIDNV",
+ Value: 5376,
+ Capabilities: []string{"ShaderSMBuiltinsNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SMIDNV",
+ Value: 5377,
+ Capabilities: []string{"ShaderSMBuiltinsNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindScope = &OperandKind {
+ Kind: "Scope",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "CrossDevice",
+ Value: 0,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Device",
+ Value: 1,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Workgroup",
+ Value: 2,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Subgroup",
+ Value: 3,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Invocation",
+ Value: 4,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "QueueFamily",
+ Value: 5,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "QueueFamilyKHR",
+ Value: 5,
+ Capabilities: []string{"VulkanMemoryModel",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindGroupOperation = &OperandKind {
+ Kind: "GroupOperation",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Reduce",
+ Value: 0,
+ Capabilities: []string{"Kernel","GroupNonUniformArithmetic","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InclusiveScan",
+ Value: 1,
+ Capabilities: []string{"Kernel","GroupNonUniformArithmetic","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ExclusiveScan",
+ Value: 2,
+ Capabilities: []string{"Kernel","GroupNonUniformArithmetic","GroupNonUniformBallot",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ClusteredReduce",
+ Value: 3,
+ Capabilities: []string{"GroupNonUniformClustered",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "PartitionedReduceNV",
+ Value: 6,
+ Capabilities: []string{"GroupNonUniformPartitionedNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PartitionedInclusiveScanNV",
+ Value: 7,
+ Capabilities: []string{"GroupNonUniformPartitionedNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PartitionedExclusiveScanNV",
+ Value: 8,
+ Capabilities: []string{"GroupNonUniformPartitionedNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindKernelEnqueueFlags = &OperandKind {
+ Kind: "KernelEnqueueFlags",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "NoWait",
+ Value: 0,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "WaitKernel",
+ Value: 1,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "WaitWorkGroup",
+ Value: 2,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindCapability = &OperandKind {
+ Kind: "Capability",
+ Category: "ValueEnum",
+ Enumerants: []Enumerant {
+ Enumerant{
+ Enumerant: "Matrix",
+ Value: 0,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Shader",
+ Value: 1,
+ Capabilities: []string{"Matrix",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Geometry",
+ Value: 2,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Tessellation",
+ Value: 3,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Addresses",
+ Value: 4,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Linkage",
+ Value: 5,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Kernel",
+ Value: 6,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Vector16",
+ Value: 7,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Float16Buffer",
+ Value: 8,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Float16",
+ Value: 9,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Float64",
+ Value: 10,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Int64",
+ Value: 11,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Int64Atomics",
+ Value: 12,
+ Capabilities: []string{"Int64",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageBasic",
+ Value: 13,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageReadWrite",
+ Value: 14,
+ Capabilities: []string{"ImageBasic",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageMipmap",
+ Value: 15,
+ Capabilities: []string{"ImageBasic",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Pipes",
+ Value: 17,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Groups",
+ Value: 18,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DeviceEnqueue",
+ Value: 19,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "LiteralSampler",
+ Value: 20,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "AtomicStorage",
+ Value: 21,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Int16",
+ Value: 22,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "TessellationPointSize",
+ Value: 23,
+ Capabilities: []string{"Tessellation",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GeometryPointSize",
+ Value: 24,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageGatherExtended",
+ Value: 25,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "StorageImageMultisample",
+ Value: 27,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "UniformBufferArrayDynamicIndexing",
+ Value: 28,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SampledImageArrayDynamicIndexing",
+ Value: 29,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "StorageBufferArrayDynamicIndexing",
+ Value: 30,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "StorageImageArrayDynamicIndexing",
+ Value: 31,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ClipDistance",
+ Value: 32,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "CullDistance",
+ Value: 33,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageCubeArray",
+ Value: 34,
+ Capabilities: []string{"SampledCubeArray",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SampleRateShading",
+ Value: 35,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageRect",
+ Value: 36,
+ Capabilities: []string{"SampledRect",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SampledRect",
+ Value: 37,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GenericPointer",
+ Value: 38,
+ Capabilities: []string{"Addresses",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Int8",
+ Value: 39,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InputAttachment",
+ Value: 40,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SparseResidency",
+ Value: 41,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "MinLod",
+ Value: 42,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Sampled1D",
+ Value: 43,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "Image1D",
+ Value: 44,
+ Capabilities: []string{"Sampled1D",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SampledCubeArray",
+ Value: 45,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SampledBuffer",
+ Value: 46,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageBuffer",
+ Value: 47,
+ Capabilities: []string{"SampledBuffer",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageMSArray",
+ Value: 48,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "StorageImageExtendedFormats",
+ Value: 49,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "ImageQuery",
+ Value: 50,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "DerivativeControl",
+ Value: 51,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "InterpolationFunction",
+ Value: 52,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "TransformFeedback",
+ Value: 53,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "GeometryStreams",
+ Value: 54,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "StorageImageReadWithoutFormat",
+ Value: 55,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "StorageImageWriteWithoutFormat",
+ Value: 56,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "MultiViewport",
+ Value: 57,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "",
+ },
+ Enumerant{
+ Enumerant: "SubgroupDispatch",
+ Value: 58,
+ Capabilities: []string{"DeviceEnqueue",},
+ Parameters: []Parameter{},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "NamedBarrier",
+ Value: 59,
+ Capabilities: []string{"Kernel",},
+ Parameters: []Parameter{},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "PipeStorage",
+ Value: 60,
+ Capabilities: []string{"Pipes",},
+ Parameters: []Parameter{},
+ Version: "1.1",
+ },
+ Enumerant{
+ Enumerant: "GroupNonUniform",
+ Value: 61,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "GroupNonUniformVote",
+ Value: 62,
+ Capabilities: []string{"GroupNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "GroupNonUniformArithmetic",
+ Value: 63,
+ Capabilities: []string{"GroupNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "GroupNonUniformBallot",
+ Value: 64,
+ Capabilities: []string{"GroupNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "GroupNonUniformShuffle",
+ Value: 65,
+ Capabilities: []string{"GroupNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "GroupNonUniformShuffleRelative",
+ Value: 66,
+ Capabilities: []string{"GroupNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "GroupNonUniformClustered",
+ Value: 67,
+ Capabilities: []string{"GroupNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "GroupNonUniformQuad",
+ Value: 68,
+ Capabilities: []string{"GroupNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "ShaderLayer",
+ Value: 69,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "ShaderViewportIndex",
+ Value: 70,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "SubgroupBallotKHR",
+ Value: 4423,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "DrawParameters",
+ Value: 4427,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "SubgroupVoteKHR",
+ Value: 4431,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "StorageBuffer16BitAccess",
+ Value: 4433,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "StorageUniformBufferBlock16",
+ Value: 4433,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "UniformAndStorageBuffer16BitAccess",
+ Value: 4434,
+ Capabilities: []string{"StorageBuffer16BitAccess","StorageUniformBufferBlock16",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "StorageUniform16",
+ Value: 4434,
+ Capabilities: []string{"StorageBuffer16BitAccess","StorageUniformBufferBlock16",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "StoragePushConstant16",
+ Value: 4435,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "StorageInputOutput16",
+ Value: 4436,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "DeviceGroup",
+ Value: 4437,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "MultiView",
+ Value: 4439,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "VariablePointersStorageBuffer",
+ Value: 4441,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "VariablePointers",
+ Value: 4442,
+ Capabilities: []string{"VariablePointersStorageBuffer",},
+ Parameters: []Parameter{},
+ Version: "1.3",
+ },
+ Enumerant{
+ Enumerant: "AtomicStorageOps",
+ Value: 4445,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SampleMaskPostDepthCoverage",
+ Value: 4447,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "StorageBuffer8BitAccess",
+ Value: 4448,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "UniformAndStorageBuffer8BitAccess",
+ Value: 4449,
+ Capabilities: []string{"StorageBuffer8BitAccess",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "StoragePushConstant8",
+ Value: 4450,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "DenormPreserve",
+ Value: 4464,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "DenormFlushToZero",
+ Value: 4465,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "SignedZeroInfNanPreserve",
+ Value: 4466,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "RoundingModeRTE",
+ Value: 4467,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "RoundingModeRTZ",
+ Value: 4468,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.4",
+ },
+ Enumerant{
+ Enumerant: "Float16ImageAMD",
+ Value: 5008,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ImageGatherBiasLodAMD",
+ Value: 5009,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragmentMaskAMD",
+ Value: 5010,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "StencilExportEXT",
+ Value: 5013,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ImageReadWriteLodAMD",
+ Value: 5015,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShaderClockKHR",
+ Value: 5055,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SampleMaskOverrideCoverageNV",
+ Value: 5249,
+ Capabilities: []string{"SampleRateShading",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "GeometryShaderPassthroughNV",
+ Value: 5251,
+ Capabilities: []string{"Geometry",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShaderViewportIndexLayerEXT",
+ Value: 5254,
+ Capabilities: []string{"MultiViewport",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShaderViewportIndexLayerNV",
+ Value: 5254,
+ Capabilities: []string{"MultiViewport",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShaderViewportMaskNV",
+ Value: 5255,
+ Capabilities: []string{"ShaderViewportIndexLayerNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShaderStereoViewNV",
+ Value: 5259,
+ Capabilities: []string{"ShaderViewportMaskNV",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "PerViewAttributesNV",
+ Value: 5260,
+ Capabilities: []string{"MultiView",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragmentFullyCoveredEXT",
+ Value: 5265,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "MeshShadingNV",
+ Value: 5266,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ImageFootprintNV",
+ Value: 5282,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragmentBarycentricNV",
+ Value: 5284,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ComputeDerivativeGroupQuadsNV",
+ Value: 5288,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragmentDensityEXT",
+ Value: 5291,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShadingRateNV",
+ Value: 5291,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "GroupNonUniformPartitionedNV",
+ Value: 5297,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShaderNonUniform",
+ Value: 5301,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "ShaderNonUniformEXT",
+ Value: 5301,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "RuntimeDescriptorArray",
+ Value: 5302,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "RuntimeDescriptorArrayEXT",
+ Value: 5302,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "InputAttachmentArrayDynamicIndexing",
+ Value: 5303,
+ Capabilities: []string{"InputAttachment",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "InputAttachmentArrayDynamicIndexingEXT",
+ Value: 5303,
+ Capabilities: []string{"InputAttachment",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "UniformTexelBufferArrayDynamicIndexing",
+ Value: 5304,
+ Capabilities: []string{"SampledBuffer",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "UniformTexelBufferArrayDynamicIndexingEXT",
+ Value: 5304,
+ Capabilities: []string{"SampledBuffer",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "StorageTexelBufferArrayDynamicIndexing",
+ Value: 5305,
+ Capabilities: []string{"ImageBuffer",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "StorageTexelBufferArrayDynamicIndexingEXT",
+ Value: 5305,
+ Capabilities: []string{"ImageBuffer",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "UniformBufferArrayNonUniformIndexing",
+ Value: 5306,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "UniformBufferArrayNonUniformIndexingEXT",
+ Value: 5306,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "SampledImageArrayNonUniformIndexing",
+ Value: 5307,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "SampledImageArrayNonUniformIndexingEXT",
+ Value: 5307,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "StorageBufferArrayNonUniformIndexing",
+ Value: 5308,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "StorageBufferArrayNonUniformIndexingEXT",
+ Value: 5308,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "StorageImageArrayNonUniformIndexing",
+ Value: 5309,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "StorageImageArrayNonUniformIndexingEXT",
+ Value: 5309,
+ Capabilities: []string{"ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "InputAttachmentArrayNonUniformIndexing",
+ Value: 5310,
+ Capabilities: []string{"InputAttachment","ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "InputAttachmentArrayNonUniformIndexingEXT",
+ Value: 5310,
+ Capabilities: []string{"InputAttachment","ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "UniformTexelBufferArrayNonUniformIndexing",
+ Value: 5311,
+ Capabilities: []string{"SampledBuffer","ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "UniformTexelBufferArrayNonUniformIndexingEXT",
+ Value: 5311,
+ Capabilities: []string{"SampledBuffer","ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "StorageTexelBufferArrayNonUniformIndexing",
+ Value: 5312,
+ Capabilities: []string{"ImageBuffer","ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "StorageTexelBufferArrayNonUniformIndexingEXT",
+ Value: 5312,
+ Capabilities: []string{"ImageBuffer","ShaderNonUniform",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "RayTracingNV",
+ Value: 5340,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "VulkanMemoryModel",
+ Value: 5345,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "VulkanMemoryModelKHR",
+ Value: 5345,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "VulkanMemoryModelDeviceScope",
+ Value: 5346,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "VulkanMemoryModelDeviceScopeKHR",
+ Value: 5346,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "PhysicalStorageBufferAddresses",
+ Value: 5347,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "PhysicalStorageBufferAddressesEXT",
+ Value: 5347,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "1.5",
+ },
+ Enumerant{
+ Enumerant: "ComputeDerivativeGroupLinearNV",
+ Value: 5350,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "CooperativeMatrixNV",
+ Value: 5357,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragmentShaderSampleInterlockEXT",
+ Value: 5363,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragmentShaderShadingRateInterlockEXT",
+ Value: 5372,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "ShaderSMBuiltinsNV",
+ Value: 5373,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "FragmentShaderPixelInterlockEXT",
+ Value: 5378,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "DemoteToHelperInvocationEXT",
+ Value: 5379,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SubgroupShuffleINTEL",
+ Value: 5568,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SubgroupBufferBlockIOINTEL",
+ Value: 5569,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SubgroupImageBlockIOINTEL",
+ Value: 5570,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SubgroupImageMediaBlockIOINTEL",
+ Value: 5579,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "IntegerFunctions2INTEL",
+ Value: 5584,
+ Capabilities: []string{"Shader",},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SubgroupAvcMotionEstimationINTEL",
+ Value: 5696,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SubgroupAvcMotionEstimationIntraINTEL",
+ Value: 5697,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ Enumerant{
+ Enumerant: "SubgroupAvcMotionEstimationChromaINTEL",
+ Value: 5698,
+ Capabilities: []string{},
+ Parameters: []Parameter{},
+ Version: "None",
+ },
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindIdResultType = &OperandKind {
+ Kind: "IdResultType",
+ Category: "Id",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindIdResult = &OperandKind {
+ Kind: "IdResult",
+ Category: "Id",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindIdMemorySemantics = &OperandKind {
+ Kind: "IdMemorySemantics",
+ Category: "Id",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindIdScope = &OperandKind {
+ Kind: "IdScope",
+ Category: "Id",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindIdRef = &OperandKind {
+ Kind: "IdRef",
+ Category: "Id",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindLiteralInteger = &OperandKind {
+ Kind: "LiteralInteger",
+ Category: "Literal",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindLiteralString = &OperandKind {
+ Kind: "LiteralString",
+ Category: "Literal",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindLiteralContextDependentNumber = &OperandKind {
+ Kind: "LiteralContextDependentNumber",
+ Category: "Literal",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindLiteralExtInstInteger = &OperandKind {
+ Kind: "LiteralExtInstInteger",
+ Category: "Literal",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindLiteralSpecConstantOpInteger = &OperandKind {
+ Kind: "LiteralSpecConstantOpInteger",
+ Category: "Literal",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {},
+ }
+ OperandKindPairLiteralIntegerIdRef = &OperandKind {
+ Kind: "PairLiteralIntegerIdRef",
+ Category: "Composite",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {OperandKindLiteralInteger,OperandKindIdRef,},
+ }
+ OperandKindPairIdRefLiteralInteger = &OperandKind {
+ Kind: "PairIdRefLiteralInteger",
+ Category: "Composite",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {OperandKindIdRef,OperandKindLiteralInteger,},
+ }
+ OperandKindPairIdRefIdRef = &OperandKind {
+ Kind: "PairIdRefIdRef",
+ Category: "Composite",
+ Enumerants: []Enumerant {
+ },
+ Bases: []*OperandKind {OperandKindIdRef,OperandKindIdRef,},
+ }
+
+)
diff --git a/utils/vscode/src/schema/schema.go.tmpl b/utils/vscode/src/schema/schema.go.tmpl
new file mode 100644
index 0000000..b584058
--- /dev/null
+++ b/utils/vscode/src/schema/schema.go.tmpl
@@ -0,0 +1,133 @@
+// 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.
+
+// Generated by {{GenerateArguments}}
+// Do not modify this file directly.
+
+package schema
+
+// Opcode holds information about a specific SPIR-V opcode.
+type Opcode struct {
+ Opname string
+ Class string
+ Opcode int
+ Operands []Operand
+}
+
+// Operand contains information about a logical operand for an instruction.
+type Operand struct {
+ Kind *OperandKind
+ Name string
+ Quantifier Quantifier
+}
+
+// OperandKind contains information about a specific operand kind.
+type OperandKind struct {
+ Category OperandCategory
+ Kind string
+ Enumerants []Enumerant
+ Bases []*OperandKind
+}
+
+// Enumerant contains information about an enumerant in an enum.
+type Enumerant struct {
+ Enumerant string
+ Value interface{}
+ Capabilities []string
+ Parameters []Parameter
+ Version string
+}
+
+// Parameter contains information about a logical parameter for an enumerant.
+type Parameter struct {
+ Kind *OperandKind
+ Name string
+}
+
+// Quantifier indicates the number of times the quantified term may appear.
+type Quantifier string
+
+const (
+ // Once indicates the quantified term may appear exactly once.
+ Once Quantifier = ""
+
+ // ZeroOrOnce indicates the quantified term may appear zero or one
+ // time; an optional term.
+ ZeroOrOnce Quantifier = "?"
+
+ // ZeroOrMany indicates the quantified term may appear any number of
+ // times.
+ ZeroOrMany Quantifier = "*"
+)
+
+// OperandCategory is an enumerator that groups operand kinds.
+type OperandCategory string
+
+const (
+ // OperandCategoryBitEnum describes an operand kind where its value is a
+ // mask, which is formed by combining the bits specified as enumerants in an
+ // enum.
+ OperandCategoryBitEnum = "BitEnum"
+
+ // OperandCategoryValueEnum describes an operand kind where its value is an
+ // enumerant from an enum.
+ OperandCategoryValueEnum = "ValueEnum"
+
+ // OperandCategoryID describes and operand kind where its value is an <id>
+ // definition or reference.
+ OperandCategoryID = "Id"
+
+ // OperandCategoryLiteral describes and operand kind where its value is an
+ // literal number or string.
+ OperandCategoryLiteral = "Literal"
+
+ // OperandCategoryComposite describes and operand kind where its value is
+ // composed from operand values from the above categories.
+ OperandCategoryComposite = "Composite"
+)
+
+var (
+ // Opcodes is a map of opcode name to Opcode description.
+ Opcodes = map[string]*Opcode {•{{range $i := .Instructions}}
+ "{{$i.Opname}}": {{$i.Opname}},{{end}}
+ }
+
+{{range $i := .Instructions}} {{$i.Opname}} = &Opcode {
+ Opname: "{{$i.Opname}}",
+ Operands: []Operand {•{{range $i := $i.Operands}}
+ Operand {
+ Kind: OperandKind{{$i.Kind}},
+ Name: "{{Replace $i.Name "\n" " "}}",
+ Quantifier: "{{$i.Quantifier}}",
+ }, {{end}}
+ },
+ }
+{{end}}
+
+{{range $o := .OperandKinds}} OperandKind{{$o.Kind}} = &OperandKind {
+ Kind: "{{$o.Kind}}",
+ Category: "{{$o.Category}}",
+ Enumerants: []Enumerant {•{{range $e := $o.Enumerants}}
+ Enumerant{
+ Enumerant: "{{$e.Enumerant}}",
+ Value: {{$e.Value}},
+ Capabilities: []string{•{{range $c := $e.Capabilities}}"{{$c}}",{{end}}•},
+ Parameters: []Parameter{•{{range $p := $e.Parameters}}{•OperandKind{{$p.Kind}}, "{{$p.Name}}"•},{{end}}•},
+ Version: "{{$e.Version}}",
+ },{{end}}
+ },
+ Bases: []*OperandKind {•{{range $b := $o.Bases}}OperandKind{{$b}},{{end}}•},
+ }
+{{end}}
+)
diff --git a/utils/vscode/src/tools/gen-grammar.go b/utils/vscode/src/tools/gen-grammar.go
new file mode 100644
index 0000000..f9980b9
--- /dev/null
+++ b/utils/vscode/src/tools/gen-grammar.go
@@ -0,0 +1,168 @@
+// 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.
+
+// gen-grammar generates the spirv.json grammar file from the official SPIR-V
+// grammar JSON file.
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "text/template"
+
+ "github.com/pkg/errors"
+
+ "../grammar"
+)
+
+const (
+ spirvGrammarURL = "https://raw.githubusercontent.com/KhronosGroup/SPIRV-Headers/master/include/spirv/unified1/spirv.core.grammar.json"
+ spirvGrammarName = "spirv.core.grammar.json"
+)
+
+var (
+ templatePath = flag.String("template", "", "Path to input template file (required)")
+ outputPath = flag.String("out", "", "Path to output generated file (required)")
+ cachePath = flag.String("cache", "", "Cache directory for downloaded files (optional)")
+
+ thisDir = func() string {
+ _, file, _, _ := runtime.Caller(1)
+ return filepath.Dir(file)
+ }()
+)
+
+func main() {
+ flag.Parse()
+ if *templatePath == "" || *outputPath == "" {
+ flag.Usage()
+ os.Exit(1)
+ }
+ if err := run(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+}
+
+func run() error {
+ tf, err := ioutil.ReadFile(*templatePath)
+ if err != nil {
+ return errors.Wrap(err, "Could not open template file")
+ }
+ t, err := template.New("tmpl").
+ Funcs(template.FuncMap{
+ "GenerateArguments": func() string {
+ relPath := func(path string) string {
+ rel, err := filepath.Rel(thisDir, path)
+ if err != nil {
+ return path
+ }
+ return rel
+ }
+ args := []string{
+ "--template=" + relPath(*templatePath),
+ "--out=" + relPath(*outputPath),
+ }
+ return "gen-grammar.go " + strings.Join(args, " ")
+ },
+ "OperandKindsMatch": func(k grammar.OperandKind) string {
+ sb := strings.Builder{}
+ for i, e := range k.Enumerants {
+ if i > 0 {
+ sb.WriteString("|")
+ }
+ sb.WriteString(e.Enumerant)
+ }
+ return sb.String()
+ },
+ "Replace": strings.ReplaceAll,
+ }).Parse(string(tf))
+ if err != nil {
+ return errors.Wrap(err, "Failed to parse template")
+ }
+
+ file, err := getOrDownload(spirvGrammarName, spirvGrammarURL)
+ if err != nil {
+ return errors.Wrap(err, "Failed to load grammar file")
+ }
+
+ g := grammar.Root{}
+ if err := json.NewDecoder(bytes.NewReader(file)).Decode(&g); err != nil {
+ return errors.Wrap(err, "Failed to parse grammar file")
+ }
+
+ buf := bytes.Buffer{}
+ if err := t.Execute(&buf, g); err != nil {
+ return errors.Wrap(err, "Failed to execute template")
+ }
+
+ out := buf.String()
+ out = strings.ReplaceAll(out, "•", "")
+
+ if err := ioutil.WriteFile(*outputPath, []byte(out), 0777); err != nil {
+ return errors.Wrap(err, "Failed to write output file")
+ }
+
+ return nil
+}
+
+// getOrDownload loads the specific file from the cache, or downloads the file
+// from the given url.
+func getOrDownload(name, url string) ([]byte, error) {
+ if *cachePath != "" {
+ if err := os.MkdirAll(*cachePath, 0777); err == nil {
+ path := filepath.Join(*cachePath, name)
+ if isFile(path) {
+ return ioutil.ReadFile(path)
+ }
+ }
+ }
+ resp, err := http.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+ if *cachePath != "" {
+ ioutil.WriteFile(filepath.Join(*cachePath, name), data, 0777)
+ }
+ return data, nil
+}
+
+// isFile returns true if path is a file.
+func isFile(path string) bool {
+ s, err := os.Stat(path)
+ if err != nil {
+ return false
+ }
+ return !s.IsDir()
+}
+
+// isDir returns true if path is a directory.
+func isDir(path string) bool {
+ s, err := os.Stat(path)
+ if err != nil {
+ return false
+ }
+ return s.IsDir()
+}